<commit_before>use boxdraw;

use SimpleSearch;

// EXERCISE 1: Can you make an undraw implementation that can handle
// the case below?

#[test]
fn three_by_three() {
    boxdraw::check_undraw(".............\n\
                           ..+--+--+--+.\n\
                           ..|aa|bb|cc|.\n\
                           ..|aa|bb|cc|.\n\
                           ..+--+--+--+.\n\
                           ..|dd|ee|ff|.\n\
                           ..|dd|ee|ff|.\n\
                           ..+--+--+--+.\n\
                           ..|gg|hh|ii|.\n\
                           ..|gg|hh|ii|.\n\
                           ..+--+--+--+.\n\
                           .............\n\
                          ",
                          &SimpleSearch).unwrap();

}

// EXERCISE 2: One might think that once you generate a working
// Script, there's no further way to improve upon it. However,
// consider a case like this:
//
//
//                  ....................
//                  ......+------+......
//                  ......|bbbbbb|......
//                  ......|bbbbbb|......
//                  .+----|bbbbbb|----+.
//                  .|aaaa|bbbbbb|aaaa|.
//                  .|aaaa|bbbbbb|aaaa|.
//                  .+----|bbbbbb|----+.
//                  ......|bbbbbb|......
//                  ......+------+......
//                  ....................
//
// There are two "obvious" relatively short scripts that generate the
// above picture: one that draws two 'a' rectangles and then the
// single 'b' rectangle (thus requiring three commands in the script).
//
//  ....................       ....................
//  ....................       ......+------+......
//  ....................       ......|bbbbbb|......
//  ....................       ......|bbbbbb|......
//  .+----+......+----+.       ......|bbbbbb|......
//  .|aaaa|......|aaaa|. then  ......|bbbbbb|......
//  .|aaaa|......|aaaa|.       ......|bbbbbb|......
//  .+----+......+----+.       ......|bbbbbb|......
//  ....................       ......|bbbbbb|......
//  ....................       ......+------+......
//  ....................       ....................
//
//
// But there is also this approach, which requires only two commands:
//
//  ....................       ....................
//  ....................       ......+------+......
//  ....................       ......|bbbbbb|......
//  ....................       ......|bbbbbb|......
//  .+----------------+.       ......|bbbbbb|......
//  .|aaaaaaaaaaaaaaaa|. then  ......|bbbbbb|......
//  .|aaaaaaaaaaaaaaaa|.       ......|bbbbbb|......
//  .+----------------+.       ......|bbbbbb|......
//  ....................       ......|bbbbbb|......
//  ....................       ......+------+......
//  ....................       ....................
//
// The undraw strategy of the code above will tend to generate the
// three-command script. What ideas do you have to try to make it
// generate "optimal" scripts (where "optimal" here means "minimal
// number of commands."

// EXERCISE 3: Up until now, we have assumed that all boxes are at
// least width and height >= 2.  So for example `test::narrow_lines()`
// shows boxes of width == 2, so narrow that they have no interior.
//
// BUT: The boxdraw-rs library supports boxes of width or height == 1
// as well, and it has *very* different behavior for them. Find out
// what that behavior is (perhaps by looking at the tests in the
// boxdraw library).
//
// Consider what a box with both width and height equal to 1 would
// look like. What implications does this have? For example, what kind
// of pictures can you make with just boxes of *both* width and height 1?
//
// Try to solve the undraw problem even for such cases.
//
// Note 1: to do this, you may want to start from scratch; or maybe
// some of the code here could be of use.
//
// Note 2: You may want to play around first with approaches that are
// not anywhere close to optimal.

// EXERCISE 4: Like exercise 2 above: Again, solve the generalized
// undraw problem (that is, including boxes of width and/or height 1),
// but this time, try to generate relatively small scripts.
//
// Note that you can make short scripts that first draw large boxes
// (which will then have borders) and then write over the borders with
// boxes of width or height 1, like so:
//
//  ....................       ....................   ....................
//  ....................       ....................   ....................
//  ....................       ....................   ....................
//  ....................       ....................   ....................
//  .+----------------+.       .aaaaaaaaaaaaaaaaaa.   .a................a.
//  .|aaaaaaaaaaaaaaaa|. then  .................... ; .a................a.
//  .|aaaaaaaaaaaaaaaa|.       ....................   .a................a.
//  .+----------------+.       .aaaaaaaaaaaaaaaaaa.   .a................a.
//  ....................       ....................   ....................
//  ....................       ....................   ....................
//  ....................       ....................   ....................
//
// and this generates a picture with a borderless box:
//
//  ....................
//  ....................
//  ....................
//  ....................
//  .aaaaaaaaaaaaaaaaaa.
//  .aaaaaaaaaaaaaaaaaa.
//  .aaaaaaaaaaaaaaaaaa.
//  .aaaaaaaaaaaaaaaaaa.
//  ....................
//  ....................
//  ....................
<commit_msg>Point out why this case is interesting.<commit_after>use boxdraw;

use SimpleSearch;

// EXERCISE 1: Can you make an undraw implementation that can handle
// the case below?

#[test]
fn three_by_three() {
    boxdraw::check_undraw(".............\n\
                           ..+--+--+--+.\n\
                           ..|aa|bb|cc|.\n\
                           ..|aa|bb|cc|.\n\
                           ..+--+--+--+.\n\
                           ..|dd|ee|ff|.\n\
                           ..|dd|ee|ff|.\n\
                           ..+--+--+--+.\n\
                           ..|gg|hh|ii|.\n\
                           ..|gg|hh|ii|.\n\
                           ..+--+--+--+.\n\
                           .............\n\
                          ",
                          &SimpleSearch).unwrap();

}

// EXERCISE 2: One might think that once you generate a working
// Script, there's no further way to improve upon it. However,
// consider a case like this:
//
//
//                  ....................
//                  ......+------+......
//                  ......|bbbbbb|......
//                  ......|bbbbbb|......
//                  .+----|bbbbbb|----+.
//                  .|aaaa|bbbbbb|aaaa|.
//                  .|aaaa|bbbbbb|aaaa|.
//                  .+----|bbbbbb|----+.
//                  ......|bbbbbb|......
//                  ......+------+......
//                  ....................
//
// There are two "obvious" relatively short scripts that generate the
// above picture: one that draws two 'a' rectangles and then the
// single 'b' rectangle (thus requiring three commands in the script).
//
//  ....................       ....................
//  ....................       ......+------+......
//  ....................       ......|bbbbbb|......
//  ....................       ......|bbbbbb|......
//  .+----+......+----+.       ......|bbbbbb|......
//  .|aaaa|......|aaaa|. then  ......|bbbbbb|......
//  .|aaaa|......|aaaa|.       ......|bbbbbb|......
//  .+----+......+----+.       ......|bbbbbb|......
//  ....................       ......|bbbbbb|......
//  ....................       ......+------+......
//  ....................       ....................
//
//
// But there is also this approach, which requires only two commands:
//
//  ....................       ....................
//  ....................       ......+------+......
//  ....................       ......|bbbbbb|......
//  ....................       ......|bbbbbb|......
//  .+----------------+.       ......|bbbbbb|......
//  .|aaaaaaaaaaaaaaaa|. then  ......|bbbbbb|......
//  .|aaaaaaaaaaaaaaaa|.       ......|bbbbbb|......
//  .+----------------+.       ......|bbbbbb|......
//  ....................       ......|bbbbbb|......
//  ....................       ......+------+......
//  ....................       ....................
//
// The undraw strategy of the code above will tend to generate the
// three-command script. What ideas do you have to try to make it
// generate "optimal" scripts (where "optimal" here means "minimal
// number of commands."

// EXERCISE 3: Up until now, we have assumed that all boxes are at
// least width and height >= 2.  So for example `test::narrow_lines()`
// shows boxes of width == 2, so narrow that they have no interior.
//
// BUT: The boxdraw-rs library supports boxes of width or height == 1
// as well, and it has *very* different behavior for them. Find out
// what that behavior is (perhaps by looking at the tests in the
// boxdraw library).
//
// Consider what a box with both width and height equal to 1 would
// look like. What implications does this have? For example, what kind
// of pictures can you make with just boxes of *both* width and height 1?
//
// Try to solve the undraw problem even for such cases.
//
// Note 1: to do this, you may want to start from scratch; or maybe
// some of the code here could be of use.
//
// Note 2: You may want to play around first with approaches that are
// not anywhere close to optimal.

// EXERCISE 4: Like exercise 2 above: Again, solve the generalized
// undraw problem (that is, including boxes of width and/or height 1),
// but this time, try to generate relatively small scripts.
//
// Note that you can make short scripts that first draw large boxes
// (which will then have borders) and then write over the borders with
// boxes of width or height 1, like so:
//
//  ....................       ....................   ....................
//  ....................       ....................   ....................
//  ....................       ....................   ....................
//  ....................       ....................   ....................
//  .+----------------+.       .aaaaaaaaaaaaaaaaaa.   .a................a.
//  .|aaaaaaaaaaaaaaaa|. then  .................... ; .a................a.
//  .|aaaaaaaaaaaaaaaa|.       ....................   .a................a.
//  .+----------------+.       .aaaaaaaaaaaaaaaaaa.   .a................a.
//  ....................       ....................   ....................
//  ....................       ....................   ....................
//  ....................       ....................   ....................
//
// and this generates a picture with a borderless box:
//
//  ....................
//  ....................
//  ....................
//  ....................
//  .aaaaaaaaaaaaaaaaaa.
//  .aaaaaaaaaaaaaaaaaa.
//  .aaaaaaaaaaaaaaaaaa.
//  .aaaaaaaaaaaaaaaaaa.
//  ....................
//  ....................
//  ....................
//
// but does it with only five commands.
<|endoftext|>


<commit_before>pub struct GaugeF64 {
    pub value: f64
}

impl GaugeF64 {
    pub fn update(&mut self, value: f64) {
        self.value += value;
    }

    pub fn snapshot(self) -> GaugeF64 {
        GaugeF64{ value: self.value }
    }
}

#[cfg(test)]
mod test {
    use gauge_f64::GaugeF64;

    #[test]
    fn create_and_snapshot() {
        let g = GaugeF64{value: 0f64};
        let mut g_snapshot = g.snapshot();

        g_snapshot.update(10f64);

        assert!(g.value == 0f64);
        assert!(g_snapshot.value == 10f64);

    }
}<commit_msg>= not +=<commit_after>pub struct GaugeF64 {
    pub value: f64
}

impl GaugeF64 {
    pub fn update(&mut self, value: f64) {
        self.value = value;
    }

    pub fn snapshot(self) -> GaugeF64 {
        GaugeF64{ value: self.value }
    }
}

#[cfg(test)]
mod test {
    use gauge_f64::GaugeF64;

    #[test]
    fn create_and_snapshot() {
        let g = GaugeF64{value: 0f64};
        let mut g_snapshot = g.snapshot();

        g_snapshot.update(10f64);

        assert!(g.value == 0f64);
        assert!(g_snapshot.value == 10f64);

    }
}<|endoftext|>


<commit_before>
use std::num;

#[derive(Debug)]
pub enum YSONError {
    ParseFloatError(num::ParseFloatError),
    ScalarNotFloatError
}

