<commit_before>/// Filters operating on string
use std::collections::HashMap;

use serde_json::value::{Value, to_value};

use errors::{TeraResult, TeraError};

/// Convert a value to uppercase.
pub fn upper(value: Value, _: HashMap<String, Value>) -> TeraResult<Value> {
    let s = try_get_value!("upper", "value", String, value);

    Ok(to_value(&s.to_uppercase()))
}

/// Convert a value to lowercase.
pub fn lower(value: Value, _: HashMap<String, Value>) -> TeraResult<Value> {
    let s = try_get_value!("lower", "value", String, value);

    Ok(to_value(&s.to_lowercase()))
}

/// Strip leading and trailing whitespace.
pub fn trim(value: Value, _: HashMap<String, Value>) -> TeraResult<Value> {
    let s = try_get_value!("trim", "value", String, value);

    Ok(to_value(&s.trim()))
}

/// Truncates a string to the indicated length
pub fn truncate(value: Value, args: HashMap<String, Value>) -> TeraResult<Value> {
    let s = try_get_value!("truncate", "value", String, value);
    let length = match args.get("length") {
        Some(l) => try_get_value!("truncate", "length", usize, l.clone()),
        None => 255
    };

    // Nothing to truncate?
    if length > s.len() {
        return Ok(to_value(&s));
    }

    let result = s[..s.char_indices().nth(length).unwrap().0].to_string() + "…";
    Ok(to_value(&result))
}

/// Gets the number of words in a string.
pub fn wordcount(value: Value, _: HashMap<String, Value>) -> TeraResult<Value> {
    let s = try_get_value!("wordcount", "value", String, value);

    Ok(to_value(&s.split_whitespace().count()))
}

/// Replaces given `from` substring with `to` string.
pub fn replace(value: Value, args: HashMap<String, Value>) -> TeraResult<Value> {
    let s = try_get_value!("replace", "value", String, value);

    let from = match args.get("from") {
        Some(val) => try_get_value!("replace", "from", String, val.clone()),
        None => {
            return Err(TeraError::FilterMissingArg("replace".to_string(), "from".to_string()));
        }
    };

    let to = match args.get("to") {
        Some(val) => try_get_value!("replace", "to", String, val.clone()),
        None => {
            return Err(TeraError::FilterMissingArg("replace".to_string(), "to".to_string()));
        }
    };

    Ok(to_value(&s.replace(&from, &to)))
}