pub enum YSONValue<'a> {
    Map{values: Vec<(YSONValue<'a>, YSONValue<'a>)>},
    Array{values: Vec<YSONValue<'a>>},
    RawScalar{value: &'a str},
    String{value: String}
}

struct YSONParser<'a> {
    src: &'a str
}

impl<'a> YSONParser<'a> {
    fn eat_white(&mut self) {
        self.src = self.src.trim_left();
    }

    fn require(&mut self, tok: &str) {
        self.eat_white();
        if self.src.starts_with(tok) {
            self.src = self.src.split_at(tok.len()).1;
            self.eat_white();
        }
        else {
            panic!("Expected token {} not found.", tok)
        }
    }

    fn allow(&mut self, tok: &str) {
        self.eat_white();
        if self.src.starts_with(tok) {
            self.src = self.src.split_at(tok.len()).1;
            self.eat_white();
        }
    }

    pub fn parse_map(&mut self) -> YSONValue<'a> {
        let mut values = Vec::new();
        self.require("{");
        while !self.src.starts_with('}') {
            let key = self.parse_scalar();
            self.require(":");
            let value = self.parse_value();
            self.allow(",");
            values.push((key, value));
        }
        self.require("}");
        println!("parsed map");
        YSONValue::Map{values: values}
    }

    pub fn parse_array(&mut self) -> YSONValue<'a> {
        let mut values = Vec::new();
        self.require("[");
        while !self.src.starts_with(']') {
            values.push(self.parse_value());
            self.allow(",");
        }
        self.require("]");
        println!("parsed array");
        YSONValue::Array{values: values}
    }

    pub fn parse_quoted_string(&mut self) -> YSONValue<'a> {
        // Parse series of characters starting and ending with '"', including whitespace and
        // newlines.
        let mut chars = self.src.char_indices();
        let mut prev_char = '\\';
        loop {
            let (idx, this_char) = match chars.next() {
                None => panic!("Expected terminating \" not found."),
                Some((idx, ch)) => ((idx, ch))
            };
            if this_char == '"' && prev_char != '\\' {
                let (s, src2) = self.src.split_at(idx + 1);
                self.src = src2;
                println!("parsed quoted string: {}", s);
                return YSONValue::RawScalar{value: s};
            }
            else {
                prev_char = this_char;
            }
        }
    }

    pub fn parse_literal(&mut self) -> YSONValue<'a> {
        // Parse series of characters consisting of any character but: ":,]}", or
        // whitespace.
        match self.src.find(|ch| char::is_whitespace(ch) || ":,]}".contains(ch)) {
            None => panic!("End of input reached while parsing literal."),
            Some(idx) => {
                let (s, src2) = self.src.split_at(idx);
                self.src = src2;
                println!("parsed literal: {}", s);
                return YSONValue::RawScalar{value: s};
            }
        }
    }

    pub fn parse_scalar(&mut self) -> YSONValue<'a> {
        if self.src.starts_with('"') {
            return self.parse_quoted_string();
        }
        else {
            return self.parse_literal();
        };
    }

    pub fn parse_value(&mut self) -> YSONValue<'a> {
        self.eat_white();
        if self.src.starts_with('{') {
            return self.parse_map();
        }
        else if self.src.starts_with('[') {
            return self.parse_array();
        }
        else {
            return self.parse_scalar();
        };
    }
}

impl<'a> YSONValue<'a> {
    pub fn parse(src: &'a str) -> YSONValue<'a> {
        let mut parser = YSONParser{src: src};
        parser.parse_value()
    }

    pub fn map_values(&self) -> Option<&Vec<(YSONValue<'a>, YSONValue<'a>)>> {
        match *self {
            YSONValue::Map{ref values} => Some(values),
            _ => None
        }
    }

    pub fn map_value(&self, key: &str) -> Option<&YSONValue<'a>> {
        for x in self.map_values().unwrap() {
            if x.0.scalar_value().unwrap() == key {
                return Some(&(x.1));
            }
        }
        return None;
    }

    pub fn array_values(&self) -> Option<&Vec<YSONValue<'a>>> {
        match *self {
            YSONValue::Array{ref values} => Some(values),
            _ => None
        }
    }

    pub fn scalar_value(&self) -> Option<&str> {
        match *self {
            YSONValue::RawScalar{ref value} => Some(value),
            YSONValue::String{ref value} => Some(&value),
            _ => None
        }
    }

    pub fn f64_value(&self) -> Result<f64, YSONError> {
        let scal_val = match self.scalar_value() {
            Some(scalar) => scalar,
            _ => return Err(YSONError::ScalarNotFloatError)
        };
        scal_val.parse::<f64>().map_err(YSONError::ParseFloatError)
    }

    pub fn display(&self) {
        match *self {
            YSONValue::Map{ref values} => {
                print!("{{\n");
                for x in values {
                    x.0.display();
                    print!(":");
                    x.1.display();
                    print!(",\n");
                }
                print!("}}\n");
            },
            YSONValue::Array{ref values} => {
                print!("[\n");
                for x in values {
                    x.display();
                    print!(",\n");
                }
                print!("]\n");
            },
            YSONValue::RawScalar{ref value} => {
                print!("{}", value);
            },
            YSONValue::String{ref value} => {
                print!("{}", value);
            }
        }
    }
}
<commit_msg>Added error handling, partial implementation of quoted string unescaping<commit_after>
use std::num;

#[derive(Debug)]
pub enum YSONError {
    ParseError,
    ParseNoTerminatingQuote(String),
    ParseBadEscapeCode(String),
    ParseExpect(String),
    ParseUnexpectedEndOfInput,
    ParseFloatError(num::ParseFloatError),
    ValueNotMapError,
    ValueNotArrayError,
    ValueNotScalarError,
    ScalarNotFloatError
}

pub enum YSONValue<'a> {
    Map{values: Vec<(YSONValue<'a>, YSONValue<'a>)>},
    Array{values: Vec<YSONValue<'a>>},
    RawScalar{value: &'a str},
    String{value: String}
}

struct YSONParser<'a> {
    src: &'a str
}

impl<'a> YSONParser<'a> {
    fn eat_white(&mut self) {
        self.src = self.src.trim_left();
    }

    fn require(&mut self, tok: &str) -> Result<(), YSONError> {
        self.eat_white();
        if self.src.starts_with(tok) {
            self.src = self.src.split_at(tok.len()).1;
            self.eat_white();
            Ok(())
        }
        else {
            Err(YSONError::ParseExpect(tok.to_string()))
        }
    }

    fn allow(&mut self, tok: &str) {
        self.eat_white();
        if self.src.starts_with(tok) {
            self.src = self.src.split_at(tok.len()).1;
            self.eat_white();
        }
    }

    pub fn parse_map(&mut self) -> Result<YSONValue<'a>, YSONError> {
        let mut values = Vec::new();
        try!(self.require("{"));
        while !self.src.starts_with('}') {
            let key = try!(self.parse_scalar());
            try!(self.require(":"));
            let value = try!(self.parse_value());
            self.allow(",");
            values.push((key, value));
        }
        try!(self.require("}"));
        println!("parsed map");
        Ok(YSONValue::Map{values: values})
    }

    pub fn parse_array(&mut self) -> Result<YSONValue<'a>, YSONError> {
        let mut values = Vec::new();
        try!(self.require("["));
        while !self.src.starts_with(']') {
            values.push(try!(self.parse_value()));
            self.allow(",");
        }
        try!(self.require("]"));
        println!("parsed array");
        Ok(YSONValue::Array{values: values})
    }

    pub fn parse_quoted_string(&mut self) -> Result<YSONValue<'a>, YSONError> {
        // Parse series of characters starting and ending with '"', including whitespace and
        // newlines.
        let mut chars = self.src.char_indices();
        chars.next();// skip opening '"'
        let mut string_value = String::new();
        loop {
            let (idx, this_char) = match chars.next() {
                None => return Err(YSONError::ParseNoTerminatingQuote(string_value)),
                Some((idx, ch)) => ((idx, ch))
            };

            if this_char == '\\' {
                string_value.push(match chars.next() {
                    Some((_, 'r')) => '\r',
                    Some((_, 'n')) => '\n',
                    Some((_, 't')) => '\t',
                    Some((_, '"')) => '"',
                    Some((_, '\'')) => '\'',
                    Some((_, '\\')) => '\\',
                    _ => return Err(YSONError::ParseBadEscapeCode(this_char.to_string()))
                })
            }
            else if this_char == '"' {
                self.src = self.src.split_at(idx + 1).1;
                println!("parsed quoted string: {}", string_value);
                return Ok(YSONValue::String{value: string_value});
            }
            else {
                string_value.push(this_char);
            }
        }
    }

    pub fn parse_literal(&mut self) -> Result<YSONValue<'a>, YSONError> {
        // Parse series of characters consisting of any character but: ":,]}", or
        // whitespace.
        match self.src.find(|ch| char::is_whitespace(ch) || ":,]}".contains(ch)) {
            None => return Err(YSONError::ParseUnexpectedEndOfInput),
            Some(idx) => {
                let (s, src2) = self.src.split_at(idx);
                self.src = src2;
                println!("parsed literal: {}", s);
                return Ok(YSONValue::RawScalar{value: s});
            }
        }
    }

    pub fn parse_scalar(&mut self) -> Result<YSONValue<'a>, YSONError> {
        if self.src.starts_with('"') {
            return self.parse_quoted_string();
        }
        else {
            return self.parse_literal();
        };
    }

    pub fn parse_value(&mut self) -> Result<YSONValue<'a>, YSONError> {
        self.eat_white();
        if self.src.starts_with('{') {
            return self.parse_map();
        }
        else if self.src.starts_with('[') {
            return self.parse_array();
        }
        else {
            return self.parse_scalar();
        };
    }
}

impl<'a> YSONValue<'a> {
    pub fn parse(src: &'a str) -> Result<YSONValue<'a>, YSONError> {
        let mut parser = YSONParser{src: src};
        parser.parse_value()
    }

    pub fn map_values(&self) -> Result<&Vec<(YSONValue<'a>, YSONValue<'a>)>, YSONError> {
        match *self {
            YSONValue::Map{ref values} => Ok(values),
            _ => Err(YSONError::ValueNotMapError)
        }
    }

    pub fn map_value(&self, key: &str) -> Result<&YSONValue<'a>, YSONError> {
        for x in self.map_values().unwrap() {
            if x.0.scalar_value().unwrap() == key {
                return Ok(&(x.1));
            }
        }
        return Err(YSONError::ValueNotMapError);
    }

    pub fn array_values(&self) -> Result<&Vec<YSONValue<'a>>, YSONError> {
        match *self {
            YSONValue::Array{ref values} => Ok(values),
            _ => Err(YSONError::ValueNotArrayError)
        }
    }

    pub fn scalar_value(&self) -> Result<&str, YSONError> {
        match *self {
            YSONValue::RawScalar{ref value} => Ok(value),
            YSONValue::String{ref value} => Ok(&value),
            _ => Err(YSONError::ValueNotScalarError)
        }
    }

    pub fn f64_value(&self) -> Result<f64, YSONError> {
        match self.scalar_value() {
            Ok(scalar) => return scalar.parse::<f64>().map_err(YSONError::ParseFloatError),
            Err(e) => return Err(e)
        };
    }

    pub fn display(&self) {
        match *self {
            YSONValue::Map{ref values} => {
                print!("{{\n");
                for x in values {
                    x.0.display();
                    print!(":");
                    x.1.display();
                    print!(",\n");
                }
                print!("}}\n");
            },
            YSONValue::Array{ref values} => {
                print!("[\n");
                for x in values {
                    x.display();
                    print!(",\n");
                }
                print!("]\n");
            },
            YSONValue::RawScalar{ref value} => {
                print!("{}", value);
            },
            YSONValue::String{ref value} => {
                print!("{}", value);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use euclid::Point2D;
use calx_resource::Resource;
use world::Brush;
use backend;
use render::Layer;

/// Drawable display element.
///
/// Sprites are basically a way to defer somewhat complex draw instructions. The reason they exist
/// is that scene draw order is not necessarily trivially reflectable in scene data traversal, so
/// emitting sprites and then sorting them is the simplest way to go ahead.
#[derive(Clone, PartialEq, Eq)]
pub struct Sprite {
    pub layer: Layer,
    // XXX: Not using Point2D<f32> because floats don't have Ord.
    pub offset: [i32; 2],

    // TODO: Replace this with a generic "Drawable" trait object once we start having other things
    // than frames as sprites.
    pub brush: Resource<Brush>,
    pub frame_idx: usize,
}

impl Ord for Sprite {
    fn cmp(&self, other: &Self) -> Ordering {
        (self.layer, self.offset[1], self.offset[0])
            .cmp(&(other.layer, other.offset[1], other.offset[0]))
    }
}

impl PartialOrd for Sprite {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
}

impl Sprite {
    pub fn draw(&self, ui: &mut backend::UI) {
        let pos = Point2D::new(self.offset[0] as f32, self.offset[1] as f32);
        for splat in &self.brush[self.frame_idx] {
            ui.draw_image(&splat.image, pos - splat.offset, splat.color);
        }
    }
}
<commit_msg>Don't sort sprites by x coordinate<commit_after>use std::cmp::Ordering;
use euclid::Point2D;
use calx_resource::Resource;
use world::Brush;
use backend;
use render::Layer;

/// Drawable display element.
///
/// Sprites are basically a way to defer somewhat complex draw instructions. The reason they exist
/// is that scene draw order is not necessarily trivially reflectable in scene data traversal, so
/// emitting sprites and then sorting them is the simplest way to go ahead.
#[derive(Clone, PartialEq, Eq)]
pub struct Sprite {
    pub layer: Layer,
    // XXX: Not using Point2D<f32> because floats don't have Ord.
    pub offset: [i32; 2],

    // TODO: Replace this with a generic "Drawable" trait object once we start having other things
    // than frames as sprites.
    pub brush: Resource<Brush>,
    pub frame_idx: usize,
}

impl Ord for Sprite {
    fn cmp(&self, other: &Self) -> Ordering {
        (self.layer, self.offset[1])
            .cmp(&(other.layer, other.offset[1]))
    }
}

impl PartialOrd for Sprite {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
}

impl Sprite {
    pub fn draw(&self, ui: &mut backend::UI) {
        let pos = Point2D::new(self.offset[0] as f32, self.offset[1] as f32);
        for splat in &self.brush[self.frame_idx] {
            ui.draw_image(&splat.image, pos - splat.offset, splat.color);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::conversion::api::{ApiName, NullPhase, Provenance};
use crate::conversion::apivec::ApiVec;
use crate::conversion::doc_attr::get_doc_attr;
use crate::conversion::error_reporter::report_any_error;
use crate::conversion::{
    api::{FuncToConvert, UnanalyzedApi},
    convert_error::ConvertErrorWithContext,
    convert_error::ErrorContext,
};
use crate::{
    conversion::ConvertError,
    types::{Namespace, QualifiedName},
};
use std::collections::HashMap;
use syn::{Block, Expr, ExprCall, ForeignItem, Ident, ImplItem, ItemImpl, Stmt, Type};

use super::bindgen_semantic_attributes::BindgenSemanticAttributes;

/// Parses a given bindgen-generated 'mod' into suitable
/// [Api]s. In bindgen output, a given mod concerns
/// a specific C++ namespace.
pub(crate) struct ParseForeignMod {
    ns: Namespace,
    // We mostly act upon the functions we see within the 'extern "C"'
    // block of bindgen output, but we can't actually do this until
    // we've seen the (possibly subsequent) 'impl' blocks so we can
    // deduce which functions are actually static methods. Hence
    // store them.
    funcs_to_convert: Vec<FuncToConvert>,
    // Evidence from 'impl' blocks about which of these items
    // may actually be methods (static or otherwise). Mapping from
    // function name to type name.
    method_receivers: HashMap<Ident, QualifiedName>,
    ignored_apis: ApiVec<NullPhase>,
}

impl ParseForeignMod {
    pub(crate) fn new(ns: Namespace) -> Self {
        Self {
            ns,
            funcs_to_convert: Vec::new(),
            method_receivers: HashMap::new(),
            ignored_apis: ApiVec::new(),
        }
    }

    /// Record information from foreign mod items encountered
    /// in bindgen output.
    pub(crate) fn convert_foreign_mod_items(&mut self, foreign_mod_items: Vec<ForeignItem>) {
        let mut extra_apis = ApiVec::new();
        for i in foreign_mod_items {
            report_any_error(&self.ns.clone(), &mut extra_apis, || {
                self.parse_foreign_item(i)
            });
        }
        self.ignored_apis.append(&mut extra_apis);
    }

    fn parse_foreign_item(&mut self, i: ForeignItem) -> Result<(), ConvertErrorWithContext> {
        match i {
            ForeignItem::Fn(item) => {
                let annotations = BindgenSemanticAttributes::new(&item.attrs);
                let doc_attr = get_doc_attr(&item.attrs);
                self.funcs_to_convert.push(FuncToConvert {
                    provenance: Provenance::Bindgen,
                    self_ty: None,
                    ident: item.sig.ident,
                    doc_attr,
                    inputs: item.sig.inputs,
                    output: item.sig.output,
                    vis: item.vis,
                    virtualness: annotations.get_virtualness(),
                    cpp_vis: annotations.get_cpp_visibility(),
                    special_member: annotations.special_member_kind(),
                    unused_template_param: annotations
                        .has_attr("unused_template_param_in_arg_or_return"),
                    references: annotations.get_reference_parameters_and_return(),
                    original_name: annotations.get_original_name(),
                    synthesized_this_type: None,
                    add_to_trait: None,
                    is_deleted: annotations.has_attr("deleted"),
                    synthetic_cpp: None,
                });
                Ok(())
            }
            ForeignItem::Static(item) => Err(ConvertErrorWithContext(
                ConvertError::StaticData(item.ident.to_string()),
                Some(ErrorContext::new_for_item(item.ident)),
            )),
            _ => Err(ConvertErrorWithContext(
                ConvertError::UnexpectedForeignItem,
                None,
            )),
        }
    }

    /// Record information from impl blocks encountered in bindgen
    /// output.
    pub(crate) fn convert_impl_items(&mut self, imp: ItemImpl) {
        let ty_id = match *imp.self_ty {
            Type::Path(typ) => typ.path.segments.last().unwrap().ident.clone(),
            _ => return,
        };
        for i in imp.items {
            if let ImplItem::Method(itm) = i {
                let effective_fun_name = match get_called_function(&itm.block) {
                    Some(id) => id.clone(),
                    None => itm.sig.ident,
                };
                self.method_receivers.insert(
                    effective_fun_name,
                    QualifiedName::new(&self.ns, ty_id.clone()),
                );
            }
        }
    }

    /// Indicate that all foreign mods and all impl blocks have been
    /// fed into us, and we should process that information to generate
    /// the resulting APIs.
    pub(crate) fn finished(mut self, apis: &mut ApiVec<NullPhase>) {
        apis.append(&mut self.ignored_apis);
        while !self.funcs_to_convert.is_empty() {
            let mut fun = self.funcs_to_convert.remove(0);
            fun.self_ty = self.method_receivers.get(&fun.ident).cloned();
            apis.push(UnanalyzedApi::Function {
                name: ApiName::new_with_cpp_name(
                    &self.ns,
                    fun.ident.clone(),
                    fun.original_name.clone(),
                ),
                fun: Box::new(fun),
                analysis: (),
            })
        }
    }
}

/// bindgen sometimes generates an impl fn called a which calls
/// a function called a1(), if it's dealing with conflicting names.
/// We actually care about the name a1, so we have to parse the
/// name of the actual function call inside the block's body.
fn get_called_function(block: &Block) -> Option<&Ident> {
    match block.stmts.first() {
        Some(Stmt::Expr(Expr::Call(ExprCall { func, .. }))) => match **func {
            Expr::Path(ref exp) => exp.path.segments.first().map(|ps| &ps.ident),
            _ => None,
        },
        _ => None,
    }
}

#[cfg(test)]
mod test {
    use super::get_called_function;
    use syn::parse_quote;
    use syn::Block;

    #[test]
    fn test_get_called_function() {
        let b: Block = parse_quote! {
            {
                call_foo()
            }
        };
        assert_eq!(get_called_function(&b).unwrap().to_string(), "call_foo");
    }
}
<commit_msg>Support updated autocxx-bindgen attribute.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::conversion::api::{ApiName, NullPhase, Provenance};
use crate::conversion::apivec::ApiVec;
use crate::conversion::doc_attr::get_doc_attr;
use crate::conversion::error_reporter::report_any_error;
use crate::conversion::{
    api::{FuncToConvert, UnanalyzedApi},
    convert_error::ConvertErrorWithContext,
    convert_error::ErrorContext,
};
use crate::{
    conversion::ConvertError,
    types::{Namespace, QualifiedName},
};
use std::collections::HashMap;
use syn::{Block, Expr, ExprCall, ForeignItem, Ident, ImplItem, ItemImpl, Stmt, Type};

use super::bindgen_semantic_attributes::BindgenSemanticAttributes;

/// Parses a given bindgen-generated 'mod' into suitable
/// [Api]s. In bindgen output, a given mod concerns
/// a specific C++ namespace.
pub(crate) struct ParseForeignMod {
    ns: Namespace,
    // We mostly act upon the functions we see within the 'extern "C"'
    // block of bindgen output, but we can't actually do this until
    // we've seen the (possibly subsequent) 'impl' blocks so we can
    // deduce which functions are actually static methods. Hence
    // store them.
    funcs_to_convert: Vec<FuncToConvert>,
    // Evidence from 'impl' blocks about which of these items
    // may actually be methods (static or otherwise). Mapping from
    // function name to type name.
    method_receivers: HashMap<Ident, QualifiedName>,
    ignored_apis: ApiVec<NullPhase>,
}

impl ParseForeignMod {
    pub(crate) fn new(ns: Namespace) -> Self {
        Self {
            ns,
            funcs_to_convert: Vec::new(),
            method_receivers: HashMap::new(),
            ignored_apis: ApiVec::new(),
        }
    }

    /// Record information from foreign mod items encountered
    /// in bindgen output.
    pub(crate) fn convert_foreign_mod_items(&mut self, foreign_mod_items: Vec<ForeignItem>) {
        let mut extra_apis = ApiVec::new();
        for i in foreign_mod_items {
            report_any_error(&self.ns.clone(), &mut extra_apis, || {
                self.parse_foreign_item(i)
            });
        }
        self.ignored_apis.append(&mut extra_apis);
    }

    fn parse_foreign_item(&mut self, i: ForeignItem) -> Result<(), ConvertErrorWithContext> {
        match i {
            ForeignItem::Fn(item) => {
                let annotations = BindgenSemanticAttributes::new(&item.attrs);
                let doc_attr = get_doc_attr(&item.attrs);
                self.funcs_to_convert.push(FuncToConvert {
                    provenance: Provenance::Bindgen,
                    self_ty: None,
                    ident: item.sig.ident,
                    doc_attr,
                    inputs: item.sig.inputs,
                    output: item.sig.output,
                    vis: item.vis,
                    virtualness: annotations.get_virtualness(),
                    cpp_vis: annotations.get_cpp_visibility(),
                    special_member: annotations.special_member_kind(),
                    unused_template_param: annotations
                        .has_attr("unused_template_param_in_arg_or_return")
                        || annotations.has_attr("incomprehensible_param_in_arg_or_return"),
                    references: annotations.get_reference_parameters_and_return(),
                    original_name: annotations.get_original_name(),
                    synthesized_this_type: None,
                    add_to_trait: None,
                    is_deleted: annotations.has_attr("deleted"),
                    synthetic_cpp: None,
                });
                Ok(())
            }
            ForeignItem::Static(item) => Err(ConvertErrorWithContext(
                ConvertError::StaticData(item.ident.to_string()),
                Some(ErrorContext::new_for_item(item.ident)),
            )),
            _ => Err(ConvertErrorWithContext(
                ConvertError::UnexpectedForeignItem,
                None,
            )),
        }
    }

    /// Record information from impl blocks encountered in bindgen
    /// output.
    pub(crate) fn convert_impl_items(&mut self, imp: ItemImpl) {
        let ty_id = match *imp.self_ty {
            Type::Path(typ) => typ.path.segments.last().unwrap().ident.clone(),
            _ => return,
        };
        for i in imp.items {
            if let ImplItem::Method(itm) = i {
                let effective_fun_name = match get_called_function(&itm.block) {
                    Some(id) => id.clone(),
                    None => itm.sig.ident,
                };
                self.method_receivers.insert(
                    effective_fun_name,
                    QualifiedName::new(&self.ns, ty_id.clone()),
                );
            }
        }
    }

    /// Indicate that all foreign mods and all impl blocks have been
    /// fed into us, and we should process that information to generate
    /// the resulting APIs.
    pub(crate) fn finished(mut self, apis: &mut ApiVec<NullPhase>) {
        apis.append(&mut self.ignored_apis);
        while !self.funcs_to_convert.is_empty() {
            let mut fun = self.funcs_to_convert.remove(0);
            fun.self_ty = self.method_receivers.get(&fun.ident).cloned();
            apis.push(UnanalyzedApi::Function {
                name: ApiName::new_with_cpp_name(
                    &self.ns,
                    fun.ident.clone(),
                    fun.original_name.clone(),
                ),
                fun: Box::new(fun),
                analysis: (),
            })
        }
    }
}

/// bindgen sometimes generates an impl fn called a which calls
/// a function called a1(), if it's dealing with conflicting names.
/// We actually care about the name a1, so we have to parse the
/// name of the actual function call inside the block's body.
fn get_called_function(block: &Block) -> Option<&Ident> {
    match block.stmts.first() {
        Some(Stmt::Expr(Expr::Call(ExprCall { func, .. }))) => match **func {
            Expr::Path(ref exp) => exp.path.segments.first().map(|ps| &ps.ident),
            _ => None,
        },
        _ => None,
    }
}

#[cfg(test)]
mod test {
    use super::get_called_function;
    use syn::parse_quote;
    use syn::Block;

    #[test]
    fn test_get_called_function() {
        let b: Block = parse_quote! {
            {
                call_foo()
            }
        };
        assert_eq!(get_called_function(&b).unwrap().to_string(), "call_foo");
    }
}
<|endoftext|>


<commit_before>static X: usize = 5;

#[allow(mutable_transmutes)]
fn main() {
    let _x = unsafe {
        std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR borrow stack
    };
}
<commit_msg>fix a Stacked Borrows test whose output changed<commit_after>static X: usize = 5;

#[allow(mutable_transmutes)]
fn main() {
    let _x = unsafe {
        std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR writing to alloc0 which is read-only
    };
}
<|endoftext|>


<commit_before>pub mod prefetch;
pub mod compression;
pub mod utils;
<commit_msg>add submodules<commit_after>pub mod prefetch;
pub mod compression;
pub mod utils;
pub mod errors;
pub mod fileinfo;
<|endoftext|>


<commit_before>macro_rules! log {
    (target: $target:expr, $lvl:expr, $($arg:tt)+) => {
        let _ = $target;
        let _ = log!($lvl, $($arg)+);
    };
    ($lvl:expr, $($arg:tt)+) => {{
        let _ = $lvl;
        let _ = format_args!($($arg)+);
    }};
}
macro_rules! error {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
    ($($arg:tt)*) => { log!("", $($arg)*); };
}
macro_rules! warn {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
    ($($arg:tt)*) => { log!("", $($arg)*); };
}
macro_rules! info {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
    ($($arg:tt)*) => { log!("", $($arg)*); };
}
macro_rules! debug {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
    ($($arg:tt)*) => { log!("", $($arg)*); };
}
macro_rules! trace {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
    ($($arg:tt)*) => { log!("", $($arg)*); };
}
<commit_msg>Allow log stubs to be unused.<commit_after>#![allow(unused)]

macro_rules! log {
    (target: $target:expr, $lvl:expr, $($arg:tt)+) => {
        let _ = $target;
        let _ = log!($lvl, $($arg)+);
    };
    ($lvl:expr, $($arg:tt)+) => {{
        let _ = $lvl;
        let _ = format_args!($($arg)+);
    }};
}
macro_rules! error {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
    ($($arg:tt)*) => { log!("", $($arg)*); };
}
macro_rules! warn {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
    ($($arg:tt)*) => { log!("", $($arg)*); };
}
macro_rules! info {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
    ($($arg:tt)*) => { log!("", $($arg)*); };
}
macro_rules! debug {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
    ($($arg:tt)*) => { log!("", $($arg)*); };
}
macro_rules! trace {
    (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); };
    ($($arg:tt)*) => { log!("", $($arg)*); };
}
<|endoftext|>


<commit_before>//! Utilities to talk to Lua

use rlua::{self, Table};
use rustwlc::*;

const MOD_NAMES: [&str; 8] = ["Shift", "Caps", "Control", "Alt",
                              "Mod2", "Mod3", "Mod4", "Mod5"];

/// Convert a modifier to the Lua interpretation
pub fn mods_to_lua(lua: &rlua::Lua, mut mods: KeyMod) -> rlua::Result<Table> {
    let mut mods_list: Vec<String> = Vec::with_capacity(MOD_NAMES.len());
    for mod_name in &MOD_NAMES {
        if mods == MOD_NONE {
            break;
        }
        if mods.bits() & 1 != 0 {
            mods_list.push((*mod_name).into());
        }
        mods = KeyMod::from_bits_truncate(mods.bits() >> 1);
    }
    lua.create_table_from(mods_list.into_iter().enumerate())
}
<commit_msg>Added mouse_events_to_lua helper function<commit_after>//! Utilities to talk to Lua

use rlua::{self, Table};
use rustwlc::*;

const MOD_NAMES: [&str; 8] = ["Shift", "Caps", "Control", "Alt",
                              "Mod2", "Mod3", "Mod4", "Mod5"];
const MOUSE_EVENTS: [u32; 6] = [
    // TODO This only grabs the buttons, not the scroll
    // This is a WLC limitation, it will be lifted later!

    272,  // button mask 1
    273,  // button mask 2
    274, // button mask 3
    275, // button mask 4
    276, // button mask 5

    // TODO currently unused
    1 << 15  /* mask any */];

/// Convert a modifier to the Lua interpretation
pub fn mods_to_lua(lua: &rlua::Lua, mut mods: KeyMod) -> rlua::Result<Table> {
    let mut mods_list: Vec<String> = Vec::with_capacity(MOD_NAMES.len());
    for mod_name in &MOD_NAMES {
        if mods == MOD_NONE {
            break;
        }
        if mods.bits() & 1 != 0 {
            mods_list.push((*mod_name).into());
        }
        mods = KeyMod::from_bits_truncate(mods.bits() >> 1);
    }
    lua.create_table_from(mods_list.into_iter().enumerate())
}

/// Convert a mouse event from Wayland to the representation Lua expcets
pub fn mouse_events_to_lua(_: &rlua::Lua, button: u32,
                           button_state: ButtonState) -> rlua::Result<Vec<bool>> {
    let mut event_list = Vec::with_capacity(MOUSE_EVENTS.len());
    for mouse_event in &MOUSE_EVENTS[..5] {
        let state_pressed = button_state == ButtonState::Pressed;
        let is_pressed = button == *mouse_event && state_pressed;
        event_list.push(is_pressed);
    }
    Ok(event_list)
}
<|endoftext|>


<commit_before>use scene::{BoxedScene, Scene, SceneChangeEvent, SceneName};
use engine::EngineData;
use text_renderer::TextRenderer;
use sdl2::pixels::{Color, PixelFormatEnum};
use sdl2::surface::Surface;
use std::io::Result;
use std::path::Path;
use uorustlibs::color::{Color16, Color as ColorTrait};
use uorustlibs::map::{MapReader, Block, RadarColReader, StaticReader, StaticLocation};
use uorustlibs::map::map_size::{TRAMMEL, FELUCCA, ILSHENAR, MALAS};

use std::io::{Error};
use sdl2::render::{Renderer, Texture, TextureQuery};
use sdl2::rect::Rect;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;

use map::lens::MapLens;
use map::Facet;

const MAX_BLOCKS_WIDTH: u32 = 1024 / 8;
const MAX_BLOCKS_HEIGHT: u32 = 768 / 8;
const STEP_X: u32 = MAX_BLOCKS_WIDTH / 4;
const STEP_Y: u32 = MAX_BLOCKS_HEIGHT / 4;

enum MapRenderMode {
    HeightMap,
    RadarMap,
    StaticsMap,
}

const MAP_DETAILS: [(&'static str, &'static str, &'static str, (u32, u32)); 4] = [
    ("./assets/map0.mul", "./assets/staidx0.mul", "./assets/statics0.mul", TRAMMEL),
    ("./assets/map0.mul", "./assets/staidx0.mul", "./assets/statics0.mul", FELUCCA),
    ("./assets/map2.mul", "./assets/staidx2.mul", "./assets/statics2.mul", ILSHENAR),
    ("./assets/map3.mul", "./assets/staidx3.mul", "./assets/statics3.mul", MALAS),
];

pub struct MapScene {
    facet: Facet,
    map_id: u8,
    radar_colors: Result<Vec<Color16>>,
    mode: MapRenderMode,
    texture: Option<Texture>,
}

pub fn draw_heightmap_block<'a>(block: &Block, statics: &Vec<StaticLocation>, radar_cols: &Result<Vec<Color16>>) -> Surface<'a> {
    let mut surface = Surface::new(8, 8, PixelFormatEnum::RGBA8888).unwrap();
    surface.with_lock_mut(|bitmap| {
        for y in 0..8 {
            for x in 0..8 {
                let target = (x + (y * 8));
                let height = (block.cells[target].altitude as i16 + 128) as u8;
                bitmap[target * 4] = 255;
                bitmap[target * 4 + 1] = height;
                bitmap[target * 4 + 2] = height;
                bitmap[target * 4 + 3] = height;
            }
        };
    });
    surface
}

pub fn draw_radarcol_block<'a>(block: &Block, statics: &Vec<StaticLocation>, radar_cols: &Result<Vec<Color16>>) -> Surface<'a> {
    let mut surface = Surface::new(8, 8, PixelFormatEnum::RGBA8888).unwrap();
    surface.with_lock_mut(|bitmap| {
        for y in 0..8 {
            for x in 0..8 {
                let target = (x + (y * 8));
                let index = block.cells[target].graphic;
                let (r, g, b, _) = match radar_cols {
                    &Ok(ref colors) => colors[index as usize].to_rgba(),
                    _ => index.to_rgba()
                };
                bitmap[target * 4] = 255;
                bitmap[target * 4 + 1] = b;
                bitmap[target * 4 + 2] = g;
                bitmap[target * 4 + 3] = r;
            }
        };
    });
    surface
}

pub fn draw_statics_block<'a>(block: &Block, statics: &Vec<StaticLocation>, radar_cols: &Result<Vec<Color16>>) -> Surface<'a> {
    let mut surface = draw_radarcol_block(block, statics, radar_cols);
    let mut last_height_locs = vec![-127; 64];
    surface.with_lock_mut(|bitmap| {
        for stat in statics {
            let lookup = (stat.x + (stat.y * 8)) as usize;
            if last_height_locs[lookup] < stat.altitude {
                // Paint the cell as we're higher.
                // Inefficient, but probably no worse than trying to keep track of which items are in which cell
                let (r, g, b, _) = match radar_cols {
                    &Ok(ref colors) => colors[stat.color_idx() as usize].to_rgba(),
                    _ => (0, 0, 0, 0)
                };
                bitmap[lookup * 4] = 255;
                bitmap[lookup * 4 + 1] = b;
                bitmap[lookup * 4 + 2] = g;
                bitmap[lookup * 4 + 3] = r;

                last_height_locs[lookup] = stat.altitude;
            }
        }
    });
    surface
}

pub fn map_id_to_facet(id: u8) -> Facet {
    let corrected_id = if id as usize >= MAP_DETAILS.len() {
        0
    } else {
        id as usize
    };
    let (map, idx, statics, (width, height)) = MAP_DETAILS[corrected_id];
    Facet::new(&Path::new(map), &Path::new(idx), &Path::new(statics), width / 8, height / 8)
}

impl MapScene {
    pub fn new<'a>(renderer: &mut Renderer, engine_data: &mut EngineData<'a>) -> BoxedScene<SceneName, EngineData<'a>> {
        let colors = RadarColReader::new(&Path::new("./assets/radarcol.mul"))
            .and_then(|mut reader| reader.read_colors());

        let mut scene = Box::new(MapScene {
            facet: map_id_to_facet(0),
            map_id: 0,
            texture: None,
            mode: MapRenderMode::HeightMap,
            radar_colors: colors,
        });

        scene.draw_page(renderer, engine_data);
        scene
    }

    pub fn draw_page(&mut self, renderer: &mut Renderer, engine_data: &mut EngineData) {
        let lens = self.facet.get_lens();

        self.texture = match lens {
            &Some(ref lens) => {
                let mut surface = Surface::new(1024, 768, PixelFormatEnum::RGBA8888).unwrap();
                let block_drawer = match self.mode {
                    MapRenderMode::HeightMap => draw_heightmap_block,
                    MapRenderMode::RadarMap => draw_radarcol_block,
                    MapRenderMode::StaticsMap => draw_statics_block,
                };
                for y in 0..lens.height {
                    for x in 0..lens.width {
                        match &lens.blocks[(x + (y * MAX_BLOCKS_WIDTH)) as usize] {
                            &(Some(ref block), Some(ref statics)) => {
                                let block_surface = block_drawer(block, statics, &self.radar_colors);
                                block_surface.blit(None, &mut surface, Some(Rect::new(x as i32 * 8, y as i32* 8, block_surface.width(), block_surface.height()))).unwrap();
                            },
                            &(Some(ref block), _) => {
                                let block_surface = block_drawer(block, &vec![], &self.radar_colors);
                                block_surface.blit(None, &mut surface, Some(Rect::new(x as i32 * 8, y as i32* 8, block_surface.width(), block_surface.height()))).unwrap();
                            },
                            _ => ()
                        }
                    }
                }
                Some(renderer.create_texture_from_surface(&surface).unwrap())
            },
            &None => None
        }
    }
}

impl<'a> Scene<SceneName, EngineData<'a>> for MapScene {
    fn render(&self, renderer: &mut Renderer, engine_data: &mut EngineData) {
        renderer.clear();
        match self.texture {
            Some(ref texture) => {
                renderer.copy(texture, None, None).unwrap();
            },
            None => ()
        };
        renderer.present();
    }

    fn handle_event(&mut self, event: &Event, renderer: &mut Renderer, engine_data: &mut EngineData) -> Option<SceneChangeEvent<SceneName>> {
        match *event {
            Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                Some(SceneChangeEvent::PopScene)
            },
            Event::KeyDown { keycode: Some(Keycode::Left), .. } => {
                if self.facet.x >= STEP_X as u32 {
                    self.facet.x -= STEP_X as u32;
                    self.draw_page(renderer, engine_data);
                }
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Right), .. } => {
                self.facet.x += STEP_X as u32;
                self.draw_page(renderer, engine_data);
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Up), .. } => {
                if self.facet.y >= STEP_Y as u32 {
                    self.facet.y -= STEP_Y as u32;
                    self.draw_page(renderer, engine_data);
                }
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Down), .. } => {
                self.facet.y += STEP_Y as u32;
                self.draw_page(renderer, engine_data);
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Num1), .. } => {
                self.mode = MapRenderMode::HeightMap;
                self.draw_page(renderer, engine_data);
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Num2), .. } => {
                self.mode = MapRenderMode::RadarMap;
                self.draw_page(renderer, engine_data);
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Num3), .. } => {
                self.mode = MapRenderMode::StaticsMap;
                self.draw_page(renderer, engine_data);
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Tab), .. } => {
                self.mode = MapRenderMode::HeightMap;
                self.map_id = (self.map_id + 1) % MAP_DETAILS.len() as u8;
                self.facet = map_id_to_facet(self.map_id);
                self.draw_page(renderer, engine_data);
                None
            },
             _ => None
        }
    }
}
<commit_msg>Corrected lifetime shenanigans<commit_after>use scene::{BoxedScene, Scene, SceneChangeEvent, SceneName};
use engine::EngineData;
use text_renderer::TextRenderer;
use sdl2::pixels::{Color, PixelFormatEnum};
use sdl2::surface::Surface;
use std::io::Result;
use std::path::Path;
use uorustlibs::color::{Color16, Color as ColorTrait};
use uorustlibs::map::{MapReader, Block, RadarColReader, StaticReader, StaticLocation};
use uorustlibs::map::map_size::{TRAMMEL, FELUCCA, ILSHENAR, MALAS};