/// First letter of the string is uppercase rest is lowercase
pub fn capitalize(value: Value, _: HashMap<String, Value>) -> TeraResult<Value> {
    let s = try_get_value!("capitalize", "value", String, value);
    let mut chars = s.chars();
    match chars.next() {
        None => Ok(to_value("")),
        Some(f) => {
            let res = f.to_uppercase().collect::<String>() + &chars.as_str().to_lowercase();
            Ok(to_value(&res))
        }
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;

    use serde_json::value::{to_value};

    use errors::TeraError::*;

    use super::*;

    #[test]
    fn test_upper() {
        let result = upper(to_value("hello"), HashMap::new());
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("HELLO"));
    }

    #[test]
    fn test_upper_error() {
        let result = upper(to_value(&50), HashMap::new());
        assert!(result.is_err());
        assert_eq!(
            result.err().unwrap(),
            FilterIncorrectArgType("upper".to_string(), "value".to_string(), to_value(&50), "String".to_string())
        );
    }

    #[test]
    fn test_trim() {
        let result = trim(to_value("  hello  "), HashMap::new());
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("hello"));
    }

    #[test]
    fn test_truncate_smaller_than_length() {
        let mut args = HashMap::new();
        args.insert("length".to_string(), to_value(&255));
        let result = truncate(to_value("hello"), args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("hello"));
    }

    #[test]
    fn test_truncate_when_required() {
        let mut args = HashMap::new();
        args.insert("length".to_string(), to_value(&2));
        let result = truncate(to_value("日本語"), args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("日本…"));
    }

    #[test]
    fn test_lower() {
        let result = lower(to_value("HELLO"), HashMap::new());
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("hello"));
    }

    #[test]
    fn test_wordcount() {
        let result = wordcount(to_value("Joel is a slug"), HashMap::new());
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value(&4));
    }

    #[test]
    fn test_replace() {
        let mut args = HashMap::new();
        args.insert("from".to_string(), to_value(&"Hello"));
        args.insert("to".to_string(), to_value(&"Goodbye"));
        let result = replace(to_value(&"Hello world!"), args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("Goodbye world!"));
    }

    #[test]
    fn test_replace_missing_arg() {
        let mut args = HashMap::new();
        args.insert("from".to_string(), to_value(&"Hello"));
        let result = replace(to_value(&"Hello world!"), args);
        assert!(result.is_err());
        assert_eq!(
            result.err().unwrap(),
            FilterMissingArg("replace".to_string(), "to".to_string())
        );
    }

    #[test]
    fn test_capitalize() {
        let tests = vec![
            ("CAPITAL IZE", "Capital ize"),
            ("capital ize", "Capital ize"),
        ];
        for (input, expected) in tests {
            let result = capitalize(to_value(input), HashMap::new());
            assert!(result.is_ok());
            assert_eq!(result.unwrap(), to_value(expected));
        }
    }
}
<commit_msg>Addslashes filter implemented (#52)<commit_after>/// Filters operating on string
use std::collections::HashMap;

use serde_json::value::{Value, to_value};

use errors::{TeraResult, TeraError};

/// Convert a value to uppercase.
pub fn upper(value: Value, _: HashMap<String, Value>) -> TeraResult<Value> {
    let s = try_get_value!("upper", "value", String, value);

    Ok(to_value(&s.to_uppercase()))
}

/// Convert a value to lowercase.
pub fn lower(value: Value, _: HashMap<String, Value>) -> TeraResult<Value> {
    let s = try_get_value!("lower", "value", String, value);

    Ok(to_value(&s.to_lowercase()))
}

/// Strip leading and trailing whitespace.
pub fn trim(value: Value, _: HashMap<String, Value>) -> TeraResult<Value> {
    let s = try_get_value!("trim", "value", String, value);

    Ok(to_value(&s.trim()))
}

/// Truncates a string to the indicated length
pub fn truncate(value: Value, args: HashMap<String, Value>) -> TeraResult<Value> {
    let s = try_get_value!("truncate", "value", String, value);
    let length = match args.get("length") {
        Some(l) => try_get_value!("truncate", "length", usize, l.clone()),
        None => 255
    };

    // Nothing to truncate?
    if length > s.len() {
        return Ok(to_value(&s));
    }

    let result = s[..s.char_indices().nth(length).unwrap().0].to_string() + "…";
    Ok(to_value(&result))
}

/// Gets the number of words in a string.
pub fn wordcount(value: Value, _: HashMap<String, Value>) -> TeraResult<Value> {
    let s = try_get_value!("wordcount", "value", String, value);

    Ok(to_value(&s.split_whitespace().count()))
}

/// Replaces given `from` substring with `to` string.
pub fn replace(value: Value, args: HashMap<String, Value>) -> TeraResult<Value> {
    let s = try_get_value!("replace", "value", String, value);

    let from = match args.get("from") {
        Some(val) => try_get_value!("replace", "from", String, val.clone()),
        None => {
            return Err(TeraError::FilterMissingArg("replace".to_string(), "from".to_string()));
        }
    };

    let to = match args.get("to") {
        Some(val) => try_get_value!("replace", "to", String, val.clone()),
        None => {
            return Err(TeraError::FilterMissingArg("replace".to_string(), "to".to_string()));
        }
    };

    Ok(to_value(&s.replace(&from, &to)))
}

/// First letter of the string is uppercase rest is lowercase
pub fn capitalize(value: Value, _: HashMap<String, Value>) -> TeraResult<Value> {
    let s = try_get_value!("capitalize", "value", String, value);
    let mut chars = s.chars();
    match chars.next() {
        None => Ok(to_value("")),
        Some(f) => {
            let res = f.to_uppercase().collect::<String>() + &chars.as_str().to_lowercase();
            Ok(to_value(&res))
        }
    }
}

/// Escapes quote chracters
pub fn addslashes(value: Value, _: HashMap<String, Value>) -> TeraResult<Value> {
    let s = try_get_value!("addslashes", "value", String, value);
    let result = s.replace("\\","\\\\").replace("\"", "\\\"");
    Ok(to_value(&result.replace("\'", "\\\'")))

}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;

    use serde_json::value::{to_value};

    use errors::TeraError::*;

    use super::*;

    #[test]
    fn test_upper() {
        let result = upper(to_value("hello"), HashMap::new());
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("HELLO"));
    }

    #[test]
    fn test_upper_error() {
        let result = upper(to_value(&50), HashMap::new());
        assert!(result.is_err());
        assert_eq!(
            result.err().unwrap(),
            FilterIncorrectArgType("upper".to_string(), "value".to_string(), to_value(&50), "String".to_string())
        );
    }

    #[test]
    fn test_trim() {
        let result = trim(to_value("  hello  "), HashMap::new());
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("hello"));
    }

    #[test]
    fn test_truncate_smaller_than_length() {
        let mut args = HashMap::new();
        args.insert("length".to_string(), to_value(&255));
        let result = truncate(to_value("hello"), args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("hello"));
    }

    #[test]
    fn test_truncate_when_required() {
        let mut args = HashMap::new();
        args.insert("length".to_string(), to_value(&2));
        let result = truncate(to_value("日本語"), args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("日本…"));
    }

    #[test]
    fn test_lower() {
        let result = lower(to_value("HELLO"), HashMap::new());
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("hello"));
    }

    #[test]
    fn test_wordcount() {
        let result = wordcount(to_value("Joel is a slug"), HashMap::new());
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value(&4));
    }

    #[test]
    fn test_replace() {
        let mut args = HashMap::new();
        args.insert("from".to_string(), to_value(&"Hello"));
        args.insert("to".to_string(), to_value(&"Goodbye"));
        let result = replace(to_value(&"Hello world!"), args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("Goodbye world!"));
    }

    #[test]
    fn test_replace_missing_arg() {
        let mut args = HashMap::new();
        args.insert("from".to_string(), to_value(&"Hello"));
        let result = replace(to_value(&"Hello world!"), args);
        assert!(result.is_err());
        assert_eq!(
            result.err().unwrap(),
            FilterMissingArg("replace".to_string(), "to".to_string())
        );
    }

    #[test]
    fn test_capitalize() {
        let tests = vec![
            ("CAPITAL IZE", "Capital ize"),
            ("capital ize", "Capital ize"),
        ];
        for (input, expected) in tests {
            let result = capitalize(to_value(input), HashMap::new());
            assert!(result.is_ok());
            assert_eq!(result.unwrap(), to_value(expected));
        }
    }

    #[test]
    fn test_addslashes() {
        let tests = vec![
            (r#"I'm so happy"#, r#"I\'m so happy"#),
            (r#"Let "me" help you"#, r#"Let \"me\" help you"#),
            (r#"<a>'"#, r#"<a>\'"#),
            (r#""double quotes" and \'single quotes\'"#, r#"\"double quotes\" and \\\'single quotes\\\'"#),
            (r#"\ : backslashes too"#, r#"\\ : backslashes too"#)
        ];
        for (input, expected) in tests {
            let result = addslashes(to_value(input), HashMap::new());
            assert!(result.is_ok());
            assert_eq!(result.unwrap(), to_value(expected));
        }
    }
}
<|endoftext|>


<commit_before>extern crate direct2d;

use direct2d::Factory;
use direct2d::geometry::{Geometry, FillMode};
use direct2d::math::*;

const EPSILON: f32 = 0.0001;

#[test]
fn rectangle_area() {
    let factory = Factory::create().unwrap();

    let rect = RectF::new(0.0, 0.0, 1.0, 1.0);
    let rectangle = factory.create_rectangle_geometry(&rect).unwrap();

    let area = rectangle.compute_area(None).unwrap();
    assert!((area - 1.0).abs() <= EPSILON);
}

#[test]
fn combined_area() {
    let factory = Factory::create().unwrap();

    let rect1 = RectF::new(0.0, 0.0, 1.0, 1.0);
    let rectangle1 = factory.create_rectangle_geometry(&rect1).unwrap();

    let rect2 = RectF::new(0.0, 1.0, 1.0, 2.0);
    let rectangle2 = factory.create_rectangle_geometry(&rect2).unwrap();

    let combined = factory.create_geometry_group(FillMode::Winding, &[&rectangle1, &rectangle2]).unwrap();

    let area = combined.compute_area(None).unwrap();
    assert!((area - 2.0).abs() <= EPSILON);
}

<commit_msg>Length test too!<commit_after>extern crate direct2d;

use direct2d::Factory;
use direct2d::geometry::{Geometry, FillMode};
use direct2d::math::*;

const EPSILON: f32 = 0.0001;

#[test]
fn rectangle_area() {
    let factory = Factory::create().unwrap();

    let rect = RectF::new(0.0, 0.0, 1.0, 1.0);
    let rectangle = factory.create_rectangle_geometry(&rect).unwrap();

    let area = rectangle.compute_area(None).unwrap();
    assert!((area - 1.0).abs() <= EPSILON);
}

#[test]
fn rectangle_length() {
    let factory = Factory::create().unwrap();

    let rect = RectF::new(0.0, 0.0, 1.0, 1.0);
    let rectangle = factory.create_rectangle_geometry(&rect).unwrap();

    let area = rectangle.compute_length(None).unwrap();
    assert!((area - 4.0).abs() <= EPSILON);
}

#[test]
fn combined_area() {
    let factory = Factory::create().unwrap();

    let rect1 = RectF::new(0.0, 0.0, 1.0, 1.0);
    let rectangle1 = factory.create_rectangle_geometry(&rect1).unwrap();

    let rect2 = RectF::new(0.0, 1.0, 1.0, 2.0);
    let rectangle2 = factory.create_rectangle_geometry(&rect2).unwrap();

    let combined = factory.create_geometry_group(FillMode::Winding, &[&rectangle1, &rectangle2]).unwrap();

    let area = combined.compute_area(None).unwrap();
    assert!((area - 2.0).abs() <= EPSILON);
}

<|endoftext|>


<commit_before>
use serialize::json::{JsonObject, ToJson};
use regex::{Regex, Captures};

static MATCHER: Regex = regex!(r":([a-z][a-z_]*)");

pub struct Path {
    regex: Regex,
    pub path: String,
    pub params: Vec<String>
}

impl Path {

    pub fn apply_captures(&self, jobj: &mut JsonObject, captures: Captures) {
        for param in self.params.iter() {
            jobj.insert(param.clone(), captures.name(param.as_slice()).to_string().to_json());
        }
    }

    pub fn is_match<'a>(&'a self, path: &'a str) -> Option<Captures> {
        match self.regex.captures(path) {
            Some(captures) => Some(captures),
            None => None
        }
    }

    pub fn parse(path: &str, endpoint: bool) -> Result<Path,String> {
        let mut regex_body = "^/".to_string() + Path::sub_regex(path);

        if endpoint {
            regex_body = regex_body + "$";
        }

        let regex = match Regex::new(regex_body.as_slice()) {
            Ok(re) => re,
            Err(err) => return Err(format!("{}", err))
        };

        let mut params = vec![];
        for capture in MATCHER.captures_iter(path) {
            params.push(capture.at(1).to_string());
        }

        Ok(Path {
            path: path.to_string(),
            params: params,
            regex: regex
        })
    }

    fn sub_regex(path: &str) -> String {
        return MATCHER.replace_all(path, "(?P<$1>[^/?&]+)");
    }

}

#[test]
fn sub_regex() {
    let res = Path::sub_regex(":user_id/messages/:message_id");
    assert_eq!(res.as_slice(), "(?P<user_id>[^/?&]+)/messages/(?P<message_id>[^/?&]+)")
}

#[test]
fn parse_and_match() {
    let path = Path::parse(":user_id/messages/:message_id", true).unwrap();
    assert!(match path.is_match("/1920/messages/100500") {
        Some(captures) => {
            captures.name("user_id") == "1920" &&
            captures.name("message_id") == "100500"
        }
        None => false
    });
    assert!(match path.is_match("/1920/messages/not_match/100500") {
        Some(_) => false,
        None => true
    });
}

// #[test]
// fn parse_and_match_root() {
//     let path = Path::parse("", true).unwrap();
//     assert!(match path.is_match("/") {
//         Some(captures) => captures.at(0) == "",
//         None => false
//     });
// }

#[test]
fn parse_and_match_single_val() {
    let path = Path::parse(":id", true).unwrap();
    assert!(match path.is_match("/550e8400-e29b-41d4-a716-446655440000") {
        Some(captures) => captures.name("id") == "550e8400-e29b-41d4-a716-446655440000",
        None => false
    });
}<commit_msg>test: fix commented spec<commit_after>
use serialize::json::{JsonObject, ToJson};
use regex::{Regex, Captures};

static MATCHER: Regex = regex!(r":([a-z][a-z_]*)");

pub struct Path {
    regex: Regex,
    pub path: String,
    pub params: Vec<String>
}

impl Path {

    pub fn apply_captures(&self, jobj: &mut JsonObject, captures: Captures) {
        for param in self.params.iter() {
            jobj.insert(param.clone(), captures.name(param.as_slice()).to_string().to_json());
        }
    }

    pub fn is_match<'a>(&'a self, path: &'a str) -> Option<Captures> {
        match self.regex.captures(path) {
            Some(captures) => Some(captures),
            None => None
        }
    }

    pub fn parse(path: &str, endpoint: bool) -> Result<Path,String> {
        let mut regex_body = "^/".to_string() + Path::sub_regex(path);

        if endpoint {
            regex_body = regex_body + "$";
        }

        let regex = match Regex::new(regex_body.as_slice()) {
            Ok(re) => re,
            Err(err) => return Err(format!("{}", err))
        };

        let mut params = vec![];
        for capture in MATCHER.captures_iter(path) {
            params.push(capture.at(1).to_string());
        }

        Ok(Path {
            path: path.to_string(),
            params: params,
            regex: regex
        })
    }

    fn sub_regex(path: &str) -> String {
        return MATCHER.replace_all(path, "(?P<$1>[^/?&]+)");
    }

}

#[test]
fn sub_regex() {
    let res = Path::sub_regex(":user_id/messages/:message_id");
    assert_eq!(res.as_slice(), "(?P<user_id>[^/?&]+)/messages/(?P<message_id>[^/?&]+)")
}

#[test]
fn parse_and_match() {
    let path = Path::parse(":user_id/messages/:message_id", true).unwrap();
    assert!(match path.is_match("/1920/messages/100500") {
        Some(captures) => {
            captures.name("user_id") == "1920" &&
            captures.name("message_id") == "100500"
        }
        None => false
    });
    assert!(match path.is_match("/1920/messages/not_match/100500") {
        Some(_) => false,
        None => true
    });
}

#[test]
fn parse_and_match_root() {
    let path = Path::parse("", true).unwrap();
    assert!(match path.is_match("/") {
        Some(captures) => captures.at(0) == "/",
        None => false
    });
}

#[test]
fn parse_and_match_single_val() {
    let path = Path::parse(":id", true).unwrap();
    assert!(match path.is_match("/550e8400-e29b-41d4-a716-446655440000") {
        Some(captures) => captures.name("id") == "550e8400-e29b-41d4-a716-446655440000",
        None => false
    });
}<|endoftext|>


<commit_before>use num_traits;
pub use num_traits::Float;

/// Casts a literal f64 to an appropriate `Float` value
#[inline]
pub fn f<F: Float>(x: f64) -> F {
    num_traits::cast(x).expect("cast failed, are you using non f32,f64 types?")
}

/// Macro for defining constants of generic Float type, reduces boiler plate when `f(1.23)` usage
/// isn't enough and the compiler needs explicit type, ie f::<F>(1.23). Such cases we can improve
/// equation readability by using constants like `_1_23`
///
/// `cast_constants!(F; _1_23=1.23, _10=10);` is equivalent to
/// ```
/// let _1_23: F = f(1.23);
/// let _10: F = f(10 as f64);
/// ```
macro_rules! cast_constants {
    ($t:ty; $( $name:ident=$val:expr ),+) => {
        $(
            let $name: $t = f($val as f64);
        )+
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn float_casting() {
        type F1 = f64;
        type F2 = f32;

        let root2: f64 = 2.0.sqrt();
        let root2_f1: F1 = f(root2);
        assert_relative_eq!(root2_f1, root2);

        let root2_f2: F2 = f(root2);
        assert_relative_eq!(root2_f2, root2 as F2);
    }

    #[test]
    fn cast_constants_macro() {
        type F = f64;
        cast_constants!(F; _1_234=1.234, _234=234);

        assert_relative_eq!(_1_234, 1.234);
        assert_relative_eq!(_234, 234.0);
    }
}
<commit_msg>Use F::from(x) over num_traits::cast(x)<commit_after>pub use num_traits::Float;

/// Casts a literal f64 to an appropriate `Float` value
#[inline]
pub fn f<F: Float>(x: f64) -> F {
    F::from(x).expect("cast failed, are you using non f32,f64 types?")
}

/// Macro for defining constants of generic Float type, reduces boiler plate when `f(1.23)` usage
/// isn't enough and the compiler needs explicit type, ie f::<F>(1.23). Such cases we can improve
/// equation readability by using constants like `_1_23`
///
/// `cast_constants!(F; _1_23=1.23, _10=10);` is equivalent to
/// ```
/// let _1_23: F = f(1.23);
/// let _10: F = f(10 as f64);
/// ```
macro_rules! cast_constants {
    ($t:ty; $( $name:ident=$val:expr ),+) => {
        $(
            let $name: $t = f($val as f64);
        )+
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn float_casting() {
        type F1 = f64;
        type F2 = f32;

        let root2: f64 = 2.0.sqrt();
        let root2_f1: F1 = f(root2);
        assert_relative_eq!(root2_f1, root2);

        let root2_f2: F2 = f(root2);
        assert_relative_eq!(root2_f2, root2 as F2);
    }

    #[test]
    fn cast_constants_macro() {
        type F = f64;
        cast_constants!(F; _1_234=1.234, _234=234);

        assert_relative_eq!(_1_234, 1.234);
        assert_relative_eq!(_234, 234.0);
    }
}
<|endoftext|>


<commit_before>use std::path;
use std::fs;
use std::io::{Read, Write};
use bincode::{self, SizeLimit};
use game::*;

const SAVE_FILE: &'static str = "save";

pub fn save(user_path: &path::Path, game_state: GameState) -> GameState {
    let serializable = SerializableGameState::from(game_state);

    let encoded = bincode::serialize(&serializable, SizeLimit::Infinite).expect("Failed to serialize game state");

    fs::File::create(user_path.join(SAVE_FILE))
        .and_then(|mut f| f.write_all(&encoded))
        .expect("Failed to save game");

    GameState::from(serializable)
}

pub fn load(user_path: &path::Path) -> Option<GameState> {
    if let Ok(mut f) = fs::File::open(user_path.join(SAVE_FILE)) {
        let mut encoded = Vec::new();
        f.read_to_end(&mut encoded).expect("Failed to read save file");
        let serializable: SerializableGameState = bincode::deserialize(&encoded).expect("Failed to parse save file");
        Some(GameState::from(serializable))
    } else {
        None
    }
}

pub fn delete(user_path: &path::Path) -> bool {
    fs::remove_file(user_path.join(SAVE_FILE)).is_ok()
}
<commit_msg>Refactor save_file to use AsRef<commit_after>use std::path::Path;
use std::fs::{self, File};
use std::io::{Read, Write};
use bincode::{self, SizeLimit};
use game::*;

const SAVE_FILE: &'static str = "save";

pub fn save<P: AsRef<Path>>(user_path: P, game_state: GameState) -> GameState {
    let serializable = SerializableGameState::from(game_state);

    let encoded = bincode::serialize(&serializable, SizeLimit::Infinite).expect("Failed to serialize game state");

    File::create(user_path.as_ref().join(SAVE_FILE))
        .and_then(|mut f| f.write_all(&encoded))
        .expect("Failed to save game");

    GameState::from(serializable)
}

pub fn load<P: AsRef<Path>>(user_path: P) -> Option<GameState> {
    if let Ok(mut f) = File::open(user_path.as_ref().join(SAVE_FILE)) {
        let mut encoded = Vec::new();
        f.read_to_end(&mut encoded).expect("Failed to read save file");
        let serializable: SerializableGameState = bincode::deserialize(&encoded).expect("Failed to parse save file");
        Some(GameState::from(serializable))
    } else {
        None
    }
}

pub fn delete<P: AsRef<Path>>(user_path: P) -> bool {
    fs::remove_file(user_path.as_ref().join(SAVE_FILE)).is_ok()
}
<|endoftext|>


<commit_before>use std::i64;

use super::number::NumberOps;
use super::point::Point;
use super::ring::Ring;

pub const HALF_MAX_ERR: i64  = i64::MAX / 2;

#[inline]
pub fn h_multi_intersect(p1: Point, p2: Point, step_y: i64, inters: &mut Ring<i64>) {
   let (p1, p2) = if p1.y > p2.y {
      (p2, p1)
   } else {
      (p1, p2)
   };

   let start = 1 + p1.y / step_y;
   let end = 1 + (p2.y - 1) / step_y;

   for i in start..end {
      let x = h_intersect(p1, p2, i * step_y);
      inters.push(x);
   }
}

#[inline]
pub fn v_multi_intersect(p1: Point, p2: Point, step_x: i64, inters: &mut Ring<i64>) {
   let (p1, p2) = if p1.x > p2.x {
      (p2, p1)
   } else {
      (p1, p2)
   };

   let start = 1 + p1.x / step_x;
   let end = 1 + (p2.x - 1) / step_x;

   for i in start..end {
      let y = v_intersect(p1, p2, i * step_x);
      inters.push(y);
   }
}

#[inline]
pub fn h_multi_intersect_fast(p1: Point, p2: Point, step_y: i64, inters: &mut Ring<i64>) -> i64 {
   let (p1, p2) = if p1.y > p2.y {
      (p2, p1)
   } else {
      (p1, p2)
   };

   let start = 1 + p1.y / step_y;
   let end = 1 + (p2.y - 1) / step_y;

   let dy = p2.y - p1.y;
   let dx = p2.x - p1.x;
   let dx_signum = dx.signum();

   let step_x = dx * step_y / dy;

   let max_div_dy = i64::MAX / dy;

   let err_step = max_div_dy * (step_y * dx * dx_signum - step_x * dx_signum * dy);

   let first_y = start * step_y;

   let fdy = first_y - p1.y;
   let fdx = dx * fdy / dy;

   let mut x = p1.x + fdx;

   if err_step == 0 {
      for _ in start..end {
         inters.push(x);

         x += step_x;
      }

      return first_y;
   }

   let mut err = max_div_dy * (fdy * dx * dx_signum - fdx * dx_signum * dy) - HALF_MAX_ERR;

   for _ in start..end {
      if err > 0 {
         x += dx_signum;
         err -= i64::MAX;
      }

      inters.push(x);

      x += step_x;

      err += err_step;
   }

   first_y
}

#[inline]
pub fn v_multi_intersect_fast(p1: Point, p2: Point, step_x: i64, inters: &mut Ring<i64>) -> i64 {
   let (p1, p2) = if p1.x > p2.x {
      (p2, p1)
   } else {
      (p1, p2)
   };

   let start = 1 + p1.x / step_x;
   let end = 1 + (p2.x - 1) / step_x;

   let dx = p2.x - p1.x;
   let dy = p2.y - p1.y;
   let dy_signum = dy.signum();

   let step_y = dy * step_x / dx;

   let max_div_dx = i64::MAX / dx;

   let err_step = max_div_dx * (step_x * dy * dy_signum - step_y * dy_signum * dx);

   let first_x = start * step_x;

   let fdx = first_x - p1.x;
   let fdy = dy * fdx / dx;

   let mut y = p1.y + fdy;

   if err_step == 0 {
      for _ in start..end {
         inters.push(y);

         y += step_y;
      }

      return first_x;
   }

   let mut err = max_div_dx * (fdx * dy * dy_signum - fdy * dy_signum * dx) - HALF_MAX_ERR;

   for _ in start..end {
      if err > 0 {
         y += dy_signum;
         err -= i64::MAX;
      }

      inters.push(y);

      y += step_y;

      err += err_step;
   }

   first_x
}

#[inline]
fn h_intersect(p1: Point, p2: Point, y: i64) -> i64 {
   p1.x + ((p2.x - p1.x) * (y - p1.y)).rounding_div(p2.y - p1.y)
}

#[inline]
fn v_intersect(p1: Point, p2: Point, x: i64) -> i64 {
   p1.y + ((p2.y - p1.y) * (x - p1.x)).rounding_div(p2.x - p1.x)
}

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

   use super::super::point::Point;
   use super::super::ring::Ring;

   use super::*;

   #[test]
   fn test_correct_h() {
      let mut inters = Ring::new(100_000);
      let mut inters_fast = Ring::new(100_000);
      let p1 = Point::new(0, 0);
      let p2 = Point::new(500_000, 2_000_000);

      h_multi_intersect(p1, p2, 1000, &mut inters);
      h_multi_intersect_fast(p1, p2, 1000, &mut inters_fast);

      for (correct, fast) in inters[..].iter().zip(inters_fast[..].iter()) {
         assert_eq!(correct, fast);
      }
   }

   #[test]
   fn test_correct_h_rev() {
      let mut inters = Ring::new(100_000);
      let mut inters_fast = Ring::new(100_000);
      let p1 = Point::new(500_000, 0);
      let p2 = Point::new(0, 2_000_000);

      h_multi_intersect(p1, p2, 1000, &mut inters);
      h_multi_intersect_fast(p1, p2, 1000, &mut inters_fast);

      for (correct, fast) in inters[..].iter().zip(inters_fast[..].iter()) {
         assert_eq!(correct, fast);
      }
   }

   #[test]
   fn test_correct_v() {
      let mut inters = Ring::new(100_000);
      let mut inters_fast = Ring::new(100_000);
      let p1 = Point::new(0, 0);
      let p2 = Point::new(500_000, 2_000_000);

      v_multi_intersect(p1, p2, 1000, &mut inters);
      v_multi_intersect_fast(p1, p2, 1000, &mut inters_fast);

      for (correct, fast) in inters[..].iter().zip(inters_fast[..].iter()) {
         assert_eq!(correct, fast);
      }
   }

   #[test]
   fn test_correct_v_rev() {
      let mut inters = Ring::new(100_000);
      let mut inters_fast = Ring::new(100_000);
      let p1 = Point::new(500_000, 0);
      let p2 = Point::new(0, 2_000_000);

      v_multi_intersect(p1, p2, 1000, &mut inters);
      v_multi_intersect_fast(p1, p2, 1000, &mut inters_fast);

      for (correct, fast) in inters[..].iter().zip(inters_fast[..].iter()) {
         assert_eq!(correct, fast);
      }
   }

   #[bench]
   fn bench_lineinter(b: &mut Bencher) {
      let mut inters = Ring::new(100_000);
      let p1 = Point::new(0, 0);
      let p2 = Point::new(500_000, 2_000_000);

      b.iter(|| {
         for _ in 0..1000 {
            inters.clear();
            h_multi_intersect(p1, p2, 1000, &mut inters);
         }
      });
   }

   #[bench]
   fn bench_lineinter_fast(b: &mut Bencher) {
      let mut inters = Ring::new(100_000);
      let p1 = Point::new(0, 0);
      let p2 = Point::new(500_000, 2_000_000);

      b.iter(|| {
         for _ in 0..1000 {
            inters.clear();
            h_multi_intersect_fast(p1, p2, 1000, &mut inters);
         }
      });
   }
}
<commit_msg>Making the h_intersect and v_intersect functions public<commit_after>use std::i64;

use super::number::NumberOps;
use super::point::Point;
use super::ring::Ring;

pub const HALF_MAX_ERR: i64  = i64::MAX / 2;

#[inline]
pub fn h_multi_intersect(p1: Point, p2: Point, step_y: i64, inters: &mut Ring<i64>) {
   let (p1, p2) = if p1.y > p2.y {
      (p2, p1)
   } else {
      (p1, p2)
   };

   let start = 1 + p1.y / step_y;
   let end = 1 + (p2.y - 1) / step_y;

   for i in start..end {
      let x = h_intersect(p1, p2, i * step_y);
      inters.push(x);
   }
}

#[inline]
pub fn v_multi_intersect(p1: Point, p2: Point, step_x: i64, inters: &mut Ring<i64>) {
   let (p1, p2) = if p1.x > p2.x {
      (p2, p1)
   } else {
      (p1, p2)
   };

   let start = 1 + p1.x / step_x;
   let end = 1 + (p2.x - 1) / step_x;

   for i in start..end {
      let y = v_intersect(p1, p2, i * step_x);
      inters.push(y);
   }
}

#[inline]
pub fn h_multi_intersect_fast(p1: Point, p2: Point, step_y: i64, inters: &mut Ring<i64>) -> i64 {
   let (p1, p2) = if p1.y > p2.y {
      (p2, p1)
   } else {
      (p1, p2)
   };

   let start = 1 + p1.y / step_y;
   let end = 1 + (p2.y - 1) / step_y;

   let dy = p2.y - p1.y;
   let dx = p2.x - p1.x;
   let dx_signum = dx.signum();

   let step_x = dx * step_y / dy;

   let max_div_dy = i64::MAX / dy;

   let err_step = max_div_dy * (step_y * dx * dx_signum - step_x * dx_signum * dy);

   let first_y = start * step_y;

   let fdy = first_y - p1.y;
   let fdx = dx * fdy / dy;

   let mut x = p1.x + fdx;

   if err_step == 0 {
      for _ in start..end {
         inters.push(x);

         x += step_x;
      }

      return first_y;
   }

   let mut err = max_div_dy * (fdy * dx * dx_signum - fdx * dx_signum * dy) - HALF_MAX_ERR;

   for _ in start..end {
      if err > 0 {
         x += dx_signum;
         err -= i64::MAX;
      }

      inters.push(x);

      x += step_x;

      err += err_step;
   }

   first_y
}

#[inline]
pub fn v_multi_intersect_fast(p1: Point, p2: Point, step_x: i64, inters: &mut Ring<i64>) -> i64 {
   let (p1, p2) = if p1.x > p2.x {
      (p2, p1)
   } else {
      (p1, p2)
   };

   let start = 1 + p1.x / step_x;
   let end = 1 + (p2.x - 1) / step_x;

   let dx = p2.x - p1.x;
   let dy = p2.y - p1.y;
   let dy_signum = dy.signum();

   let step_y = dy * step_x / dx;

   let max_div_dx = i64::MAX / dx;

   let err_step = max_div_dx * (step_x * dy * dy_signum - step_y * dy_signum * dx);

   let first_x = start * step_x;

   let fdx = first_x - p1.x;
   let fdy = dy * fdx / dx;

   let mut y = p1.y + fdy;

   if err_step == 0 {
      for _ in start..end {
         inters.push(y);

         y += step_y;
      }

      return first_x;
   }

   let mut err = max_div_dx * (fdx * dy * dy_signum - fdy * dy_signum * dx) - HALF_MAX_ERR;

   for _ in start..end {
      if err > 0 {
         y += dy_signum;
         err -= i64::MAX;
      }

      inters.push(y);

      y += step_y;

      err += err_step;
   }

   first_x
}

#[inline]
pub fn h_intersect(p1: Point, p2: Point, y: i64) -> i64 {
   p1.x + ((p2.x - p1.x) * (y - p1.y)).rounding_div(p2.y - p1.y)
}

#[inline]
pub fn v_intersect(p1: Point, p2: Point, x: i64) -> i64 {
   p1.y + ((p2.y - p1.y) * (x - p1.x)).rounding_div(p2.x - p1.x)
}

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

   use super::super::point::Point;
   use super::super::ring::Ring;

   use super::*;

   #[test]
   fn test_correct_h() {
      let mut inters = Ring::new(100_000);
      let mut inters_fast = Ring::new(100_000);
      let p1 = Point::new(0, 0);
      let p2 = Point::new(500_000, 2_000_000);

      h_multi_intersect(p1, p2, 1000, &mut inters);
      h_multi_intersect_fast(p1, p2, 1000, &mut inters_fast);

      for (correct, fast) in inters[..].iter().zip(inters_fast[..].iter()) {
         assert_eq!(correct, fast);
      }
   }

   #[test]
   fn test_correct_h_rev() {
      let mut inters = Ring::new(100_000);
      let mut inters_fast = Ring::new(100_000);
      let p1 = Point::new(500_000, 0);
      let p2 = Point::new(0, 2_000_000);

      h_multi_intersect(p1, p2, 1000, &mut inters);
      h_multi_intersect_fast(p1, p2, 1000, &mut inters_fast);

      for (correct, fast) in inters[..].iter().zip(inters_fast[..].iter()) {
         assert_eq!(correct, fast);
      }
   }

   #[test]
   fn test_correct_v() {
      let mut inters = Ring::new(100_000);
      let mut inters_fast = Ring::new(100_000);
      let p1 = Point::new(0, 0);
      let p2 = Point::new(500_000, 2_000_000);

      v_multi_intersect(p1, p2, 1000, &mut inters);
      v_multi_intersect_fast(p1, p2, 1000, &mut inters_fast);

      for (correct, fast) in inters[..].iter().zip(inters_fast[..].iter()) {
         assert_eq!(correct, fast);
      }
   }

   #[test]
   fn test_correct_v_rev() {
      let mut inters = Ring::new(100_000);
      let mut inters_fast = Ring::new(100_000);
      let p1 = Point::new(500_000, 0);
      let p2 = Point::new(0, 2_000_000);

      v_multi_intersect(p1, p2, 1000, &mut inters);
      v_multi_intersect_fast(p1, p2, 1000, &mut inters_fast);

      for (correct, fast) in inters[..].iter().zip(inters_fast[..].iter()) {
         assert_eq!(correct, fast);
      }
   }

   #[bench]
   fn bench_lineinter(b: &mut Bencher) {
      let mut inters = Ring::new(100_000);
      let p1 = Point::new(0, 0);
      let p2 = Point::new(500_000, 2_000_000);

      b.iter(|| {
         for _ in 0..1000 {
            inters.clear();
            h_multi_intersect(p1, p2, 1000, &mut inters);
         }
      });
   }

   #[bench]
   fn bench_lineinter_fast(b: &mut Bencher) {
      let mut inters = Ring::new(100_000);
      let p1 = Point::new(0, 0);
      let p2 = Point::new(500_000, 2_000_000);

      b.iter(|| {
         for _ in 0..1000 {
            inters.clear();
            h_multi_intersect_fast(p1, p2, 1000, &mut inters);
         }
      });
   }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::convert::TryInto;
use std::fs::File;
use std::io::*;

use rug::Integer;

/*
Parser for the subset of FASM that Oxide cares about

Note that this does some preprocessing on features to speed up
downstream usage.

The first part of a feature, split by '.' is considered the tile
if 'PIP' follows it is a pip of form to_wire.from_wire
if it is vector style it is a word
otherwise it is an enum

*/

pub struct FasmTile {
    pub pips: BTreeMap<String, String>,
    pub enums: BTreeMap<String, String>,
    pub words: BTreeMap<String, Integer>,
}

impl FasmTile {
    pub fn new() -> FasmTile {
        FasmTile {
            pips: BTreeMap::new(),
            enums: BTreeMap::new(),
            words: BTreeMap::new(),
        }
    }
}

pub struct ParsedFasm {
    pub tiles: BTreeMap<String, FasmTile>,
}

impl ParsedFasm {
    pub fn parse(filename: &str) -> Result<ParsedFasm> {
        let mut p = ParsedFasm {
            tiles: BTreeMap::new(),
        };
        let file = File::open(filename)?;
        let reader = BufReader::new(file);
        for (lineno, line) in reader.lines().enumerate() {
            let l: String = line?;
            let first_nonblank = l.find(|c: char| !c.is_whitespace());
            if first_nonblank == None {
                continue;
            }
            let first_nonblank = first_nonblank.unwrap();
            let comment_start = l.find(|c: char| c == '#' || c == '{').unwrap_or(l.len());
            if first_nonblank >= comment_start {
                continue;
            }
            let mut buf = &l[first_nonblank..comment_start];

            let get_ident = |parsebuf: &mut &str| -> String {
                let end_index = parsebuf
                    .find(|c: char| !c.is_ascii_alphanumeric() && c != '_')
                    .unwrap_or(parsebuf.len());
                let token = &parsebuf[0..end_index];
                *parsebuf = &parsebuf[end_index..];
                token.to_string()
            };
            let assert_token = |parsebuf: &mut &str, tok: &str| {
                if tok.len() > parsebuf.len() || &parsebuf[0..tok.len()] != tok {
                    panic!("expected token {} on line {}", tok, lineno + 1);
                }
                *parsebuf = &&parsebuf[tok.len()..];
            };
            let check_token = |parsebuf: &mut &str, tok: &str| -> bool {
                if tok.len() > parsebuf.len() || &parsebuf[0..tok.len()] != tok {
                    false
                } else {
                    *parsebuf = &parsebuf[tok.len()..];
                    true
                }
            };
            let skip_whitespace = |parsebuf: &mut &str| {
                let end_index = parsebuf
                    .find(|c: char| !c.is_whitespace())
                    .unwrap_or(parsebuf.len());
                *parsebuf = &parsebuf[end_index..];
            };
            let get_integer = |parsebuf: &mut &str| -> i32 {
                let end_index = parsebuf
                    .find(|c: char| !c.is_ascii_digit())
                    .unwrap_or(parsebuf.len());
                if end_index == 0 {
                    panic!("expected numeric value on line {}", lineno + 1);
                }
                let val = parsebuf[0..end_index].parse::<i32>().unwrap();
                *parsebuf = &parsebuf[end_index..];
                val
            };
            let get_char = |parsebuf: &mut &str| -> char {
                let ch = parsebuf.chars().next().unwrap();
                *parsebuf = &parsebuf[1..];
                ch
            };
            let get_value = |parsebuf: &mut &str| -> Integer {
                skip_whitespace(parsebuf);
                let width_or_value = get_integer(parsebuf);
                skip_whitespace(parsebuf);
                if !check_token(parsebuf, "'") {
                    return Integer::from(width_or_value);
                }
                skip_whitespace(parsebuf);
                let base = get_char(parsebuf);
                let digits = get_ident(parsebuf);
                Integer::from(
                    match base {
                        'b' => Integer::parse_radix(&digits, 2),
                        'o' => Integer::parse_radix(&digits, 8),
                        'd' => Integer::parse_radix(&digits, 10),
                        'h' => Integer::parse_radix(&digits, 16),
                        _ => panic!("unsupported base '{} on line {}", base, lineno + 1),
                    }
                    .unwrap(),
                )
            };
            let tilename = get_ident(&mut buf).replace("__", ":");
            let tile_data = p.tiles.entry(tilename).or_insert_with(FasmTile::new);
            assert_token(&mut buf, ".");
            if check_token(&mut buf, "PIP.") {
                // It's a pip
                let to_wire = get_ident(&mut buf).replace("__", ":");
                assert_token(&mut buf, ".");
                let from_wire = get_ident(&mut buf).replace("__", ":");
                tile_data.pips.insert(to_wire, from_wire);
            } else {
                let mut feature_split = Vec::new();
                loop {
                    feature_split.push(get_ident(&mut buf));
                    if !check_token(&mut buf, ".") {
                        break;
                    }
                }
                skip_whitespace(&mut buf);
                if check_token(&mut buf, "[") {
                    skip_whitespace(&mut buf);
                    // Word style setting
                    let key = feature_split.join(".");
                    let end_bit: u32 = get_integer(&mut buf).try_into().unwrap();
                    skip_whitespace(&mut buf);
                    let mut start_bit = end_bit;
                    skip_whitespace(&mut buf);
                    if check_token(&mut buf, ":") {
                        skip_whitespace(&mut buf);
                        start_bit = get_integer(&mut buf).try_into().unwrap();
                        skip_whitespace(&mut buf);
                    }
                    assert!(end_bit >= start_bit);
                    assert_token(&mut buf, "]");
                    skip_whitespace(&mut buf);
                    let value = if check_token(&mut buf, "=") {
                        skip_whitespace(&mut buf);
                        get_value(&mut buf)
                    } else {
                        Integer::from(1)
                    };
                    let dest = tile_data
                        .words
                        .entry(key)
                        .or_insert_with(|| Integer::from(0));
                    let count: u32 = (end_bit - start_bit) + 1;
                    for i in 0..count {
                        dest.set_bit(start_bit + i, value.get_bit(i));
                    }
                } else {
                    // Enum style setting
                    let key = feature_split[0..feature_split.len() - 1].join(".");
                    let value = &feature_split[feature_split.len() - 1];
                    tile_data.enums.insert(key, value.to_string());
                }
            }
        }
        Ok(p)
    }

    pub fn dump(&self, out: &mut dyn Write) -> Result<()> {
        for (tile, tdata) in self.tiles.iter() {
            for (to_wire, from_wire) in tdata.pips.iter() {
                writeln!(out, "{}.PIP.{}.{}", tile, to_wire, from_wire)?;
            }
            for (name, opt) in tdata.enums.iter() {
                writeln!(out, "{}.{}.{}", tile, name, opt)?;
            }
            for (name, val) in tdata.words.iter() {
                if val.significant_bits() > 0 {
                    writeln!(
                        out,
                        "{}.{}[{}:0] = {}'b{:b}",
                        tile,
                        name,
                        val.significant_bits() - 1,
                        val.significant_bits(),
                        val
                    )?;
                }
            }
            if !tdata.pips.is_empty() || !tdata.enums.is_empty() || !tdata.words.is_empty() {
                writeln!(out, "")?;
            }
        }
        Ok(())
    }
}
<commit_msg>Add attributes to FASM parsing<commit_after>use std::collections::BTreeMap;
use std::convert::TryInto;
use std::fs::File;
use std::io::*;

use rug::Integer;

/*
Parser for the subset of FASM that Oxide cares about

Note that this does some preprocessing on features to speed up
downstream usage.

The first part of a feature, split by '.' is considered the tile
if 'PIP' follows it is a pip of form to_wire.from_wire
if it is vector style it is a word
otherwise it is an enum

*/

pub struct FasmTile {
    pub pips: BTreeMap<String, String>,
    pub enums: BTreeMap<String, String>,
    pub words: BTreeMap<String, Integer>,
}

impl FasmTile {
    pub fn new() -> FasmTile {
        FasmTile {
            pips: BTreeMap::new(),
            enums: BTreeMap::new(),
            words: BTreeMap::new(),
        }
    }
}

pub struct ParsedFasm {
    pub attrs: Vec<(String, String)>,
    pub tiles: BTreeMap<String, FasmTile>,
}

impl ParsedFasm {
    pub fn parse(filename: &str) -> Result<ParsedFasm> {
        let mut p = ParsedFasm {
            attrs: Vec::new(),
            tiles: BTreeMap::new(),
        };
        let file = File::open(filename)?;
        let reader = BufReader::new(file);
        for (lineno, line) in reader.lines().enumerate() {
            let l: String = line?;
            let first_nonblank = l.find(|c: char| !c.is_whitespace());
            if first_nonblank == None {
                continue;
            }
            let first_nonblank = first_nonblank.unwrap();
            let comment_start = l.find(|c: char| c == '#').unwrap_or(l.len());
            if first_nonblank >= comment_start {
                continue;
            }
            let mut buf = &l[first_nonblank..comment_start];

            let get_ident = |parsebuf: &mut &str| -> String {
                let end_index = parsebuf
                    .find(|c: char| !c.is_ascii_alphanumeric() && c != '_')
                    .unwrap_or(parsebuf.len());
                let token = &parsebuf[0..end_index];
                *parsebuf = &parsebuf[end_index..];
                token.to_string()
            };
            let get_attr_key = |parsebuf: &mut &str| -> String {
                let end_index = parsebuf
                    .find(|c: char| !c.is_ascii_alphanumeric() && c != '_' && c != '.')
                    .unwrap_or(parsebuf.len());
                let token = &parsebuf[0..end_index];
                *parsebuf = &parsebuf[end_index..];
                token.to_string()
            };
            let assert_token = |parsebuf: &mut &str, tok: &str| {
                if tok.len() > parsebuf.len() || &parsebuf[0..tok.len()] != tok {
                    panic!("expected token {} on line {}", tok, lineno + 1);
                }
                *parsebuf = &&parsebuf[tok.len()..];
            };
            let check_token = |parsebuf: &mut &str, tok: &str| -> bool {
                if tok.len() > parsebuf.len() || &parsebuf[0..tok.len()] != tok {
                    false
                } else {
                    *parsebuf = &parsebuf[tok.len()..];
                    true
                }
            };
            let skip_whitespace = |parsebuf: &mut &str| {
                let end_index = parsebuf
                    .find(|c: char| !c.is_whitespace())
                    .unwrap_or(parsebuf.len());
                *parsebuf = &parsebuf[end_index..];
            };
            let get_integer = |parsebuf: &mut &str| -> i32 {
                let end_index = parsebuf
                    .find(|c: char| !c.is_ascii_digit())
                    .unwrap_or(parsebuf.len());
                if end_index == 0 {
                    panic!("expected numeric value on line {}", lineno + 1);
                }
                let val = parsebuf[0..end_index].parse::<i32>().unwrap();
                *parsebuf = &parsebuf[end_index..];
                val
            };
            let get_char = |parsebuf: &mut &str| -> char {
                let ch = parsebuf.chars().next().unwrap();
                *parsebuf = &parsebuf[1..];
                ch
            };
            let get_value = |parsebuf: &mut &str| -> Integer {
                skip_whitespace(parsebuf);
                let width_or_value = get_integer(parsebuf);
                skip_whitespace(parsebuf);
                if !check_token(parsebuf, "'") {
                    return Integer::from(width_or_value);
                }
                skip_whitespace(parsebuf);
                let base = get_char(parsebuf);
                let digits = get_ident(parsebuf);
                Integer::from(
                    match base {
                        'b' => Integer::parse_radix(&digits, 2),
                        'o' => Integer::parse_radix(&digits, 8),
                        'd' => Integer::parse_radix(&digits, 10),
                        'h' => Integer::parse_radix(&digits, 16),
                        _ => panic!("unsupported base '{} on line {}", base, lineno + 1),
                    }
                    .unwrap(),
                )
            };
            let get_attr_value = |parsebuf: &mut &str| -> String {
                if check_token(parsebuf, "\"") {
                    // String
                    let end_index = parsebuf.find('"').unwrap();
                    let val = &parsebuf[0..end_index];
                    *parsebuf = &parsebuf[end_index + 1..];
                    val.to_string()
                } else {
                    // Not string
                    get_attr_key(parsebuf)
                }
            };
            if check_token(&mut buf, "{") {
                skip_whitespace(&mut buf);
                while !check_token(&mut buf, "}") {
                    let key = get_attr_key(&mut buf);
                    skip_whitespace(&mut buf);
                    assert_token(&mut buf, "=");
                    skip_whitespace(&mut buf);
                    p.attrs.push((key, get_attr_value(&mut buf)));
                    skip_whitespace(&mut buf);
                    if !check_token(&mut buf, ",") {
                        assert_token(&mut buf, "}");
                        break;
                    }
                }
            } else {
                let tilename = get_ident(&mut buf).replace("__", ":");
                let tile_data = p.tiles.entry(tilename).or_insert_with(FasmTile::new);
                assert_token(&mut buf, ".");
                if check_token(&mut buf, "PIP.") {
                    // It's a pip
                    let to_wire = get_ident(&mut buf).replace("__", ":");
                    assert_token(&mut buf, ".");
                    let from_wire = get_ident(&mut buf).replace("__", ":");
                    tile_data.pips.insert(to_wire, from_wire);
                } else {
                    let mut feature_split = Vec::new();
                    loop {
                        feature_split.push(get_ident(&mut buf));
                        if !check_token(&mut buf, ".") {
                            break;
                        }
                    }
                    skip_whitespace(&mut buf);
                    if check_token(&mut buf, "[") {
                        skip_whitespace(&mut buf);
                        // Word style setting
                        let key = feature_split.join(".");
                        let end_bit: u32 = get_integer(&mut buf).try_into().unwrap();
                        skip_whitespace(&mut buf);
                        let mut start_bit = end_bit;
                        skip_whitespace(&mut buf);
                        if check_token(&mut buf, ":") {
                            skip_whitespace(&mut buf);
                            start_bit = get_integer(&mut buf).try_into().unwrap();
                            skip_whitespace(&mut buf);
                        }
                        assert!(end_bit >= start_bit);
                        assert_token(&mut buf, "]");
                        skip_whitespace(&mut buf);
                        let value = if check_token(&mut buf, "=") {
                            skip_whitespace(&mut buf);
                            get_value(&mut buf)
                        } else {
                            Integer::from(1)
                        };
                        let dest = tile_data
                            .words
                            .entry(key)
                            .or_insert_with(|| Integer::from(0));
                        let count: u32 = (end_bit - start_bit) + 1;
                        for i in 0..count {
                            dest.set_bit(start_bit + i, value.get_bit(i));
                        }
                    } else {
                        // Enum style setting
                        let key = feature_split[0..feature_split.len() - 1].join(".");
                        let value = &feature_split[feature_split.len() - 1];
                        tile_data.enums.insert(key, value.to_string());
                    }
                }
            }
        }
        Ok(p)
    }

    pub fn dump(&self, out: &mut dyn Write) -> Result<()> {
        for (akey, aval) in self.attrs.iter() {
            writeln!(out, "{{ {}=\"{}\" }}", akey, aval)?;
        }
        for (tile, tdata) in self.tiles.iter() {
            for (to_wire, from_wire) in tdata.pips.iter() {
                writeln!(out, "{}.PIP.{}.{}", tile, to_wire, from_wire)?;
            }
            for (name, opt) in tdata.enums.iter() {
                writeln!(out, "{}.{}.{}", tile, name, opt)?;
            }
            for (name, val) in tdata.words.iter() {
                if val.significant_bits() > 0 {
                    writeln!(
                        out,
                        "{}.{}[{}:0] = {}'b{:b}",
                        tile,
                        name,
                        val.significant_bits() - 1,
                        val.significant_bits(),
                        val
                    )?;
                }
            }
            if !tdata.pips.is_empty() || !tdata.enums.is_empty() || !tdata.words.is_empty() {
                writeln!(out, "")?;
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! QuickFLI.

extern crate flic;
extern crate sdl2;

use std::env;
use std::path::PathBuf;
use flic::{FlicFile,RasterMut};
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::PixelFormatEnum;

const DEFAULT_SCREEN_WIDTH: u32 = 640;
const DEFAULT_SCREEN_HEIGHT: u32 = 400;
const MIN_SCREEN_WIDTH: u32 = 320;
const MIN_SCREEN_HEIGHT: u32 = 200;
const FLIC_WIDTH: usize = 320;
const FLIC_HEIGHT: usize = 200;

fn main() {
    let mut filenames: Vec<String> = env::args().skip(1).collect();
    let mut flic: Option<FlicFile> = None;
    let mut next_file: usize = 0;

    usage();
    if filenames.len() <= 0 {
        return;
    }

    // Initialise SDL window.
    let sdl = sdl2::init().unwrap();
    let video = sdl.video().unwrap();

    let mut window
        = video.window("QuickFLI", DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT)
        .resizable()
        .position_centered()
        .opengl()
        .build().unwrap();

    let _ = window.set_minimum_size(MIN_SCREEN_WIDTH, MIN_SCREEN_HEIGHT);
    let mut renderer = window.renderer().build().unwrap();
    let mut timer = sdl.timer().unwrap();
    let mut event_pump = sdl.event_pump().unwrap();

    let mut texture = renderer.create_texture_streaming(
            PixelFormatEnum::RGB24, FLIC_WIDTH as u32, FLIC_HEIGHT as u32).unwrap();
    let mut buf = vec![0; FLIC_WIDTH * FLIC_HEIGHT];
    let mut pal = vec![0; 3 * 256];

    let mut last_tstart: u32 = 0;
    'mainloop: loop {
        let msec = match flic {
            Some(ref f) => 1000 * f.speed_jiffies() as u32 / 70,
            None => 100,
        };

        let tnow = timer.ticks();
        let tstart = if msec > 0 { tnow - tnow % msec } else { tnow };
        let tend = tstart + msec;

        let redraw = tstart > last_tstart;
        if redraw {
            if let Some(ref mut flic) = flic {
                match flic.read_next_frame(
                        &mut RasterMut::new(FLIC_WIDTH, FLIC_HEIGHT, &mut buf, &mut pal)) {
                    Ok(_) => {
                        render_to_texture(&mut texture, FLIC_WIDTH, FLIC_HEIGHT, &buf, &pal);
                        present_to_screen(&mut renderer, &texture);
                    },
                    Err(e) => {
                        println!("Error occurred - {}", e);
                    },
                }
            } else {
                renderer.clear();
                renderer.present();
            }

            last_tstart = tstart;
        }

        if !redraw || msec == 0 {
            if let Some(e) = event_pump.wait_event_timeout(tend - tnow) {
                match e {
                    Event::Quit {..}
                    | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                        break 'mainloop;
                    },

                    Event::KeyDown { keycode: Some(Keycode::Space), .. } => {
                        if filenames.len() > 1 {
                            flic = None;
                        }
                    },

                    _ => (),
                }
            }

            // Try loading a new flic.
            if flic.is_none() && filenames.len() > 0 {
                if next_file >= filenames.len() {
                    next_file = 0;
                }

                let path = PathBuf::from(&filenames[next_file]);
                match FlicFile::open(path.as_path()) {
                    Ok(f) => {
                        println!("Loaded {}", &filenames[next_file]);
                        flic = Some(f);
                        last_tstart = 0;
                        next_file = next_file + 1;
                    },
                    Err(e) => {
                        println!("Error loading {} -- {}", &filenames[next_file], e);
                        filenames.remove(next_file);
                    },
                }
            }
        }
    }
}

fn usage() {
    println!("QuickFLI - a simple player for 256 color VGA animations");
    println!("");
    println!("Give QuickFLI a list of FLICs to play.");
    println!("<ESC> to abort playback.");
    println!("<space> to go to next FLIC.");
}

fn render_to_texture(
        texture: &mut sdl2::render::Texture,
        w: usize, h: usize, buf: &[u8], pal: &[u8]) {
    texture.with_lock(None, |buffer: &mut [u8], pitch: usize| {
        for y in 0..h {
            for x in 0..w {
                let offset = pitch * y + 3 * x;
                let c = buf[w * y + x] as usize;

                buffer[offset + 0] = pal[3 * c + 0];
                buffer[offset + 1] = pal[3 * c + 1];
                buffer[offset + 2] = pal[3 * c + 2];
            }
        }
    }).unwrap();
}

fn present_to_screen(
        renderer: &mut sdl2::render::Renderer,
        texture: &sdl2::render::Texture) {
    renderer.clear();
    renderer.copy(&texture, None, None);
    renderer.present();
}
<commit_msg>Update QuickFLI to support different size FLICs.<commit_after>//! QuickFLI.

extern crate flic;
extern crate sdl2;

use std::env;
use std::path::PathBuf;
use flic::{FlicFile,RasterMut};
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::PixelFormatEnum;

const DEFAULT_SCREEN_WIDTH: u32 = 640;
const DEFAULT_SCREEN_HEIGHT: u32 = 400;
const MIN_SCREEN_WIDTH: u32 = 320;
const MIN_SCREEN_HEIGHT: u32 = 200;

fn main() {
    let mut filenames: Vec<String> = env::args().skip(1).collect();
    let mut flic: Option<FlicFile> = None;
    let mut next_file: usize = 0;

    usage();
    if filenames.len() <= 0 {
        return;
    }

    // Initialise SDL window.
    let sdl = sdl2::init().unwrap();
    let video = sdl.video().unwrap();

    let mut window
        = video.window("QuickFLI", DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT)
        .resizable()
        .position_centered()
        .opengl()
        .build().unwrap();

    let _ = window.set_minimum_size(MIN_SCREEN_WIDTH, MIN_SCREEN_HEIGHT);
    let mut renderer = window.renderer().build().unwrap();
    let mut timer = sdl.timer().unwrap();
    let mut event_pump = sdl.event_pump().unwrap();

    let mut flic_w = 0;
    let mut flic_h = 0;
    let mut texture = None;
    let mut buf = vec![0; flic_w * flic_h];
    let mut pal = vec![0; 3 * 256];

    let mut last_tstart: u32 = 0;
    'mainloop: loop {
        let msec = match flic {
            Some(ref f) => f.speed_msec(),
            None => 100,
        };

        let tnow = timer.ticks();
        let tstart = if msec > 0 { tnow - tnow % msec } else { tnow };
        let tend = tstart + msec;

        let redraw = tstart > last_tstart;
        if redraw {
            if let (Some(ref mut flic), Some(ref mut texture)) = (flic.as_mut(), texture.as_mut()) {
                match flic.read_next_frame(
                        &mut RasterMut::new(flic_w, flic_h, &mut buf, &mut pal)) {
                    Ok(_) => {
                        render_to_texture(texture, flic_w, flic_h, &buf, &pal);
                        present_to_screen(&mut renderer, texture);
                    },
                    Err(e) => {
                        println!("Error occurred - {}", e);
                    },
                }
            } else {
                renderer.clear();
                renderer.present();
            }

            last_tstart = tstart;
        }

        if !redraw || msec == 0 {
            if let Some(e) = event_pump.wait_event_timeout(tend - tnow) {
                match e {
                    Event::Quit {..}
                    | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                        break 'mainloop;
                    },

                    Event::KeyDown { keycode: Some(Keycode::Space), .. } => {
                        if filenames.len() > 1 {
                            flic = None;
                        }
                    },

                    _ => (),
                }
            }

            // Try loading a new flic.
            if flic.is_none() && filenames.len() > 0 {
                if next_file >= filenames.len() {
                    next_file = 0;
                }

                let path = PathBuf::from(&filenames[next_file]);
                match FlicFile::open(path.as_path()) {
                    Ok(f) => {
                        println!("Loaded {}", &filenames[next_file]);

                        if f.width() as usize != flic_w || f.height() as usize != flic_h {
                            flic_w = f.width() as usize;
                            flic_h = f.height() as usize;

                            texture = renderer.create_texture_streaming(
                                        PixelFormatEnum::RGB24,
                                        flic_w as u32, flic_h as u32).ok();
                            buf = vec![0; flic_w * flic_h];
                        }

                        flic = Some(f);
                        last_tstart = 0;
                        next_file = next_file + 1;
                    },
                    Err(e) => {
                        println!("Error loading {} -- {}", &filenames[next_file], e);
                        filenames.remove(next_file);
                    },
                }
            }
        }
    }
}

fn usage() {
    println!("QuickFLI - a simple player for 256 color VGA animations");
    println!("");
    println!("Give QuickFLI a list of FLICs to play.");
    println!("<ESC> to abort playback.");
    println!("<space> to go to next FLIC.");
}

fn render_to_texture(
        texture: &mut sdl2::render::Texture,
        w: usize, h: usize, buf: &[u8], pal: &[u8]) {
    texture.with_lock(None, |buffer: &mut [u8], pitch: usize| {
        for y in 0..h {
            for x in 0..w {
                let offset = pitch * y + 3 * x;
                let c = buf[w * y + x] as usize;

                buffer[offset + 0] = pal[3 * c + 0];
                buffer[offset + 1] = pal[3 * c + 1];
                buffer[offset + 2] = pal[3 * c + 2];
            }
        }
    }).unwrap();
}

fn present_to_screen(
        renderer: &mut sdl2::render::Renderer,
        texture: &sdl2::render::Texture) {
    renderer.clear();
    renderer.copy(&texture, None, None);
    renderer.present();
}
<|endoftext|>


<commit_before>use crate::gen::include::Includes;
use crate::syntax::namespace::Namespace;
use std::cell::RefCell;
use std::fmt::{self, Arguments, Write};

pub(crate) struct OutFile {
    pub namespace: Namespace,
    pub header: bool,
    pub include: Includes,
    pub front: Content,
    content: RefCell<Content>,
}

pub struct Content {
    bytes: String,
    section_pending: bool,
    blocks_pending: Vec<&'static str>,
}

impl OutFile {
    pub fn new(namespace: Namespace, header: bool) -> Self {
        OutFile {
            namespace,
            header,
            include: Includes::new(),
            front: Content::new(),
            content: RefCell::new(Content::new()),
        }
    }

    // Write a blank line if the preceding section had any contents.
    pub fn next_section(&mut self) {
        let content = self.content.get_mut();
        content.section_pending = true;
    }

    pub fn begin_block(&mut self, block: &'static str) {
        let content = self.content.get_mut();
        content.blocks_pending.push(block);
    }

    pub fn end_block(&mut self, block: &'static str) {
        let content = self.content.get_mut();
        if content.blocks_pending.pop().is_none() {
            content.bytes.push_str("} // ");
            content.bytes.push_str(block);
            content.bytes.push('\n');
            content.section_pending = true;
        }
    }

    pub fn write_fmt(&self, args: Arguments) {
        let content = &mut *self.content.borrow_mut();
        Write::write_fmt(content, args).unwrap();
    }

    pub fn content(&self) -> Vec<u8> {
        let front = &self.front.bytes;
        let content = &self.content.borrow().bytes;
        let len = front.len() + !front.is_empty() as usize + content.len();
        let mut out = String::with_capacity(len);
        out.push_str(front);
        if !front.is_empty() {
            out.push('\n');
        }
        out.push_str(content);
        out.into_bytes()
    }
}

impl Write for Content {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        self.write(s);
        Ok(())
    }
}

impl Content {
    pub fn write_fmt(&mut self, args: Arguments) {
        Write::write_fmt(self, args).unwrap();
    }

    fn new() -> Self {
        Content {
            bytes: String::new(),
            section_pending: false,
            blocks_pending: Vec::new(),
        }
    }

    fn write(&mut self, b: &str) {
        if !b.is_empty() {
            if !self.blocks_pending.is_empty() {
                if !self.bytes.is_empty() {
                    self.bytes.push('\n');
                }
                for block in self.blocks_pending.drain(..) {
                    self.bytes.push_str(block);
                    self.bytes.push_str(" {\n");
                }
                self.section_pending = false;
            } else if self.section_pending {
                if !self.bytes.is_empty() {
                    self.bytes.push('\n');
                }
                self.section_pending = false;
            }
            self.bytes.push_str(b);
        }
    }
}
<commit_msg>Avoid printing completely empty output<commit_after>use crate::gen::include::Includes;
use crate::syntax::namespace::Namespace;
use std::cell::RefCell;
use std::fmt::{self, Arguments, Write};

pub(crate) struct OutFile {
    pub namespace: Namespace,
    pub header: bool,
    pub include: Includes,
    pub front: Content,
    content: RefCell<Content>,
}

pub struct Content {
    bytes: String,
    section_pending: bool,
    blocks_pending: Vec<&'static str>,
}

impl OutFile {
    pub fn new(namespace: Namespace, header: bool) -> Self {
        OutFile {
            namespace,
            header,
            include: Includes::new(),
            front: Content::new(),
            content: RefCell::new(Content::new()),
        }
    }

    // Write a blank line if the preceding section had any contents.
    pub fn next_section(&mut self) {
        let content = self.content.get_mut();
        content.section_pending = true;
    }

    pub fn begin_block(&mut self, block: &'static str) {
        let content = self.content.get_mut();
        content.blocks_pending.push(block);
    }

    pub fn end_block(&mut self, block: &'static str) {
        let content = self.content.get_mut();
        if content.blocks_pending.pop().is_none() {
            content.bytes.push_str("} // ");
            content.bytes.push_str(block);
            content.bytes.push('\n');
            content.section_pending = true;
        }
    }

    pub fn write_fmt(&self, args: Arguments) {
        let content = &mut *self.content.borrow_mut();
        Write::write_fmt(content, args).unwrap();
    }

    pub fn content(&self) -> Vec<u8> {
        let front = &self.front.bytes;
        let content = &self.content.borrow().bytes;
        let len = front.len() + content.len() + 1;
        let mut out = String::with_capacity(len);
        out.push_str(front);
        if !front.is_empty() && !content.is_empty() {
            out.push('\n');
        }
        out.push_str(content);
        if out.is_empty() {
            out.push_str("// empty\n");
        }
        out.into_bytes()
    }
}

impl Write for Content {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        self.write(s);
        Ok(())
    }
}

impl Content {
    pub fn write_fmt(&mut self, args: Arguments) {
        Write::write_fmt(self, args).unwrap();
    }

    fn new() -> Self {
        Content {
            bytes: String::new(),
            section_pending: false,
            blocks_pending: Vec::new(),
        }
    }

    fn write(&mut self, b: &str) {
        if !b.is_empty() {
            if !self.blocks_pending.is_empty() {
                if !self.bytes.is_empty() {
                    self.bytes.push('\n');
                }
                for block in self.blocks_pending.drain(..) {
                    self.bytes.push_str(block);
                    self.bytes.push_str(" {\n");
                }
                self.section_pending = false;
            } else if self.section_pending {
                if !self.bytes.is_empty() {
                    self.bytes.push('\n');
                }
                self.section_pending = false;
            }
            self.bytes.push_str(b);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Virtio device async helper functions.

use std::cell::RefCell;
use std::rc::Rc;

use anyhow::{Context, Result};
use base::Event;
use cros_async::{EventAsync, Executor};

use super::{Interrupt, SignalableInterrupt};

/// Async task that waits for a signal from `event`.  Once this event is readable, exit. Exiting
/// this future will cause the main loop to break and the worker thread to exit.
pub async fn await_and_exit(ex: &Executor, event: Event) -> Result<()> {
    let event_async = EventAsync::new(event.0, ex).context("failed to create EventAsync")?;
    let _ = event_async.next_val().await;
    Ok(())
}

/// Async task that resamples the status of the interrupt when the guest sends a request by
/// signalling the resample event associated with the interrupt.
pub async fn handle_irq_resample(ex: &Executor, interrupt: Rc<RefCell<Interrupt>>) -> Result<()> {
    if let Some(resample_evt) = interrupt.borrow().get_resample_evt() {
        let resample_evt = resample_evt
            .try_clone()
            .context("resample_evt.try_clone() failed")?;
        let resample_evt =
            EventAsync::new(resample_evt.0, ex).context("failed to create async resample event")?;
        loop {
            let _ = resample_evt
                .next_val()
                .await
                .context("failed to read resample event")?;
            interrupt.borrow().do_interrupt_resample();
        }
    } else {
        // No resample event; park the future.
        let () = futures::future::pending().await;
    }
    Ok(())
}
<commit_msg>devices: virtio: async_utils: do not borrow interrupt across await<commit_after>// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Virtio device async helper functions.

use std::cell::RefCell;
use std::rc::Rc;

use anyhow::{Context, Result};
use base::Event;
use cros_async::{EventAsync, Executor};

use super::{Interrupt, SignalableInterrupt};

/// Async task that waits for a signal from `event`.  Once this event is readable, exit. Exiting
/// this future will cause the main loop to break and the worker thread to exit.
pub async fn await_and_exit(ex: &Executor, event: Event) -> Result<()> {
    let event_async = EventAsync::new(event.0, ex).context("failed to create EventAsync")?;
    let _ = event_async.next_val().await;
    Ok(())
}

/// Async task that resamples the status of the interrupt when the guest sends a request by
/// signalling the resample event associated with the interrupt.
pub async fn handle_irq_resample(ex: &Executor, interrupt: Rc<RefCell<Interrupt>>) -> Result<()> {
    // Clone resample_evt if interrupt has one.
    // This is a separate block so that we do not hold a RefCell borrow across await.
    let resample_evt = if let Some(resample_evt) = interrupt.borrow().get_resample_evt() {
        let resample_evt = resample_evt
            .try_clone()
            .context("resample_evt.try_clone() failed")?;
        Some(EventAsync::new(resample_evt.0, ex).context("failed to create async resample event")?)
    } else {
        None
    };

    if let Some(resample_evt) = resample_evt {
        loop {
            let _ = resample_evt
                .next_val()
                .await
                .context("failed to read resample event")?;
            interrupt.borrow().do_interrupt_resample();
        }
    } else {
        // No resample event; park the future.
        let () = futures::future::pending().await;
    }
    Ok(())
}
<|endoftext|>


<commit_before>
//! Helper functions for hue and saturation selection

use image::{
    GenericImage,
    Rgba,
    RgbaImage,
    SubImage,
};

/// Selects color at coordinate in a rectangle show hue and saturation
pub fn select(rect: [u32, ..4], x: u32, y: u32) -> Rgba<u8> {
    let inv_rect_width = 1.0_f64 / rect[2] as f64;
    let half_inv_rect_height = 0.5_f64 / rect[3] as f64;
    let inv60 = 1.0_f64 / 60.0_f64;

    let fx = (x - rect[0]) as f64 * inv_rect_width;
    let hue = fx * 360.0_f64;
    // Saturation is 0.5 * fy, so by halving the height we save operations.
    let saturation = (y - rect[1]) as f64 * half_inv_rect_height;
    let hi = (hue * inv60) as int;
    let f = hue * inv60 - hi as f64;
    let hi = hi % 6;
    let v = 255; // use white as color without saturation.
    let p = (255.0 * (1.0 - saturation)) as u8;
    let q = (255.0 * (1.0 - f * saturation)) as u8;
    let t = (255.0 * (1.0 - (1.0 - f) * saturation)) as u8;
    Rgba([
        match hi {
            0 | 1 => p,
            2 => t,
            3 | 4 => v,
            _ => q
        },
        match hi {
            0 => t,
            1 | 2 => v,
            3 => q,
            _ => p
        },
        match hi {
            1 => q,
            2 | 3 => p,
            4 => t,
            _ => v
        },
        255
    ])
}

/// Sets colors to hue/saturation image.
/// White is used as color without saturation.
/// This is at the top of the image,
/// while saturated colors are at the bottom.
pub fn fill_image(
    image: &mut RgbaImage,
    rect: [u32, ..4]
) {
    let mut sub_image = SubImage::new(image,
        rect[0], rect[1], rect[2], rect[3]);
    let inv_rect_width = 1.0_f64 / rect[2] as f64;
    let half_inv_rect_height = 0.5_f64 / rect[3] as f64;
    let inv60 = 1.0_f64 / 60.0_f64;
    for (x, y, pxl) in sub_image.pixels_mut() {
        let fx = (x - rect[0]) as f64 * inv_rect_width;
        let hue = fx * 360.0_f64;
        // Saturation is 0.5 * fy, so by halving the height we save operations.
        let saturation = (y - rect[1]) as f64 * half_inv_rect_height;
        let hi = (hue * inv60) as int;
        let f = hue * inv60 - hi as f64;
        let hi = hi % 6;
        let v = 255; // use white as color without saturation.
        let p = (255.0 * (1.0 - saturation)) as u8;
        let q = (255.0 * (1.0 - f * saturation)) as u8;
        let t = (255.0 * (1.0 - (1.0 - f) * saturation)) as u8;
        *pxl = Rgba([
            match hi {
                0 | 1 => p,
                2 => t,
                3 | 4 => v,
                _ => q
            },
            match hi {
                0 => t,
                1 | 2 => v,
                3 => q,
                _ => p
            },
            match hi {
                1 => q,
                2 | 3 => p,
                4 => t,
                _ => v
            },
            255
        ]);
    }
}
<commit_msg>Using ImageBuffer directly<commit_after>
//! Helper functions for hue and saturation selection

use image::{
    GenericImage,
    Rgba,
    RgbaImage,
};

/// Selects color at coordinate in a rectangle show hue and saturation
pub fn select(rect: [u32, ..4], x: u32, y: u32) -> Rgba<u8> {
    let inv_rect_width = 1.0_f64 / rect[2] as f64;
    let half_inv_rect_height = 0.5_f64 / rect[3] as f64;
    let inv60 = 1.0_f64 / 60.0_f64;

    let fx = (x - rect[0]) as f64 * inv_rect_width;
    let hue = fx * 360.0_f64;
    // Saturation is 0.5 * fy, so by halving the height we save operations.
    let saturation = (y - rect[1]) as f64 * half_inv_rect_height;
    let hi = (hue * inv60) as int;
    let f = hue * inv60 - hi as f64;
    let hi = hi % 6;
    let v = 255; // use white as color without saturation.
    let p = (255.0 * (1.0 - saturation)) as u8;
    let q = (255.0 * (1.0 - f * saturation)) as u8;
    let t = (255.0 * (1.0 - (1.0 - f) * saturation)) as u8;
    Rgba([
        match hi {
            0 | 1 => p,
            2 => t,
            3 | 4 => v,
            _ => q
        },
        match hi {
            0 => t,
            1 | 2 => v,
            3 => q,
            _ => p
        },
        match hi {
            1 => q,
            2 | 3 => p,
            4 => t,
            _ => v
        },
        255
    ])
}

/// Sets colors to hue/saturation image.
/// White is used as color without saturation.
/// This is at the top of the image,
/// while saturated colors are at the bottom.
pub fn fill_image(
    image: &mut RgbaImage,
    rect: [u32, ..4]
) {
    let inv_rect_width = 1.0_f64 / rect[2] as f64;
    let half_inv_rect_height = 0.5_f64 / rect[3] as f64;
    let inv60 = 1.0_f64 / 60.0_f64;
    for x in range(rect[0], rect[0] + rect[2]) {
        for y in range(rect[1], rect[1] + rect[3]) {
            let fx = (x - rect[0]) as f64 * inv_rect_width;
            let hue = fx * 360.0_f64;
            // Saturation is 0.5 * fy, so by halving the height we save operations.
            let saturation = (y - rect[1]) as f64 * half_inv_rect_height;
            let hi = (hue * inv60) as int;
            let f = hue * inv60 - hi as f64;
            let hi = hi % 6;
            let v = 255; // use white as color without saturation.
            let p = (255.0 * (1.0 - saturation)) as u8;
            let q = (255.0 * (1.0 - f * saturation)) as u8;
            let t = (255.0 * (1.0 - (1.0 - f) * saturation)) as u8;
            *image.get_pixel_mut(x, y) = Rgba([
                match hi {
                    0 | 1 => p,
                    2 => t,
                    3 | 4 => v,
                    _ => q
                },
                match hi {
                    0 => t,
                    1 | 2 => v,
                    3 => q,
                    _ => p
                },
                match hi {
                    1 => q,
                    2 | 3 => p,
                    4 => t,
                    _ => v
                },
                255
            ]);
        }
    }
}
<|endoftext|>


<commit_before>use crate::bindings;
use crate::instance::Instance;
use failure::{format_err, Error, Fail};
use lucet;
use lucet::{UntypedRetval, Val};
use lucetc::{
    compile,
    error::{LucetcError, LucetcErrorKind},
    program::{HeapSettings, Program},
};
use parity_wasm::{self, deserialize_buffer};
use std::io;
use std::process::Command;
use tempdir::TempDir;

#[derive(Fail, Debug)]
pub enum ScriptError {
    #[fail(display = "Deserialization error: {}", _0)]
    DeserializeError(parity_wasm::elements::Error),
    #[fail(display = "Validation error: {}", _0)]
    ValidationError(LucetcError),
    #[fail(display = "Program creation error: {}", _0)]
    ProgramError(LucetcError),
    #[fail(display = "Compilation error: {}", _0)]
    CompileError(LucetcError),
    #[fail(display = "Codegen error: {}", _0)]
    CodegenError(Error),
    #[fail(display = "Load error: {}", _0)]
    LoadError(lucet::LucetError),
    #[fail(display = "Instaitiation error: {}", _0)]
    InstantiateError(lucet::LucetError),
    #[fail(display = "Runtime error: {}", _0)]
    RuntimeError(lucet::LucetError),
    #[fail(display = "Malformed script: {}", _0)]
    MalformedScript(String),
    #[fail(display = "IO error: {}", _0)]
    IoError(io::Error),
}

impl ScriptError {
    pub fn unsupported(&self) -> bool {
        match self {
            ScriptError::ProgramError(ref lucetc_err)
            | ScriptError::CompileError(ref lucetc_err) => match lucetc_err.get_context() {
                &LucetcErrorKind::Unsupported(_) => true,
                _ => false,
            },
            _ => false,
        }
    }
}

impl From<io::Error> for ScriptError {
    fn from(e: io::Error) -> ScriptError {
        ScriptError::IoError(e)
    }
}

pub struct ScriptEnv {
    instances: Vec<(Option<String>, Instance)>,
}

fn program_error(e: LucetcError) -> ScriptError {
    match e.get_context() {
        LucetcErrorKind::Validation => ScriptError::ValidationError(e),
        _ => ScriptError::ProgramError(e),
    }
}

impl ScriptEnv {
    pub fn new() -> Self {
        Self {
            instances: Vec::new(),
        }
    }
    pub fn instantiate(
        &mut self,
        module: Vec<u8>,
        name: &Option<String>,
    ) -> Result<(), ScriptError> {
        let bindings = bindings::spec_test_bindings();

        let module = deserialize_buffer(&module).map_err(ScriptError::DeserializeError)?;

        let program =
            Program::new(module, bindings, HeapSettings::default()).map_err(program_error)?;

        let dir = TempDir::new("codegen")?;
        let objfile_path = dir.path().join("a.o");
        let sofile_path = dir.path().join("a.so");

        {
            let compiler = compile(&program, &name.clone().unwrap_or("default".to_owned()))
                .map_err(ScriptError::CompileError)?;

            let object = compiler.codegen().map_err(ScriptError::CodegenError)?;

            object
                .write(&objfile_path)
                .map_err(ScriptError::CodegenError)?;
        }

        let mut cmd_ld = Command::new("ld");
        cmd_ld.arg(objfile_path.clone());
        cmd_ld.arg("-shared");
        cmd_ld.arg("-o");
        cmd_ld.arg(sofile_path.clone());
        let run_ld = cmd_ld.output()?;
        if !run_ld.status.success() {
            Err(ScriptError::CodegenError(format_err!(
                "ld {:?}: {}",
                objfile_path,
                String::from_utf8_lossy(&run_ld.stderr)
            )))?;
        }

        let lucet_module = lucet::Module::from_file(sofile_path).map_err(ScriptError::LoadError)?;

        let mut lucet_pool = lucet::Pool::builder()
            .entries(1)
            .build()
            .expect("valid pool");

        let lucet_instance = lucet::Instance::new(&mut lucet_pool, &lucet_module)
            .map_err(ScriptError::InstantiateError)?;

        self.instances.push((
            name.clone(),
            Instance::new(program, lucet_module, lucet_pool, lucet_instance),
        ));
        Ok(())
    }

    fn instance_named_mut(
        &mut self,
        name: &Option<String>,
    ) -> Result<&mut (Option<String>, Instance), ScriptError> {
        Ok(match name {
            // None means the last defined module should be used
            None => self
                .instances
                .last_mut()
                .ok_or_else(|| ScriptError::MalformedScript("no defined instances".to_owned()))?,
            Some(ref n) => self
                .instances
                .iter_mut()
                .find(|(iname, _)| *iname == *name)
                .ok_or_else(|| ScriptError::MalformedScript(format!("no instance named {}", n)))?,
        })
    }

    pub fn instance_named(&self, name: &Option<String>) -> Result<&Instance, ScriptError> {
        Ok(match name {
            // None means the last defined module should be used
            None => self
                .instances
                .last()
                .map(|(_fst, snd)| snd)
                .ok_or_else(|| ScriptError::MalformedScript("no defined instances".to_owned()))?,
            Some(ref n) => self
                .instances
                .iter()
                .find(|(iname, _)| *iname == *name)
                .map(|(_fst, snd)| snd)
                .ok_or_else(|| ScriptError::MalformedScript(format!("no instance named {}", n)))?,
        })
    }

    pub fn run(
        &mut self,
        name: &Option<String>,
        field: &str,
        args: Vec<Val>,
    ) -> Result<UntypedRetval, ScriptError> {
        let (_, ref mut inst) = self.instance_named_mut(name)?;
        inst.run(&field, &args)
            .map_err(|e| ScriptError::RuntimeError(e))
    }

    pub fn register(&mut self, name: &Option<String>, as_name: &str) -> Result<(), ScriptError> {
        let (ref mut oldname, _) = self.instance_named_mut(name)?;
        *oldname = Some(as_name.to_owned());
        Ok(())
    }

    pub fn delete_last(&mut self) {
        let last_index = self.instances.len() - 1;
        self.instances.remove(last_index);
    }
}
<commit_msg>Update spectest to include the opt level in the compile call.<commit_after>use crate::bindings;
use crate::instance::Instance;
use failure::{format_err, Error, Fail};
use lucet;
use lucet::{UntypedRetval, Val};
use lucetc::{
    compile,
    compiler::OptLevel,
    error::{LucetcError, LucetcErrorKind},
    program::{HeapSettings, Program},
};
use parity_wasm::{self, deserialize_buffer};
use std::io;
use std::process::Command;
use tempdir::TempDir;

#[derive(Fail, Debug)]
pub enum ScriptError {
    #[fail(display = "Deserialization error: {}", _0)]
    DeserializeError(parity_wasm::elements::Error),
    #[fail(display = "Validation error: {}", _0)]
    ValidationError(LucetcError),
    #[fail(display = "Program creation error: {}", _0)]
    ProgramError(LucetcError),
    #[fail(display = "Compilation error: {}", _0)]
    CompileError(LucetcError),
    #[fail(display = "Codegen error: {}", _0)]
    CodegenError(Error),
    #[fail(display = "Load error: {}", _0)]
    LoadError(lucet::LucetError),
    #[fail(display = "Instaitiation error: {}", _0)]
    InstantiateError(lucet::LucetError),
    #[fail(display = "Runtime error: {}", _0)]
    RuntimeError(lucet::LucetError),
    #[fail(display = "Malformed script: {}", _0)]
    MalformedScript(String),
    #[fail(display = "IO error: {}", _0)]
    IoError(io::Error),
}

impl ScriptError {
    pub fn unsupported(&self) -> bool {
        match self {
            ScriptError::ProgramError(ref lucetc_err)
            | ScriptError::CompileError(ref lucetc_err) => match lucetc_err.get_context() {
                &LucetcErrorKind::Unsupported(_) => true,
                _ => false,
            },
            _ => false,
        }
    }
}

impl From<io::Error> for ScriptError {
    fn from(e: io::Error) -> ScriptError {
        ScriptError::IoError(e)
    }
}

pub struct ScriptEnv {
    instances: Vec<(Option<String>, Instance)>,
}

fn program_error(e: LucetcError) -> ScriptError {
    match e.get_context() {
        LucetcErrorKind::Validation => ScriptError::ValidationError(e),
        _ => ScriptError::ProgramError(e),
    }
}

impl ScriptEnv {
    pub fn new() -> Self {
        Self {
            instances: Vec::new(),
        }
    }
    pub fn instantiate(
        &mut self,
        module: Vec<u8>,
        name: &Option<String>,
    ) -> Result<(), ScriptError> {
        let bindings = bindings::spec_test_bindings();

        let module = deserialize_buffer(&module).map_err(ScriptError::DeserializeError)?;

        let program =
            Program::new(module, bindings, HeapSettings::default()).map_err(program_error)?;

        let dir = TempDir::new("codegen")?;
        let objfile_path = dir.path().join("a.o");
        let sofile_path = dir.path().join("a.so");

        {
            let compiler = compile(
                &program,
                &name.clone().unwrap_or("default".to_owned()),
                OptLevel::Default,
            )
            .map_err(ScriptError::CompileError)?;

            let object = compiler.codegen().map_err(ScriptError::CodegenError)?;

            object
                .write(&objfile_path)
                .map_err(ScriptError::CodegenError)?;
        }

        let mut cmd_ld = Command::new("ld");
        cmd_ld.arg(objfile_path.clone());
        cmd_ld.arg("-shared");
        cmd_ld.arg("-o");
        cmd_ld.arg(sofile_path.clone());
        let run_ld = cmd_ld.output()?;
        if !run_ld.status.success() {
            Err(ScriptError::CodegenError(format_err!(
                "ld {:?}: {}",
                objfile_path,
                String::from_utf8_lossy(&run_ld.stderr)
            )))?;
        }

        let lucet_module = lucet::Module::from_file(sofile_path).map_err(ScriptError::LoadError)?;

        let mut lucet_pool = lucet::Pool::builder()
            .entries(1)
            .build()
            .expect("valid pool");

        let lucet_instance = lucet::Instance::new(&mut lucet_pool, &lucet_module)
            .map_err(ScriptError::InstantiateError)?;

        self.instances.push((
            name.clone(),
            Instance::new(program, lucet_module, lucet_pool, lucet_instance),
        ));
        Ok(())
    }

    fn instance_named_mut(
        &mut self,
        name: &Option<String>,
    ) -> Result<&mut (Option<String>, Instance), ScriptError> {
        Ok(match name {
            // None means the last defined module should be used
            None => self
                .instances
                .last_mut()
                .ok_or_else(|| ScriptError::MalformedScript("no defined instances".to_owned()))?,
            Some(ref n) => self
                .instances
                .iter_mut()
                .find(|(iname, _)| *iname == *name)
                .ok_or_else(|| ScriptError::MalformedScript(format!("no instance named {}", n)))?,
        })
    }

    pub fn instance_named(&self, name: &Option<String>) -> Result<&Instance, ScriptError> {
        Ok(match name {
            // None means the last defined module should be used
            None => self
                .instances
                .last()
                .map(|(_fst, snd)| snd)
                .ok_or_else(|| ScriptError::MalformedScript("no defined instances".to_owned()))?,
            Some(ref n) => self
                .instances
                .iter()
                .find(|(iname, _)| *iname == *name)
                .map(|(_fst, snd)| snd)
                .ok_or_else(|| ScriptError::MalformedScript(format!("no instance named {}", n)))?,
        })
    }

    pub fn run(
        &mut self,
        name: &Option<String>,
        field: &str,
        args: Vec<Val>,
    ) -> Result<UntypedRetval, ScriptError> {
        let (_, ref mut inst) = self.instance_named_mut(name)?;
        inst.run(&field, &args)
            .map_err(|e| ScriptError::RuntimeError(e))
    }

    pub fn register(&mut self, name: &Option<String>, as_name: &str) -> Result<(), ScriptError> {
        let (ref mut oldname, _) = self.instance_named_mut(name)?;
        *oldname = Some(as_name.to_owned());
        Ok(())
    }

    pub fn delete_last(&mut self) {
        let last_index = self.instances.len() - 1;
        self.instances.remove(last_index);
    }
}
<|endoftext|>