use std::io::{Error};
use sdl2::render::{Renderer, Texture, TextureQuery};
use sdl2::rect::Rect;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;

use map::lens::MapLens;
use map::Facet;

const MAX_BLOCKS_WIDTH: u32 = 1024 / 8;
const MAX_BLOCKS_HEIGHT: u32 = 768 / 8;
const STEP_X: u32 = MAX_BLOCKS_WIDTH / 4;
const STEP_Y: u32 = MAX_BLOCKS_HEIGHT / 4;

enum MapRenderMode {
    HeightMap,
    RadarMap,
    StaticsMap,
}

const MAP_DETAILS: [(&'static str, &'static str, &'static str, (u32, u32)); 4] = [
    ("./assets/map0.mul", "./assets/staidx0.mul", "./assets/statics0.mul", TRAMMEL),
    ("./assets/map0.mul", "./assets/staidx0.mul", "./assets/statics0.mul", FELUCCA),
    ("./assets/map2.mul", "./assets/staidx2.mul", "./assets/statics2.mul", ILSHENAR),
    ("./assets/map3.mul", "./assets/staidx3.mul", "./assets/statics3.mul", MALAS),
];

pub struct MapScene {
    facet: Facet,
    map_id: u8,
    radar_colors: Result<Vec<Color16>>,
    mode: MapRenderMode,
    texture: Option<Texture>,
}

pub fn draw_heightmap_block(block: &Block, statics: &Vec<StaticLocation>, radar_cols: &Result<Vec<Color16>>) -> Surface<'static> {
    let mut surface = Surface::new(8, 8, PixelFormatEnum::RGBA8888).unwrap();
    surface.with_lock_mut(|bitmap| {
        for y in 0..8 {
            for x in 0..8 {
                let target = (x + (y * 8));
                let height = (block.cells[target].altitude as i16 + 128) as u8;
                bitmap[target * 4] = 255;
                bitmap[target * 4 + 1] = height;
                bitmap[target * 4 + 2] = height;
                bitmap[target * 4 + 3] = height;
            }
        };
    });
    surface
}

pub fn draw_radarcol_block(block: &Block, statics: &Vec<StaticLocation>, radar_cols: &Result<Vec<Color16>>) -> Surface<'static> {
    let mut surface = Surface::new(8, 8, PixelFormatEnum::RGBA8888).unwrap();
    surface.with_lock_mut(|bitmap| {
        for y in 0..8 {
            for x in 0..8 {
                let target = (x + (y * 8));
                let index = block.cells[target].graphic;
                let (r, g, b, _) = match radar_cols {
                    &Ok(ref colors) => colors[index as usize].to_rgba(),
                    _ => index.to_rgba()
                };
                bitmap[target * 4] = 255;
                bitmap[target * 4 + 1] = b;
                bitmap[target * 4 + 2] = g;
                bitmap[target * 4 + 3] = r;
            }
        };
    });
    surface
}

pub fn draw_statics_block(block: &Block, statics: &Vec<StaticLocation>, radar_cols: &Result<Vec<Color16>>) -> Surface<'static> {
    let mut surface = draw_radarcol_block(block, statics, radar_cols);
    let mut last_height_locs = vec![-127; 64];
    surface.with_lock_mut(|bitmap| {
        for stat in statics {
            let lookup = (stat.x + (stat.y * 8)) as usize;
            if last_height_locs[lookup] < stat.altitude {
                // Paint the cell as we're higher.
                // Inefficient, but probably no worse than trying to keep track of which items are in which cell
                let (r, g, b, _) = match radar_cols {
                    &Ok(ref colors) => colors[stat.color_idx() as usize].to_rgba(),
                    _ => (0, 0, 0, 0)
                };
                bitmap[lookup * 4] = 255;
                bitmap[lookup * 4 + 1] = b;
                bitmap[lookup * 4 + 2] = g;
                bitmap[lookup * 4 + 3] = r;

                last_height_locs[lookup] = stat.altitude;
            }
        }
    });
    surface
}

pub fn map_id_to_facet(id: u8) -> Facet {
    let corrected_id = if id as usize >= MAP_DETAILS.len() {
        0
    } else {
        id as usize
    };
    let (map, idx, statics, (width, height)) = MAP_DETAILS[corrected_id];
    Facet::new(&Path::new(map), &Path::new(idx), &Path::new(statics), width / 8, height / 8)
}

impl MapScene {
    pub fn new<'a>(renderer: &mut Renderer, engine_data: &mut EngineData<'a>) -> BoxedScene<SceneName, EngineData<'a>> {
        let colors = RadarColReader::new(&Path::new("./assets/radarcol.mul"))
            .and_then(|mut reader| reader.read_colors());

        let mut scene = Box::new(MapScene {
            facet: map_id_to_facet(0),
            map_id: 0,
            texture: None,
            mode: MapRenderMode::HeightMap,
            radar_colors: colors,
        });

        scene.draw_page(renderer, engine_data);
        scene
    }

    pub fn draw_page(&mut self, renderer: &mut Renderer, engine_data: &mut EngineData) {
        let lens = self.facet.get_lens();

        self.texture = match lens {
            &Some(ref lens) => {
                let mut surface = Surface::new(1024, 768, PixelFormatEnum::RGBA8888).unwrap();
                let block_drawer = match self.mode {
                    MapRenderMode::HeightMap => draw_heightmap_block,
                    MapRenderMode::RadarMap => draw_radarcol_block,
                    MapRenderMode::StaticsMap => draw_statics_block,
                };
                for y in 0..lens.height {
                    for x in 0..lens.width {
                        match &lens.blocks[(x + (y * MAX_BLOCKS_WIDTH)) as usize] {
                            &(Some(ref block), Some(ref statics)) => {
                                let block_surface = block_drawer(block, statics, &self.radar_colors);
                                block_surface.blit(None, &mut surface, Some(Rect::new(x as i32 * 8, y as i32* 8, block_surface.width(), block_surface.height()))).unwrap();
                            },
                            &(Some(ref block), _) => {
                                let block_surface = block_drawer(block, &vec![], &self.radar_colors);
                                block_surface.blit(None, &mut surface, Some(Rect::new(x as i32 * 8, y as i32* 8, block_surface.width(), block_surface.height()))).unwrap();
                            },
                            _ => ()
                        }
                    }
                }
                Some(renderer.create_texture_from_surface(&surface).unwrap())
            },
            &None => None
        }
    }
}

impl<'a> Scene<SceneName, EngineData<'a>> for MapScene {
    fn render(&self, renderer: &mut Renderer, engine_data: &mut EngineData) {
        renderer.clear();
        match self.texture {
            Some(ref texture) => {
                renderer.copy(texture, None, None).unwrap();
            },
            None => ()
        };
        renderer.present();
    }

    fn handle_event(&mut self, event: &Event, renderer: &mut Renderer, engine_data: &mut EngineData) -> Option<SceneChangeEvent<SceneName>> {
        match *event {
            Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                Some(SceneChangeEvent::PopScene)
            },
            Event::KeyDown { keycode: Some(Keycode::Left), .. } => {
                if self.facet.x >= STEP_X as u32 {
                    self.facet.x -= STEP_X as u32;
                    self.draw_page(renderer, engine_data);
                }
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Right), .. } => {
                self.facet.x += STEP_X as u32;
                self.draw_page(renderer, engine_data);
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Up), .. } => {
                if self.facet.y >= STEP_Y as u32 {
                    self.facet.y -= STEP_Y as u32;
                    self.draw_page(renderer, engine_data);
                }
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Down), .. } => {
                self.facet.y += STEP_Y as u32;
                self.draw_page(renderer, engine_data);
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Num1), .. } => {
                self.mode = MapRenderMode::HeightMap;
                self.draw_page(renderer, engine_data);
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Num2), .. } => {
                self.mode = MapRenderMode::RadarMap;
                self.draw_page(renderer, engine_data);
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Num3), .. } => {
                self.mode = MapRenderMode::StaticsMap;
                self.draw_page(renderer, engine_data);
                None
            },
            Event::KeyDown { keycode: Some(Keycode::Tab), .. } => {
                self.mode = MapRenderMode::HeightMap;
                self.map_id = (self.map_id + 1) % MAP_DETAILS.len() as u8;
                self.facet = map_id_to_facet(self.map_id);
                self.draw_page(renderer, engine_data);
                None
            },
             _ => None
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;

#[cfg(feature = "generation")] use generation;
#[cfg(feature = "validation")] use validation;

use MultiHash::*;

#[allow(non_camel_case_types)]
pub enum MultiHash {
    Sha1([u8; 20], usize),
    Sha2_256([u8; 32], usize),
    Sha2_512([u8; 64], usize),
    Sha3_512([u8; 64], usize),
    Sha3_384([u8; 48], usize),
    Sha3_256([u8; 32], usize),
    Sha3_224([u8; 28], usize),
    Shake128([u8; 16], usize),
    Shake256([u8; 32], usize),
    Blake2B([u8; 64], usize),
    Blake2S([u8; 32], usize),
    ApplicationSpecific {
        code: u8,
        bytes: Vec<u8>,
    },
}

impl MultiHash {
    pub fn from_bytes<B: AsRef<[u8]>>(bytes: B) -> Result<MultiHash, &'static str> {
        let bytes = bytes.as_ref();
        let code = bytes[0];
        let length = bytes[1] as usize;
        let mut hash = try!(MultiHash::from_code_and_length(code, length));
        hash.digest_mut()[..length].copy_from_slice(&bytes[2..length+2]);
        Ok(hash)
    }

    // TODO: Real error type
    /// Returns an empty multihash of the specified type, validates code and length
    pub fn from_code_and_length(code: u8, length: usize) -> Result<MultiHash, &'static str> {
        Ok(match code {
            0x11 if length <= 20 => Sha1([0; 20], length),
            0x12 if length <= 32 => Sha2_256([0; 32], length),
            0x13 if length <= 64 => Sha2_512([0; 64], length),
            0x14 if length <= 64 => Sha3_512([0; 64], length),
            0x15 if length <= 48 => Sha3_384([0; 48], length),
            0x16 if length <= 32 => Sha3_256([0; 32], length),
            0x17 if length <= 28 => Sha3_224([0; 28], length),
            0x18 if length <= 16 => Shake128([0; 16], length),
            0x19 if length <= 32 => Shake256([0; 32], length),

            0x40 if length <= 64 => Blake2B([0; 64], length),
            0x41 if length <= 32 => Blake2S([0; 32], length),

            _ if code < 0x10 && length < 0x7f =>
                ApplicationSpecific { code: code, bytes: vec![0; length] },
            _ if code > 0x7f => {
                return Err("Codes greater than 0x7f are an unsupported future feature")
            }
            _ => {
                return Err("MultiHash length exceeds allowed length for specified type")
            }
        })
    }

    #[cfg(all(feature = "generation"))]
    pub fn generate<D: AsRef<[u8]>>(data: D) -> MultiHash {
        generation::generate_default(data.digest())
    }

    #[cfg(all(feature = "generation", feature = "sha2"))]
    pub fn generate_sha256<D: AsRef<[u8]>>(data: D) -> MultiHash {
        generation::generate_sha256(data.digest())
    }

    #[cfg(all(feature = "generation", feature = "sha2"))]
    pub fn generate_sha512<D: AsRef<[u8]>>(data: D) -> MultiHash {
        generation::generate_sha512(data.digest())
    }

    pub fn len(&self) -> usize {
        match *self {
            Sha1(_, length) => length,
            Sha2_256(_, length) => length,
            Sha2_512(_, length) => length,
            Sha3_224(_, length) => length,
            Sha3_256(_, length) => length,
            Sha3_384(_, length) => length,
            Sha3_512(_, length) => length,
            Shake128(_, length) => length,
            Shake256(_, length) => length,
            Blake2B(_, length) => length,
            Blake2S(_, length) => length,
            ApplicationSpecific { ref bytes, .. } => bytes.len(),
        }
    }

    pub fn code(&self) -> u8 {
        match *self {
            Sha1(..) => 0x11,
            Sha2_256(..) => 0x12,
            Sha2_512(..) => 0x13,
            Sha3_512(..) => 0x14,
            Sha3_384(..) => 0x15,
            Sha3_256(..) => 0x16,
            Sha3_224(..) => 0x17,
            Shake128(..) => 0x18,
            Shake256(..) => 0x19,
            Blake2B(..) => 0x40,
            Blake2S(..) => 0x41,

            ApplicationSpecific { code, .. } if code < 0x10 => code,

            // TODO: could just ignore them being invalid or return Error...
            ApplicationSpecific { code, .. } =>
                panic!("application specific code {:#02x} outside allowed range 0x00-0x0f", code),
        }
    }

    pub fn name(&self) -> &'static str {
        match *self {
            Sha1(..) => "sha1",
            Sha2_256(..) => "sha2-256",
            Sha2_512(..) => "sha2-512",
            Sha3_224(..) => "sha3-224",
            Sha3_256(..) => "sha3-256",
            Sha3_384(..) => "sha3-384",
            Sha3_512(..) => "sha3-512",
            Shake128(..) => "shake-128",
            Shake256(..) => "shake-256",
            Blake2B(..) => "blake2b",
            Blake2S(..) => "blake2s",

            ApplicationSpecific { code, .. } if code < 0x10 => "app-specific",
            _ => panic!("TODO: not panic"),
        }
    }

    /// Returns None if there is no validator for this digest type, otherwise
    /// the result of the validator
    #[cfg(feature = "validation")]
    pub fn validate<D: AsRef<[u8]>>(&self, data: D) -> Option<validation::Result> {
        validation::validate(self, data.digest())
    }

    pub fn digest(&self) -> &[u8] {
        match *self {
            Sha1(ref bytes, length) => &bytes[..length],
            Sha2_256(ref bytes, length) => &bytes[..length],
            Sha2_512(ref bytes, length) => &bytes[..length],
            Sha3_224(ref bytes, length) => &bytes[..length],
            Sha3_256(ref bytes, length) => &bytes[..length],
            Sha3_384(ref bytes, length) => &bytes[..length],
            Sha3_512(ref bytes, length) => &bytes[..length],
            Shake128(ref bytes, length) => &bytes[..length],
            Shake256(ref bytes, length) => &bytes[..length],
            Blake2B(ref bytes, length) => &bytes[..length],
            Blake2S(ref bytes, length) => &bytes[..length],
            ApplicationSpecific { ref bytes, .. } => bytes,
        }
    }

    pub fn digest_mut(&mut self) -> &mut [u8] {
        match *self {
            Sha1(ref mut bytes, length) => &mut bytes[..length],
            Sha2_256(ref mut bytes, length) => &mut bytes[..length],
            Sha2_512(ref mut bytes, length) => &mut bytes[..length],
            Sha3_224(ref mut bytes, length) => &mut bytes[..length],
            Sha3_256(ref mut bytes, length) => &mut bytes[..length],
            Sha3_384(ref mut bytes, length) => &mut bytes[..length],
            Sha3_512(ref mut bytes, length) => &mut bytes[..length],
            Shake128(ref mut bytes, length) => &mut bytes[..length],
            Shake256(ref mut bytes, length) => &mut bytes[..length],
            Blake2B(ref mut bytes, length) => &mut bytes[..length],
            Blake2S(ref mut bytes, length) => &mut bytes[..length],
            ApplicationSpecific { ref mut bytes, .. } => bytes,
        }
    }

    pub fn into_bytes(self) -> Vec<u8> {
        if let ApplicationSpecific { code, mut bytes } = self {
            let length = bytes.len() as u8;
            bytes.insert(0, code);
            bytes.insert(1, length);
            bytes
        } else {
            self.to_bytes()
        }
    }

    pub fn to_bytes(&self) -> Vec<u8> {
        let mut bytes = Vec::with_capacity(self.len() + 2);
        bytes.push(self.code());
        bytes.push(self.len() as u8);
        bytes.extend_from_slice(self.digest());
        bytes
    }
}

impl fmt::Debug for MultiHash {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(f.write_str(self.name()));
        try!(f.write_str("(\""));
        for byte in self.digest() {
            try!(write!(f, "{:x}", byte));
        }
        try!(f.write_str("\")"));
        Ok(())
    }
}

impl Clone for MultiHash {
    fn clone(&self) -> MultiHash {
        match *self {
            Sha1(ref bytes, length) => Sha1(*bytes, length),
            Sha2_256(ref bytes, length) => Sha2_256(*bytes, length),
            Sha2_512(ref bytes, length) => Sha2_512(*bytes, length),
            Sha3_224(ref bytes, length) => Sha3_224(*bytes, length),
            Sha3_256(ref bytes, length) => Sha3_256(*bytes, length),
            Sha3_384(ref bytes, length) => Sha3_384(*bytes, length),
            Sha3_512(ref bytes, length) => Sha3_512(*bytes, length),
            Shake128(ref bytes, length) => Shake128(*bytes, length),
            Shake256(ref bytes, length) => Shake256(*bytes, length),
            Blake2B(ref bytes, length) => Blake2B(*bytes, length),
            Blake2S(ref bytes, length) => Blake2S(*bytes, length),
            ApplicationSpecific { code, ref bytes } => ApplicationSpecific {
                code: code,
                bytes: bytes.clone(),
            },
        }
    }
}

impl Eq for MultiHash {}
impl PartialEq for MultiHash {
    fn eq(&self, other: &MultiHash) -> bool {
        match (self, other) {
            (&Sha1(ref left, l1), &Sha1(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Sha2_256(ref left, l1), &Sha2_256(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Sha2_512(ref left, l1), &Sha2_512(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Sha3_224(ref left, l1), &Sha3_224(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Sha3_256(ref left, l1), &Sha3_256(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Sha3_384(ref left, l1), &Sha3_384(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Sha3_512(ref left, l1), &Sha3_512(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Shake128(ref left, l1), &Shake128(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Shake256(ref left, l1), &Shake256(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Blake2B(ref left, l1), &Blake2B(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Blake2S(ref left, l1), &Blake2S(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (
                &ApplicationSpecific { code: left_code, bytes: ref left },
                &ApplicationSpecific { code: right_code, bytes: ref right }
            ) => left_code == right_code && left == right,
            _ => false,
        }
    }
}

#[cfg(test)]
mod tests {
    use MultiHash;

    #[test]
    fn to_bytes() {
        let multihash = MultiHash::Sha1([
            0xde, 0xad, 0xbe, 0xef,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
        ], 4);
        assert_eq!(
            multihash.to_bytes(),
            vec![0x11, 0x04, 0xde, 0xad, 0xbe, 0xef]);
    }

    #[test]
    fn from_bytes() {
        let multihash = MultiHash::Sha1([
            0xde, 0xad, 0xbe, 0xef,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
        ], 4);
        assert_eq!(
            Ok(multihash),
            MultiHash::from_bytes([0x11, 0x04, 0xde, 0xad, 0xbe, 0xef]));
    }
}
<commit_msg>Add method to get serialized length<commit_after>use std::fmt;

#[cfg(feature = "generation")] use generation;
#[cfg(feature = "validation")] use validation;

use MultiHash::*;

#[allow(non_camel_case_types)]
pub enum MultiHash {
    Sha1([u8; 20], usize),
    Sha2_256([u8; 32], usize),
    Sha2_512([u8; 64], usize),
    Sha3_512([u8; 64], usize),
    Sha3_384([u8; 48], usize),
    Sha3_256([u8; 32], usize),
    Sha3_224([u8; 28], usize),
    Shake128([u8; 16], usize),
    Shake256([u8; 32], usize),
    Blake2B([u8; 64], usize),
    Blake2S([u8; 32], usize),
    ApplicationSpecific {
        code: u8,
        bytes: Vec<u8>,
    },
}

impl MultiHash {
    pub fn from_bytes<B: AsRef<[u8]>>(bytes: B) -> Result<MultiHash, &'static str> {
        let bytes = bytes.as_ref();
        let code = bytes[0];
        let length = bytes[1] as usize;
        let mut hash = try!(MultiHash::from_code_and_length(code, length));
        hash.digest_mut()[..length].copy_from_slice(&bytes[2..length+2]);
        Ok(hash)
    }

    // TODO: Real error type
    /// Returns an empty multihash of the specified type, validates code and length
    pub fn from_code_and_length(code: u8, length: usize) -> Result<MultiHash, &'static str> {
        Ok(match code {
            0x11 if length <= 20 => Sha1([0; 20], length),
            0x12 if length <= 32 => Sha2_256([0; 32], length),
            0x13 if length <= 64 => Sha2_512([0; 64], length),
            0x14 if length <= 64 => Sha3_512([0; 64], length),
            0x15 if length <= 48 => Sha3_384([0; 48], length),
            0x16 if length <= 32 => Sha3_256([0; 32], length),
            0x17 if length <= 28 => Sha3_224([0; 28], length),
            0x18 if length <= 16 => Shake128([0; 16], length),
            0x19 if length <= 32 => Shake256([0; 32], length),

            0x40 if length <= 64 => Blake2B([0; 64], length),
            0x41 if length <= 32 => Blake2S([0; 32], length),

            _ if code < 0x10 && length < 0x7f =>
                ApplicationSpecific { code: code, bytes: vec![0; length] },
            _ if code > 0x7f => {
                return Err("Codes greater than 0x7f are an unsupported future feature")
            }
            _ => {
                return Err("MultiHash length exceeds allowed length for specified type")
            }
        })
    }

    #[cfg(all(feature = "generation"))]
    pub fn generate<D: AsRef<[u8]>>(data: D) -> MultiHash {
        generation::generate_default(data.digest())
    }

    #[cfg(all(feature = "generation", feature = "sha2"))]
    pub fn generate_sha256<D: AsRef<[u8]>>(data: D) -> MultiHash {
        generation::generate_sha256(data.digest())
    }

    #[cfg(all(feature = "generation", feature = "sha2"))]
    pub fn generate_sha512<D: AsRef<[u8]>>(data: D) -> MultiHash {
        generation::generate_sha512(data.digest())
    }

    pub fn len(&self) -> usize {
        match *self {
            Sha1(_, length) => length,
            Sha2_256(_, length) => length,
            Sha2_512(_, length) => length,
            Sha3_224(_, length) => length,
            Sha3_256(_, length) => length,
            Sha3_384(_, length) => length,
            Sha3_512(_, length) => length,
            Shake128(_, length) => length,
            Shake256(_, length) => length,
            Blake2B(_, length) => length,
            Blake2S(_, length) => length,
            ApplicationSpecific { ref bytes, .. } => bytes.len(),
        }
    }

    pub fn code(&self) -> u8 {
        match *self {
            Sha1(..) => 0x11,
            Sha2_256(..) => 0x12,
            Sha2_512(..) => 0x13,
            Sha3_512(..) => 0x14,
            Sha3_384(..) => 0x15,
            Sha3_256(..) => 0x16,
            Sha3_224(..) => 0x17,
            Shake128(..) => 0x18,
            Shake256(..) => 0x19,
            Blake2B(..) => 0x40,
            Blake2S(..) => 0x41,

            ApplicationSpecific { code, .. } if code < 0x10 => code,

            // TODO: could just ignore them being invalid or return Error...
            ApplicationSpecific { code, .. } =>
                panic!("application specific code {:#02x} outside allowed range 0x00-0x0f", code),
        }
    }

    pub fn name(&self) -> &'static str {
        match *self {
            Sha1(..) => "sha1",
            Sha2_256(..) => "sha2-256",
            Sha2_512(..) => "sha2-512",
            Sha3_224(..) => "sha3-224",
            Sha3_256(..) => "sha3-256",
            Sha3_384(..) => "sha3-384",
            Sha3_512(..) => "sha3-512",
            Shake128(..) => "shake-128",
            Shake256(..) => "shake-256",
            Blake2B(..) => "blake2b",
            Blake2S(..) => "blake2s",

            ApplicationSpecific { code, .. } if code < 0x10 => "app-specific",
            _ => panic!("TODO: not panic"),
        }
    }

    /// Returns None if there is no validator for this digest type, otherwise
    /// the result of the validator
    #[cfg(feature = "validation")]
    pub fn validate<D: AsRef<[u8]>>(&self, data: D) -> Option<validation::Result> {
        validation::validate(self, data.digest())
    }

    pub fn digest(&self) -> &[u8] {
        match *self {
            Sha1(ref bytes, length) => &bytes[..length],
            Sha2_256(ref bytes, length) => &bytes[..length],
            Sha2_512(ref bytes, length) => &bytes[..length],
            Sha3_224(ref bytes, length) => &bytes[..length],
            Sha3_256(ref bytes, length) => &bytes[..length],
            Sha3_384(ref bytes, length) => &bytes[..length],
            Sha3_512(ref bytes, length) => &bytes[..length],
            Shake128(ref bytes, length) => &bytes[..length],
            Shake256(ref bytes, length) => &bytes[..length],
            Blake2B(ref bytes, length) => &bytes[..length],
            Blake2S(ref bytes, length) => &bytes[..length],
            ApplicationSpecific { ref bytes, .. } => bytes,
        }
    }

    pub fn digest_mut(&mut self) -> &mut [u8] {
        match *self {
            Sha1(ref mut bytes, length) => &mut bytes[..length],
            Sha2_256(ref mut bytes, length) => &mut bytes[..length],
            Sha2_512(ref mut bytes, length) => &mut bytes[..length],
            Sha3_224(ref mut bytes, length) => &mut bytes[..length],
            Sha3_256(ref mut bytes, length) => &mut bytes[..length],
            Sha3_384(ref mut bytes, length) => &mut bytes[..length],
            Sha3_512(ref mut bytes, length) => &mut bytes[..length],
            Shake128(ref mut bytes, length) => &mut bytes[..length],
            Shake256(ref mut bytes, length) => &mut bytes[..length],
            Blake2B(ref mut bytes, length) => &mut bytes[..length],
            Blake2S(ref mut bytes, length) => &mut bytes[..length],
            ApplicationSpecific { ref mut bytes, .. } => bytes,
        }
    }

    pub fn into_bytes(self) -> Vec<u8> {
        if let ApplicationSpecific { code, mut bytes } = self {
            let length = bytes.len() as u8;
            bytes.insert(0, code);
            bytes.insert(1, length);
            bytes
        } else {
            self.to_bytes()
        }
    }

    pub fn to_bytes(&self) -> Vec<u8> {
        let mut bytes = Vec::with_capacity(self.output_len());
        bytes.push(self.code());
        bytes.push(self.len() as u8);
        bytes.extend_from_slice(self.digest());
        bytes
    }

    /// The length of this multihash when serialized to a byte array/stream
    pub fn output_len(&self) -> usize {
        self.len() + 2
    }
}

impl fmt::Debug for MultiHash {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(f.write_str(self.name()));
        try!(f.write_str("(\""));
        for byte in self.digest() {
            try!(write!(f, "{:x}", byte));
        }
        try!(f.write_str("\")"));
        Ok(())
    }
}

impl Clone for MultiHash {
    fn clone(&self) -> MultiHash {
        match *self {
            Sha1(ref bytes, length) => Sha1(*bytes, length),
            Sha2_256(ref bytes, length) => Sha2_256(*bytes, length),
            Sha2_512(ref bytes, length) => Sha2_512(*bytes, length),
            Sha3_224(ref bytes, length) => Sha3_224(*bytes, length),
            Sha3_256(ref bytes, length) => Sha3_256(*bytes, length),
            Sha3_384(ref bytes, length) => Sha3_384(*bytes, length),
            Sha3_512(ref bytes, length) => Sha3_512(*bytes, length),
            Shake128(ref bytes, length) => Shake128(*bytes, length),
            Shake256(ref bytes, length) => Shake256(*bytes, length),
            Blake2B(ref bytes, length) => Blake2B(*bytes, length),
            Blake2S(ref bytes, length) => Blake2S(*bytes, length),
            ApplicationSpecific { code, ref bytes } => ApplicationSpecific {
                code: code,
                bytes: bytes.clone(),
            },
        }
    }
}

impl Eq for MultiHash {}
impl PartialEq for MultiHash {
    fn eq(&self, other: &MultiHash) -> bool {
        match (self, other) {
            (&Sha1(ref left, l1), &Sha1(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Sha2_256(ref left, l1), &Sha2_256(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Sha2_512(ref left, l1), &Sha2_512(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Sha3_224(ref left, l1), &Sha3_224(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Sha3_256(ref left, l1), &Sha3_256(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Sha3_384(ref left, l1), &Sha3_384(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Sha3_512(ref left, l1), &Sha3_512(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Shake128(ref left, l1), &Shake128(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Shake256(ref left, l1), &Shake256(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Blake2B(ref left, l1), &Blake2B(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (&Blake2S(ref left, l1), &Blake2S(ref right, l2)) => l1 == l2 && left[..l1] == right[..l2],
            (
                &ApplicationSpecific { code: left_code, bytes: ref left },
                &ApplicationSpecific { code: right_code, bytes: ref right }
            ) => left_code == right_code && left == right,
            _ => false,
        }
    }
}

#[cfg(test)]
mod tests {
    use MultiHash;

    #[test]
    fn to_bytes() {
        let multihash = MultiHash::Sha1([
            0xde, 0xad, 0xbe, 0xef,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
        ], 4);
        assert_eq!(
            multihash.to_bytes(),
            vec![0x11, 0x04, 0xde, 0xad, 0xbe, 0xef]);
    }

    #[test]
    fn from_bytes() {
        let multihash = MultiHash::Sha1([
            0xde, 0xad, 0xbe, 0xef,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
        ], 4);
        assert_eq!(
            Ok(multihash),
            MultiHash::from_bytes([0x11, 0x04, 0xde, 0xad, 0xbe, 0xef]));
    }
}
<|endoftext|>


<commit_before>
use std::string;
use std::iter;
use std::ascii::AsciiExt;

static STANDARD_CHARS: &'static[u8] = b"abcdefghijklmnopqrstuvwxyz234567";

pub fn encode(b: &[u8]) -> String {
    let mut out = Vec::new();
    let mut n: u64 = 0;

    for i in 0 .. b.len() {
        // Calculate the shift (32, 24, 16, 8, 0)
        let shift = 8 * (4 - (i % 5));
        n |= (b[i] as u64) << shift;

        // If the shift was zero, or this is the last character of input, extract
        // each 5-bit group from n.
        if shift == 0 || (i == b.len()-1) {
            // Determine number of output groups, based on the shift
            let groups = match shift {
                32 => 2,
                24 => 4,
                16 => 5,
                8  => 7,
                _  => 8
            };

            // Pull out each 5-bit index
            for j in iter::range_step(35, (35 - (groups * 5)), -5) {
                let ndx = (n >> j as u32) & 31;
                out.push(STANDARD_CHARS[ndx as usize]);
            }

            // Reset n
            n = 0;
        }
    }

    let result = match String::from_utf8(out) {
        Ok(s) => s,
        Err(E) => panic!(E)
    };
    result
}

pub fn decode(b: &[u8]) -> Vec<u8> {
    let mut out: Vec<u8> = Vec::new();
    let mut n: u64 = 0;

    for i in range(0, b.len()) {
        // Use the character to generate an index
        let c = b[i];
        let idx = match c as char {
            'A' ... 'Z' => c - 65, // A..Z => 65..90
            'a' ... 'z' => c - 97, // a..z => 97..122
            _ => 26 + (c - 50)     // 2..7 => 50..55
        };

        // Calculate the shift for this 5-bit group (35, 25, ..., 0)
        let shift = 35 - (5 * (i % 8));
        n |= (idx as u64 & 31) << shift;

        // If the shift is zero or this is the last character of input, extract
        // each 8-bit group from n.
        if shift == 0 || (i == b.len()-1) {
            // Determine number of output groups, based on shift
            let groups = match shift {
                35 => 0,
                30 => 1,
                25 => 2,
                20 => 2,
                15 => 3,
                10 => 4,
                5  => 4,
                _  => 5
            };

            // Pull out each 8-bit group
            for j in iter::range_step(32, (32 - (groups * 8)), -8) {
                let v = ((n >> j as u8) & 255) as u8;
                out.push(v);
            }

            // Reset n
            n = 0;
        }
    }

    out
}

macro_rules! check_encode(
    ($input:expr, $expected:expr) => ( {
        let x: Result<String, string::FromUtf8Error> = encode($input.as_bytes());
        assert_eq!(x.is_ok(), true);
        assert!(x.unwrap().eq_ignore_ascii_case($expected));
    });
    );

macro_rules! check_decode(
    ($expected:expr, $input:expr) => (
        assert_eq!($expected.as_bytes(), decode($input.as_bytes()));
        );
);

#[test]
fn encode_tests() {
    check_encode!("", "");
    check_encode!("f", "MY");
    check_encode!("foo", "MZXw6");
    check_encode!("foob", "MZXW6YQ");
    check_encode!("fooba", "MZXW6YTB");
    check_encode!("foobar", "MZXW6YTBOI");
}

#[test]
fn decode_tests() {
    check_decode!("", "");
    check_decode!("f", "MY");
    check_decode!("foo", "MZXW6");
    check_decode!("foob", "MZxw6YQ");
    check_decode!("fooba", "MZXW6YTB");
    check_decode!("foobar", "MZXW6YTBOI");
}

<commit_msg>Fix broken test<commit_after>
use std::iter;
use std::ascii::AsciiExt;

static STANDARD_CHARS: &'static[u8] = b"abcdefghijklmnopqrstuvwxyz234567";

pub fn encode(b: &[u8]) -> String {
    let mut out = Vec::new();
    let mut n: u64 = 0;

    for i in 0 .. b.len() {
        // Calculate the shift (32, 24, 16, 8, 0)
        let shift = 8 * (4 - (i % 5));
        n |= (b[i] as u64) << shift;

        // If the shift was zero, or this is the last character of input, extract
        // each 5-bit group from n.
        if shift == 0 || (i == b.len()-1) {
            // Determine number of output groups, based on the shift
            let groups = match shift {
                32 => 2,
                24 => 4,
                16 => 5,
                8  => 7,
                _  => 8
            };

            // Pull out each 5-bit index
            for j in iter::range_step(35, (35 - (groups * 5)), -5) {
                let ndx = (n >> j as u32) & 31;
                out.push(STANDARD_CHARS[ndx as usize]);
            }

            // Reset n
            n = 0;
        }
    }

    let result = match String::from_utf8(out) {
        Ok(s) => s,
        Err(e) => panic!(e)
    };
    result
}

pub fn decode(b: &[u8]) -> Vec<u8> {
    let mut out: Vec<u8> = Vec::new();
    let mut n: u64 = 0;

    for i in range(0, b.len()) {
        // Use the character to generate an index
        let c = b[i];
        let idx = match c as char {
            'A' ... 'Z' => c - 65, // A..Z => 65..90
            'a' ... 'z' => c - 97, // a..z => 97..122
            _ => 26 + (c - 50)     // 2..7 => 50..55
        };

        // Calculate the shift for this 5-bit group (35, 25, ..., 0)
        let shift = 35 - (5 * (i % 8));
        n |= (idx as u64 & 31) << shift;

        // If the shift is zero or this is the last character of input, extract
        // each 8-bit group from n.
        if shift == 0 || (i == b.len()-1) {
            // Determine number of output groups, based on shift
            let groups = match shift {
                35 => 0,
                30 => 1,
                25 => 2,
                20 => 2,
                15 => 3,
                10 => 4,
                5  => 4,
                _  => 5
            };

            // Pull out each 8-bit group
            for j in iter::range_step(32, (32 - (groups * 8)), -8) {
                let v = ((n >> j as u8) & 255) as u8;
                out.push(v);
            }

            // Reset n
            n = 0;
        }
    }

    out
}

macro_rules! check_encode(
    ($input:expr, $expected:expr) => ( {
        let x = encode($input.as_bytes());
        assert!(x.eq_ignore_ascii_case($expected));
    });
    );

macro_rules! check_decode(
    ($expected:expr, $input:expr) => (
        assert_eq!($expected.as_bytes(), decode($input.as_bytes()));
        );
);

#[test]
fn encode_tests() {
    check_encode!("", "");
    check_encode!("f", "MY");
    check_encode!("foo", "MZXw6");
    check_encode!("foob", "MZXW6YQ");
    check_encode!("fooba", "MZXW6YTB");
    check_encode!("foobar", "MZXW6YTBOI");
}

#[test]
fn decode_tests() {
    check_decode!("", "");
    check_decode!("f", "MY");
    check_decode!("foo", "MZXW6");
    check_decode!("foob", "MZxw6YQ");
    check_decode!("fooba", "MZXW6YTB");
    check_decode!("foobar", "MZXW6YTBOI");
}

<|endoftext|>