<commit_before>extern crate config;
extern crate serde_derive;

use config::*;
use serde_derive::Deserialize;
use std::env;

/// Reminder that tests using env variables need to use different env variable names, since
/// tests can be run in parallel

#[test]
fn test_default() {
    env::set_var("A_B_C", "abc");

    let environment = Environment::new();

    assert!(environment.collect().unwrap().contains_key("a_b_c"));

    env::remove_var("A_B_C");
}

#[test]
fn test_prefix_is_removed_from_key() {
    env::set_var("B_A_C", "abc");

    let environment = Environment::with_prefix("B");

    assert!(environment.collect().unwrap().contains_key("a_c"));

    env::remove_var("B_A_C");
}

#[test]
fn test_prefix_with_variant_forms_of_spelling() {
    env::set_var("a_A_C", "abc");

    let environment = Environment::with_prefix("a");

    assert!(environment.collect().unwrap().contains_key("a_c"));

    env::remove_var("a_A_C");
    env::set_var("aB_A_C", "abc");

    let environment = Environment::with_prefix("aB");

    assert!(environment.collect().unwrap().contains_key("a_c"));

    env::remove_var("aB_A_C");
    env::set_var("Ab_A_C", "abc");

    let environment = Environment::with_prefix("ab");

    assert!(environment.collect().unwrap().contains_key("a_c"));

    env::remove_var("Ab_A_C");
}

#[test]
fn test_separator_behavior() {
    env::set_var("C_B_A", "abc");

    let environment = Environment::with_prefix("C").separator("_");

    assert!(environment.collect().unwrap().contains_key("b.a"));

    env::remove_var("C_B_A");
}

#[test]
fn test_empty_value_is_ignored() {
    env::set_var("C_A_B", "");

    let environment = Environment::new().ignore_empty(true);

    assert!(!environment.collect().unwrap().contains_key("c_a_b"));

    env::remove_var("C_A_B");
}

#[test]
fn test_custom_separator_behavior() {
    env::set_var("C.B.A", "abc");

    let environment = Environment::with_prefix("C").separator(".");

    assert!(environment.collect().unwrap().contains_key("b.a"));

    env::remove_var("C.B.A");
}

#[test]
fn test_parse_int() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestIntEnum {
        Int(TestInt),
    }

    #[derive(Deserialize, Debug)]
    struct TestInt {
        int_val: i32,
    }

    env::set_var("INT_VAL", "42");

    let environment = Environment::new().try_parsing(true);

    let config = Config::builder()
        .set_default("tag", "Int")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    let config: TestIntEnum = config.try_into().unwrap();

    assert!(matches!(config, TestIntEnum::Int(TestInt { int_val: 42 })));

    env::remove_var("INT_VAL");
}

#[test]
fn test_parse_float() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestFloatEnum {
        Float(TestFloat),
    }

    #[derive(Deserialize, Debug)]
    struct TestFloat {
        float_val: f64,
    }

    env::set_var("FLOAT_VAL", "42.3");

    let environment = Environment::new().try_parsing(true);

    let config = Config::builder()
        .set_default("tag", "Float")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    let config: TestFloatEnum = config.try_into().unwrap();

    // can't use `matches!` because of float value
    match config {
        TestFloatEnum::Float(TestFloat { float_val }) => assert_eq!(float_val, 42.3),
    }

    env::remove_var("FLOAT_VAL");
}

#[test]
fn test_parse_bool() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestBoolEnum {
        Bool(TestBool),
    }

    #[derive(Deserialize, Debug)]
    struct TestBool {
        bool_val: bool,
    }

    env::set_var("BOOL_VAL", "true");

    let environment = Environment::new().try_parsing(true);

    let config = Config::builder()
        .set_default("tag", "Bool")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    let config: TestBoolEnum = config.try_into().unwrap();

    assert!(matches!(
        config,
        TestBoolEnum::Bool(TestBool { bool_val: true }),
    ));

    env::remove_var("BOOL_VAL");
}

#[test]
#[should_panic(expected = "invalid type: string \"42\", expected i32")]
fn test_parse_off_int() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestIntEnum {
        Int(TestInt),
    }

    #[derive(Deserialize, Debug)]
    struct TestInt {
        int_val_1: i32,
    }

    env::set_var("INT_VAL_1", "42");

    let environment = Environment::new().try_parsing(false);

    let config = Config::builder()
        .set_default("tag", "Int")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    env::remove_var("INT_VAL_1");

    config.try_into::<TestIntEnum>().unwrap();
}

#[test]
#[should_panic(expected = "invalid type: string \"42.3\", expected f64")]
fn test_parse_off_float() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestFloatEnum {
        Float(TestFloat),
    }

    #[derive(Deserialize, Debug)]
    struct TestFloat {
        float_val_1: f64,
    }

    env::set_var("FLOAT_VAL_1", "42.3");

    let environment = Environment::new().try_parsing(false);

    let config = Config::builder()
        .set_default("tag", "Float")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    env::remove_var("FLOAT_VAL_1");

    config.try_into::<TestFloatEnum>().unwrap();
}

#[test]
#[should_panic(expected = "invalid type: string \"true\", expected a boolean")]
fn test_parse_off_bool() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestBoolEnum {
        Bool(TestBool),
    }

    #[derive(Deserialize, Debug)]
    struct TestBool {
        bool_val_1: bool,
    }

    env::set_var("BOOL_VAL_1", "true");

    let environment = Environment::new().try_parsing(false);

    let config = Config::builder()
        .set_default("tag", "Bool")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    env::remove_var("BOOL_VAL_1");

    config.try_into::<TestBoolEnum>().unwrap();
}

#[test]
#[should_panic(expected = "invalid type: string \"not an int\", expected i32")]
fn test_parse_int_fail() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestIntEnum {
        Int(TestInt),
    }

    #[derive(Deserialize, Debug)]
    struct TestInt {
        int_val_2: i32,
    }

    env::set_var("INT_VAL_2", "not an int");

    let environment = Environment::new().try_parsing(true);

    let config = Config::builder()
        .set_default("tag", "Int")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    env::remove_var("INT_VAL_2");

    config.try_into::<TestIntEnum>().unwrap();
}

#[test]
#[should_panic(expected = "invalid type: string \"not a float\", expected f64")]
fn test_parse_float_fail() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestFloatEnum {
        Float(TestFloat),
    }

    #[derive(Deserialize, Debug)]
    struct TestFloat {
        float_val_2: f64,
    }

    env::set_var("FLOAT_VAL_2", "not a float");

    let environment = Environment::new().try_parsing(true);

    let config = Config::builder()
        .set_default("tag", "Float")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    env::remove_var("FLOAT_VAL_2");

    config.try_into::<TestFloatEnum>().unwrap();
}

#[test]
#[should_panic(expected = "invalid type: string \"not a bool\", expected a boolean")]
fn test_parse_bool_fail() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestBoolEnum {
        Bool(TestBool),
    }

    #[derive(Deserialize, Debug)]
    struct TestBool {
        bool_val_2: bool,
    }

    env::set_var("BOOL_VAL_2", "not a bool");

    let environment = Environment::new().try_parsing(true);

    let config = Config::builder()
        .set_default("tag", "Bool")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    env::remove_var("BOOL_VAL_2");

    config.try_into::<TestBoolEnum>().unwrap();
}

#[test]
fn test_parse_string() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestStringEnum {
        String(TestString),
    }

    #[derive(Deserialize, Debug)]
    struct TestString {
        string_val: String,
    }

    env::set_var("STRING_VAL", "test string");

    let environment = Environment::new().try_parsing(true);

    let config = Config::builder()
        .set_default("tag", "String")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    let config: TestStringEnum = config.try_into().unwrap();

    let test_string = String::from("test string");

    match config {
        TestStringEnum::String(TestString { string_val }) => assert_eq!(test_string, string_val),
    }

    env::remove_var("STRING_VAL");
}

#[test]
fn test_parse_off_string() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestStringEnum {
        String(TestString),
    }

    #[derive(Deserialize, Debug)]
    struct TestString {
        string_val_1: String,
    }

    env::set_var("STRING_VAL_1", "test string");

    let environment = Environment::new().try_parsing(false);

    let config = Config::builder()
        .set_default("tag", "String")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    let config: TestStringEnum = config.try_into().unwrap();

    let test_string = String::from("test string");

    match config {
        TestStringEnum::String(TestString { string_val_1 }) => {
            assert_eq!(test_string, string_val_1)
        }
    }

    env::remove_var("STRING_VAL_1");
}
<commit_msg>Fix: Remove trailing comma<commit_after>extern crate config;
extern crate serde_derive;

use config::*;
use serde_derive::Deserialize;
use std::env;

/// Reminder that tests using env variables need to use different env variable names, since
/// tests can be run in parallel

#[test]
fn test_default() {
    env::set_var("A_B_C", "abc");

    let environment = Environment::new();

    assert!(environment.collect().unwrap().contains_key("a_b_c"));

    env::remove_var("A_B_C");
}

#[test]
fn test_prefix_is_removed_from_key() {
    env::set_var("B_A_C", "abc");

    let environment = Environment::with_prefix("B");

    assert!(environment.collect().unwrap().contains_key("a_c"));

    env::remove_var("B_A_C");
}

#[test]
fn test_prefix_with_variant_forms_of_spelling() {
    env::set_var("a_A_C", "abc");

    let environment = Environment::with_prefix("a");

    assert!(environment.collect().unwrap().contains_key("a_c"));

    env::remove_var("a_A_C");
    env::set_var("aB_A_C", "abc");

    let environment = Environment::with_prefix("aB");

    assert!(environment.collect().unwrap().contains_key("a_c"));

    env::remove_var("aB_A_C");
    env::set_var("Ab_A_C", "abc");

    let environment = Environment::with_prefix("ab");

    assert!(environment.collect().unwrap().contains_key("a_c"));

    env::remove_var("Ab_A_C");
}

#[test]
fn test_separator_behavior() {
    env::set_var("C_B_A", "abc");

    let environment = Environment::with_prefix("C").separator("_");

    assert!(environment.collect().unwrap().contains_key("b.a"));

    env::remove_var("C_B_A");
}

#[test]
fn test_empty_value_is_ignored() {
    env::set_var("C_A_B", "");

    let environment = Environment::new().ignore_empty(true);

    assert!(!environment.collect().unwrap().contains_key("c_a_b"));

    env::remove_var("C_A_B");
}

#[test]
fn test_custom_separator_behavior() {
    env::set_var("C.B.A", "abc");

    let environment = Environment::with_prefix("C").separator(".");

    assert!(environment.collect().unwrap().contains_key("b.a"));

    env::remove_var("C.B.A");
}

#[test]
fn test_parse_int() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestIntEnum {
        Int(TestInt),
    }

    #[derive(Deserialize, Debug)]
    struct TestInt {
        int_val: i32,
    }

    env::set_var("INT_VAL", "42");

    let environment = Environment::new().try_parsing(true);

    let config = Config::builder()
        .set_default("tag", "Int")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    let config: TestIntEnum = config.try_into().unwrap();

    assert!(matches!(config, TestIntEnum::Int(TestInt { int_val: 42 })));

    env::remove_var("INT_VAL");
}

#[test]
fn test_parse_float() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestFloatEnum {
        Float(TestFloat),
    }

    #[derive(Deserialize, Debug)]
    struct TestFloat {
        float_val: f64,
    }

    env::set_var("FLOAT_VAL", "42.3");

    let environment = Environment::new().try_parsing(true);

    let config = Config::builder()
        .set_default("tag", "Float")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    let config: TestFloatEnum = config.try_into().unwrap();

    // can't use `matches!` because of float value
    match config {
        TestFloatEnum::Float(TestFloat { float_val }) => assert_eq!(float_val, 42.3),
    }

    env::remove_var("FLOAT_VAL");
}

#[test]
fn test_parse_bool() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestBoolEnum {
        Bool(TestBool),
    }

    #[derive(Deserialize, Debug)]
    struct TestBool {
        bool_val: bool,
    }

    env::set_var("BOOL_VAL", "true");

    let environment = Environment::new().try_parsing(true);

    let config = Config::builder()
        .set_default("tag", "Bool")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    let config: TestBoolEnum = config.try_into().unwrap();

    assert!(matches!(
        config,
        TestBoolEnum::Bool(TestBool { bool_val: true })
    ));

    env::remove_var("BOOL_VAL");
}

#[test]
#[should_panic(expected = "invalid type: string \"42\", expected i32")]
fn test_parse_off_int() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestIntEnum {
        Int(TestInt),
    }

    #[derive(Deserialize, Debug)]
    struct TestInt {
        int_val_1: i32,
    }

    env::set_var("INT_VAL_1", "42");

    let environment = Environment::new().try_parsing(false);

    let config = Config::builder()
        .set_default("tag", "Int")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    env::remove_var("INT_VAL_1");

    config.try_into::<TestIntEnum>().unwrap();
}

#[test]
#[should_panic(expected = "invalid type: string \"42.3\", expected f64")]
fn test_parse_off_float() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestFloatEnum {
        Float(TestFloat),
    }

    #[derive(Deserialize, Debug)]
    struct TestFloat {
        float_val_1: f64,
    }

    env::set_var("FLOAT_VAL_1", "42.3");

    let environment = Environment::new().try_parsing(false);

    let config = Config::builder()
        .set_default("tag", "Float")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    env::remove_var("FLOAT_VAL_1");

    config.try_into::<TestFloatEnum>().unwrap();
}

#[test]
#[should_panic(expected = "invalid type: string \"true\", expected a boolean")]
fn test_parse_off_bool() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestBoolEnum {
        Bool(TestBool),
    }

    #[derive(Deserialize, Debug)]
    struct TestBool {
        bool_val_1: bool,
    }

    env::set_var("BOOL_VAL_1", "true");

    let environment = Environment::new().try_parsing(false);

    let config = Config::builder()
        .set_default("tag", "Bool")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    env::remove_var("BOOL_VAL_1");

    config.try_into::<TestBoolEnum>().unwrap();
}

#[test]
#[should_panic(expected = "invalid type: string \"not an int\", expected i32")]
fn test_parse_int_fail() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestIntEnum {
        Int(TestInt),
    }

    #[derive(Deserialize, Debug)]
    struct TestInt {
        int_val_2: i32,
    }

    env::set_var("INT_VAL_2", "not an int");

    let environment = Environment::new().try_parsing(true);

    let config = Config::builder()
        .set_default("tag", "Int")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    env::remove_var("INT_VAL_2");

    config.try_into::<TestIntEnum>().unwrap();
}

#[test]
#[should_panic(expected = "invalid type: string \"not a float\", expected f64")]
fn test_parse_float_fail() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestFloatEnum {
        Float(TestFloat),
    }

    #[derive(Deserialize, Debug)]
    struct TestFloat {
        float_val_2: f64,
    }

    env::set_var("FLOAT_VAL_2", "not a float");

    let environment = Environment::new().try_parsing(true);

    let config = Config::builder()
        .set_default("tag", "Float")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    env::remove_var("FLOAT_VAL_2");

    config.try_into::<TestFloatEnum>().unwrap();
}

#[test]
#[should_panic(expected = "invalid type: string \"not a bool\", expected a boolean")]
fn test_parse_bool_fail() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestBoolEnum {
        Bool(TestBool),
    }

    #[derive(Deserialize, Debug)]
    struct TestBool {
        bool_val_2: bool,
    }

    env::set_var("BOOL_VAL_2", "not a bool");

    let environment = Environment::new().try_parsing(true);

    let config = Config::builder()
        .set_default("tag", "Bool")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    env::remove_var("BOOL_VAL_2");

    config.try_into::<TestBoolEnum>().unwrap();
}

#[test]
fn test_parse_string() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestStringEnum {
        String(TestString),
    }

    #[derive(Deserialize, Debug)]
    struct TestString {
        string_val: String,
    }

    env::set_var("STRING_VAL", "test string");

    let environment = Environment::new().try_parsing(true);

    let config = Config::builder()
        .set_default("tag", "String")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    let config: TestStringEnum = config.try_into().unwrap();

    let test_string = String::from("test string");

    match config {
        TestStringEnum::String(TestString { string_val }) => assert_eq!(test_string, string_val),
    }

    env::remove_var("STRING_VAL");
}

#[test]
fn test_parse_off_string() {
    // using a struct in an enum here to make serde use `deserialize_any`
    #[derive(Deserialize, Debug)]
    #[serde(tag = "tag")]
    enum TestStringEnum {
        String(TestString),
    }

    #[derive(Deserialize, Debug)]
    struct TestString {
        string_val_1: String,
    }

    env::set_var("STRING_VAL_1", "test string");

    let environment = Environment::new().try_parsing(false);

    let config = Config::builder()
        .set_default("tag", "String")
        .unwrap()
        .add_source(environment)
        .build()
        .unwrap();

    let config: TestStringEnum = config.try_into().unwrap();

    let test_string = String::from("test string");

    match config {
        TestStringEnum::String(TestString { string_val_1 }) => {
            assert_eq!(test_string, string_val_1)
        }
    }

    env::remove_var("STRING_VAL_1");
}
<|endoftext|>


<commit_before>#![feature(globs,macro_rules,phase)]

#[phase(plugin,link)]
extern crate nom;

use nom::{IResult,Producer,FileProducer,ProducerState,FlatMapper,Mapper,Mapper2,line_ending,not_line_ending, space, alphanumeric, is_alphanumeric};
use nom::IResult::*;

use std::str;
use std::fmt::Show;

fn empty_result(i:&[u8]) -> IResult<&[u8], ()> { Done(i,()) }
tag!(semicolon ";".as_bytes());
o!(comment_body<&[u8],&[u8]> semicolon ~ not_line_ending ~ );
o!(comment<&[u8], ()> comment_body line_ending ~ empty_result ~);
opt!(opt_comment<&[u8],&[u8]> comment_body);

tag!(lsb "[".as_bytes());
tag!(rsb "]".as_bytes());
fn category_name(input:&[u8]) -> IResult<&[u8], &str> {
  for idx in range(0, input.len()) {
    if input[idx] == ']' as u8 {
      return Done(input.slice_from(idx), input.slice(0, idx)).map_res(str::from_utf8)
    }
  }
  Done("".as_bytes(), input).map_res(str::from_utf8)
}
o!(category<&[u8], &str> lsb ~ category_name ~ rsb line_ending);

tag!(equal "=".as_bytes());
fn not_equal(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if input[idx] == '=' as u8 {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

fn value_parser(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if input[idx] == '\n' as u8 || input[idx] == ';' as u8 {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

opt!(opt_line_ending<&[u8],&[u8]> line_ending);
o!(value<&[u8],&[u8]> space equal space ~ value_parser ~ space opt_comment opt_line_ending);
chain!(key_value<&[u8],(&[u8],&[u8])>, ||{(key, val)},  key: alphanumeric, val: value,);

#[test]
fn parse_comment_test() {
  let ini_file = ";comment
[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let ini_without_comment = "[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let res = Done((), ini_file.as_bytes()).flat_map(comment);
  println!("{}", res);
  match res {
    IResult::Done(i, o) => println!("i: {} | o: {}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_comment.as_bytes(), ()));
}

#[test]
fn parse_category_test() {
  let ini_file = "[category]
parameter=value
key = value2";

  let ini_without_category = "parameter=value
key = value2";

  let res = Done((), ini_file.as_bytes()).flat_map(category);
  println!("{}", res);
  match res {
    IResult::Done(i, o) => println!("i: {} | o: {}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_category.as_bytes(), "category"));
}

#[test]
fn parse_key_value_test() {
  let ini_file = "parameter=value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = Done((), ini_file.as_bytes()).flat_map(key_value);
  println!("{}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {} | o: ({},{})", str::from_utf8(i), str::from_utf8(o1), str::from_utf8(o2)),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter".as_bytes(), "value".as_bytes())));
}

#[test]
fn parse_key_value_with_space_test() {
  let ini_file = "parameter = value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = Done((), ini_file.as_bytes()).flat_map(key_value);
  println!("{}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {} | o: ({},{})", str::from_utf8(i), str::from_utf8(o1), str::from_utf8(o2)),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter".as_bytes(), "value".as_bytes())));
}

#[test]
fn parse_key_value_with_comment_test() {
  let ini_file = "parameter=value;abc
key = value2";

  let ini_without_key_value = "key = value2";

  let res = Done((), ini_file.as_bytes()).flat_map(key_value);
  println!("{}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {} | o: ({},{})", str::from_utf8(i), str::from_utf8(o1), str::from_utf8(o2)),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter".as_bytes(), "value".as_bytes())));
}
<commit_msg>parse keys and values as text<commit_after>#![feature(globs,macro_rules,phase)]

#[phase(plugin,link)]
extern crate nom;

use nom::{IResult,Producer,FileProducer,ProducerState,FlatMapper,Mapper,Mapper2,line_ending,not_line_ending, space, alphanumeric, is_alphanumeric};
use nom::IResult::*;

use std::str;
use std::fmt::Show;

fn empty_result(i:&[u8]) -> IResult<&[u8], ()> { Done(i,()) }
tag!(semicolon ";".as_bytes());
o!(comment_body<&[u8],&[u8]> semicolon ~ not_line_ending ~ );
o!(comment<&[u8], ()> comment_body line_ending ~ empty_result ~);
opt!(opt_comment<&[u8],&[u8]> comment_body);

tag!(lsb "[".as_bytes());
tag!(rsb "]".as_bytes());
fn category_name(input:&[u8]) -> IResult<&[u8], &str> {
  for idx in range(0, input.len()) {
    if input[idx] == ']' as u8 {
      return Done(input.slice_from(idx), input.slice(0, idx)).map_res(str::from_utf8)
    }
  }
  Done("".as_bytes(), input).map_res(str::from_utf8)
}
o!(category<&[u8], &str> lsb ~ category_name ~ rsb line_ending);

tag!(equal "=".as_bytes());
fn not_equal(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if input[idx] == '=' as u8 {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

fn value_parser(input:&[u8]) -> IResult<&[u8], &str> {
  for idx in range(0, input.len()) {
    if input[idx] == '\n' as u8 || input[idx] == ';' as u8 {
      return Done(input.slice_from(idx), input.slice(0, idx)).map_res(str::from_utf8)
    }
  }
  Done("".as_bytes(), input).map_res(str::from_utf8)
}

fn parameter_parser(input: &[u8]) -> IResult<&[u8], &str> {
  alphanumeric(input).map_res(str::from_utf8)
}

opt!(opt_line_ending<&[u8],&[u8]> line_ending);
o!(value<&[u8],&str> space equal space ~ value_parser ~ space opt_comment opt_line_ending);
chain!(key_value<&[u8],(&str,&str)>, ||{(key, val)},  key: parameter_parser, val: value,);

#[test]
fn parse_comment_test() {
  let ini_file = ";comment
[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let ini_without_comment = "[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let res = Done((), ini_file.as_bytes()).flat_map(comment);
  println!("{}", res);
  match res {
    IResult::Done(i, o) => println!("i: {} | o: {}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_comment.as_bytes(), ()));
}

#[test]
fn parse_category_test() {
  let ini_file = "[category]
parameter=value
key = value2";

  let ini_without_category = "parameter=value
key = value2";

  let res = Done((), ini_file.as_bytes()).flat_map(category);
  println!("{}", res);
  match res {
    IResult::Done(i, o) => println!("i: {} | o: {}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_category.as_bytes(), "category"));
}

#[test]
fn parse_key_value_test() {
  let ini_file = "parameter=value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = Done((), ini_file.as_bytes()).flat_map(key_value);
  println!("{}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {} | o: ({},{})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_key_value_with_space_test() {
  let ini_file = "parameter = value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = Done((), ini_file.as_bytes()).flat_map(key_value);
  println!("{}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {} | o: ({},{})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_key_value_with_comment_test() {
  let ini_file = "parameter=value;abc
key = value2";

  let ini_without_key_value = "key = value2";

  let res = Done((), ini_file.as_bytes()).flat_map(key_value);
  println!("{}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {} | o: ({},{})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate zmq;

#[test]
fn version_test() {
    let (major, minor, patch) = zmq::version();
    assert!(
        ZMQ_MAKE_VERSION!(major, minor, patch) >=
        ZMQ_MAKE_VERSION!(4, 1, 4)
    );
}
<commit_msg>test case<commit_after>#[macro_use]
extern crate zmq;

#[test]
fn version_test() {
    let (major, minor, patch) = zmq::version();
    assert!(
        ZMQ_MAKE_VERSION!(major, minor, patch) >=
        ZMQ_MAKE_VERSION!(4, 1, 4)
    );
}

#[test]
fn context_test() {
    let mut ctx = zmq::Context::new().unwrap();

    ctx.shutdown().unwrap();
}
<|endoftext|>


<commit_before>extern crate trustines;

mod memory {
    use trustines::memory::Memory;

    #[test]
    fn read8_basic() {
        let mut m = Memory::new();
        m.mem[0] = 5;
        m.mem[1] = 10;
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn write8_basic() {
        let mut m = Memory::new();
        m.write8(0,5);
        assert_eq!(5,m.mem[0]);

        m.write8(1,10);
        assert_eq!(5,m.mem[0]);
        assert_eq!(10,m.mem[1]);
    }

    #[test]
    fn read16_basic() {
        let mut m = Memory::new();
        m.mem[0] = 2;
        m.mem[1] = 1;
        m.mem[2] = 0;
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(1,m.read16(1).unwrap());
    }
    #[test]
    fn write16_basic() {
        let mut m = Memory::new();
        m.write16(0,258);
        assert_eq!(2,m.mem[0]);
        assert_eq!(1,m.mem[1]);
    }
    #[test]
    fn readwrite8() {
        let mut m = Memory::new();
        m.write8(0,5);
        m.write8(1,10);
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn readwrite16() {
        let mut m = Memory::new();
        m.write16(0,258);
        m.write16(2,300);
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(300,m.read16(2).unwrap());
    }
}

mod address_mode {
    use trustines::cpu;
    use trustines::memory::Memory;

    fn build_executor() -> cpu::CpuExecutor {
        let opcode_info = cpu::opcode::load_from_file("resources/opcodes.csv").unwrap();
        return cpu::CpuExecutor::new(opcode_info.0);
    }

    #[test]
    fn absolute() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn absolute_x() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn absolute_y() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn accumulator() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn immediate() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn implied() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn indirect() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn indexed_indirect() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn indirect_indexed() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn relative() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn zeropage() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn zeropage_x() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn zeropage_y() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
}

<commit_msg>added test for the new Memory::write function<commit_after>extern crate trustines;

mod memory {
    use trustines::memory::Memory;
    #[test]
    fn write() {
        let mut m = Memory::new();
        m.write(0, &[0,1,2]);
        assert_eq!(0,m.read8(0).unwrap());
        assert_eq!(1,m.read8(1).unwrap());
        assert_eq!(2,m.read8(2).unwrap());
        m.write(1, &[3]);
        assert_eq!(0,m.read8(0).unwrap());
        assert_eq!(3,m.read8(1).unwrap());
        assert_eq!(2,m.read8(2).unwrap());
    }

    #[test]
    fn read8_basic() {
        let mut m = Memory::new();
        m.mem[0] = 5;
        m.mem[1] = 10;
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn write8_basic() {
        let mut m = Memory::new();
        m.write8(0,5);
        assert_eq!(5,m.mem[0]);

        m.write8(1,10);
        assert_eq!(5,m.mem[0]);
        assert_eq!(10,m.mem[1]);
    }

    #[test]
    fn read16_basic() {
        let mut m = Memory::new();
        m.mem[0] = 2;
        m.mem[1] = 1;
        m.mem[2] = 0;
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(1,m.read16(1).unwrap());
    }
    #[test]
    fn write16_basic() {
        let mut m = Memory::new();
        m.write16(0,258);
        assert_eq!(2,m.mem[0]);
        assert_eq!(1,m.mem[1]);
    }
    #[test]
    fn readwrite8() {
        let mut m = Memory::new();
        m.write8(0,5);
        m.write8(1,10);
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn readwrite16() {
        let mut m = Memory::new();
        m.write16(0,258);
        m.write16(2,300);
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(300,m.read16(2).unwrap());
    }
}

mod address_mode {
    use trustines::cpu;
    use trustines::memory::Memory;

    fn build_executor() -> cpu::CpuExecutor {
        let opcode_info = cpu::opcode::load_from_file("resources/opcodes.csv").unwrap();
        return cpu::CpuExecutor::new(opcode_info.0);
    }

    #[test]
    fn absolute() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn absolute_x() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn absolute_y() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn accumulator() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn immediate() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn implied() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn indirect() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn indexed_indirect() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn indirect_indexed() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn relative() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn zeropage() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn zeropage_x() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
    #[test]
    fn zeropage_y() {
        let exec = build_executor();
        let mut m = Memory::new();
    }
}

<|endoftext|>


<commit_before>#![feature(plugin)]

#[plugin(heckle)]
fn boolean() -> bool {
    false
}

#[test]
fn it_works() {
    assert!(boolean());
}
<commit_msg>Plugin attributes are crate-level only<commit_after>#![feature(plugin)]
#![plugin(heckle)]

fn boolean() -> bool {
    false
}

#[test]
fn it_works() {
    assert!(boolean());
}
<|endoftext|>


<commit_before>use crate::{
    packer::{Packer, SkylinePacker},
    texture::{Pixel, Texture},
    texture_packer::{PackResult, TexturePacker},
    texture_packer_config::TexturePackerConfig,
};

pub struct MultiTexturePacker<'a, T: 'a + Clone, P> {
    config: TexturePackerConfig,
    pages: Vec<TexturePacker<'a, T, P>>,
}

impl<'a, Pix: Pixel, T: Clone + Texture<Pixel = Pix>, P: Packer<Pixel = Pix>>
    MultiTexturePacker<'a, T, P>
{
    pub fn get_pages(&self) -> &[TexturePacker<'a, T, P>] {
        &self.pages
    }
}

impl<'a, Pix: Pixel, T: 'a + Clone + Texture<Pixel = Pix>>
    MultiTexturePacker<'a, T, SkylinePacker<Pix>>
{
    pub fn new_skyline(config: TexturePackerConfig) -> Self {
        Self {
            config,
            pages: vec![],
        }
    }
}

impl<'a, Pix: Pixel, T: Clone + Texture<Pixel = Pix>>
    MultiTexturePacker<'a, T, SkylinePacker<Pix>>
{
    pub fn pack_ref(&mut self, key: String, texture: &'a T) -> PackResult<()> {
        for packer in &mut self.pages {
            if packer.can_pack(texture) {
                return packer.pack_ref(key, texture);
            }
        }
        let mut packer = TexturePacker::new_skyline(self.config.clone());
        packer.pack_ref(key, texture)?;
        self.pages.push(packer);
        Ok(())
    }

    pub fn pack_own(&mut self, key: String, texture: T) -> PackResult<()> {
        for packer in &mut self.pages {
            if packer.can_pack(&texture) {
                return packer.pack_own(key, texture);
            }
        }
        let mut packer = TexturePacker::new_skyline(self.config.clone());
        packer.pack_own(key, texture)?;
        self.pages.push(packer);
        Ok(())
    }
}
<commit_msg>docs: Document the multi_texture_packer module<commit_after>use crate::{
    packer::{Packer, SkylinePacker},
    texture::{Pixel, Texture},
    texture_packer::{PackResult, TexturePacker},
    texture_packer_config::TexturePackerConfig,
};

/// Texture packer supporting multiple atlases.
///
/// Will create a new page for textures that do not fit. Textures packed after a new page is added
/// will still attempt to check each page for available space.
pub struct MultiTexturePacker<'a, T: 'a + Clone, P> {
    config: TexturePackerConfig,
    pages: Vec<TexturePacker<'a, T, P>>,
}

impl<'a, Pix: Pixel, T: Clone + Texture<Pixel = Pix>, P: Packer<Pixel = Pix>>
    MultiTexturePacker<'a, T, P>
{
    /// Get an array of all underlying single-atlas texture packers.
    pub fn get_pages(&self) -> &[TexturePacker<'a, T, P>] {
        &self.pages
    }
}

impl<'a, Pix: Pixel, T: 'a + Clone + Texture<Pixel = Pix>>
    MultiTexturePacker<'a, T, SkylinePacker<Pix>>
{
    /// Create a new packer using the skyline packing algorithm.
    pub fn new_skyline(config: TexturePackerConfig) -> Self {
        Self {
            config,
            pages: vec![],
        }
    }
}

impl<'a, Pix: Pixel, T: Clone + Texture<Pixel = Pix>>
    MultiTexturePacker<'a, T, SkylinePacker<Pix>>
{
    /// Pack the `texture` into this packer, taking a reference of the texture object.
    pub fn pack_ref(&mut self, key: String, texture: &'a T) -> PackResult<()> {
        for packer in &mut self.pages {
            if packer.can_pack(texture) {
                return packer.pack_ref(key, texture);
            }
        }
        let mut packer = TexturePacker::new_skyline(self.config.clone());
        packer.pack_ref(key, texture)?;
        self.pages.push(packer);
        Ok(())
    }

    /// Pack the `texture` into this packer, taking ownership of the texture object.
    pub fn pack_own(&mut self, key: String, texture: T) -> PackResult<()> {
        for packer in &mut self.pages {
            if packer.can_pack(&texture) {
                return packer.pack_own(key, texture);
            }
        }
        let mut packer = TexturePacker::new_skyline(self.config.clone());
        packer.pack_own(key, texture)?;
        self.pages.push(packer);
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use super::byteorder::{BigEndian, ByteOrder};

// Size of the memory map of a CHIP-8 interpreter is 4kb.
const RAM_SIZE: usize = 4096;

// Display size parameters.
const DISPLAY_WIDTH: usize = 64;
const DISPLAY_HEIGHT: usize = 32;
const DISPLAY_SIZE: usize = DISPLAY_WIDTH * DISPLAY_HEIGHT;

// Memory map constants.
//const START_RESERVED: u16 = 0x000;
//const END_RESERVED: u16 = 0x200;
//const END_PROGRAM_SPACE: u16 = 0xFFF;

#[derive(Default)]
pub struct Interconnect {
    pub rom: Vec<u8>,
    pub ram: Vec<u8>,
    pub display: Vec<u8>,
}

impl Interconnect {
    pub fn new(rom: Vec<u8>) -> Interconnect {
        Interconnect {
            rom: rom,
            ram: vec![0; RAM_SIZE],
            display: vec![0; DISPLAY_SIZE],
        }
    }

    #[inline(always)]
    pub fn read_word(&self, addr: u16) -> u16 {
        BigEndian::read_u16(&self.rom[addr as usize..])
    }

    #[inline(always)]
    pub fn draw(&mut self, x: usize, y: usize, sprite: Vec<u8>) -> u8 {
        let start = y * DISPLAY_WIDTH + x;
        let mut collision: u8 = 0;

        for i in 0..sprite.len() {
            // Each byte in a sprite draws on one line.
            let offset = start + DISPLAY_WIDTH * i;

            // Loop through the bits in the current byte and set the display
            // values based on them.
            for j in 0..8 {
                let bit = (0x01 << j) & sprite[i];
                let pos = x + j;
                let index: usize;

                // Determine which pixel shall be drawn. If the sprite is
                // overflowing off the right side of the screen, if wraps back
                // to the left side.
                if pos >= DISPLAY_WIDTH {
                    let diff = pos - DISPLAY_WIDTH;
                    index = y * (DISPLAY_WIDTH * i) + j - diff;
                    println!("x: {:#?}, y: {:#?}", x, y);
                } else {
                    index = offset + j;
                }

                // If the sprite is drawing off the bottom of the display, do
                // not draw pixels off the display.
                if index >= 2048 {
                    continue;
                }

                // Save the previous state of the pixel before setting it
                // for collision detection.
                let prev = self.display[index];

                // Draw the bit to the display.
                self.display[index] = bit ^ prev;

                // Check the previous state of the pixel and check if it
                // was erased, if so then there was a sprite collision.
                if prev == 1 && self.display[index] == 0 {
                    collision = 1;
                }
            }
        }

        collision
    }
}

impl fmt::Debug for Interconnect {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "interconnect")
    }
}
<commit_msg>Display now prints on every draw call<commit_after>use std::fmt;
use super::byteorder::{BigEndian, ByteOrder};

// Size of the memory map of a CHIP-8 interpreter is 4kb.
const RAM_SIZE: usize = 4096;

// Display size parameters.
const DISPLAY_WIDTH: usize = 64;
const DISPLAY_HEIGHT: usize = 32;
const DISPLAY_SIZE: usize = DISPLAY_WIDTH * DISPLAY_HEIGHT;

// Memory map constants.
//const START_RESERVED: u16 = 0x000;
//const END_RESERVED: u16 = 0x200;
//const END_PROGRAM_SPACE: u16 = 0xFFF;

#[derive(Default)]
pub struct Interconnect {
    pub rom: Vec<u8>,
    pub ram: Vec<u8>,
    pub display: Vec<u8>,
}

impl Interconnect {
    pub fn new(rom: Vec<u8>) -> Interconnect {
        Interconnect {
            rom: rom,
            ram: vec![0; RAM_SIZE],
            display: vec![0; DISPLAY_SIZE],
        }
    }

    #[inline(always)]
    pub fn read_word(&self, addr: u16) -> u16 {
        BigEndian::read_u16(&self.rom[addr as usize..])
    }

    #[inline(always)]
    pub fn draw(&mut self, x: usize, y: usize, sprite: Vec<u8>) -> u8 {
        let start = y * DISPLAY_WIDTH + x;
        let mut collision: u8 = 0;

        for i in 0..sprite.len() {
            // Each byte in a sprite draws on one line.
            let offset = start + DISPLAY_WIDTH * i;

            // Loop through the bits in the current byte and set the display
            // values based on them.
            for j in 0..8 {
                let bit = (0x01 << j) & sprite[i];
                let pos = x + j;
                let index: usize;

                // Determine which pixel shall be drawn. If the sprite is
                // overflowing off the right side of the screen, if wraps back
                // to the left side.
                if pos >= DISPLAY_WIDTH {
                    let diff = pos - DISPLAY_WIDTH;
                    index = y * (DISPLAY_WIDTH * i) + j - diff;
                } else {
                    index = offset + j;
                }

                // If the sprite is drawing off the bottom of the display, do
                // not draw pixels off the display.
                if index >= 2048 {
                    continue;
                }

                // Save the previous state of the pixel before setting it
                // for collision detection.
                let prev = self.display[index];

                // Draw the bit to the display.
                self.display[index] = bit ^ prev;

                // Check the previous state of the pixel and check if it
                // was erased, if so then there was a sprite collision.
                if prev == 1 && self.display[index] == 0 {
                    collision = 1;
                }
            }
        }

        // TODO: Get rid of when a real framebuffer is aquired. Just a way to
        // visually see what is being drawn in the terminal.
        for i in 0..DISPLAY_HEIGHT {
            for j in 0..DISPLAY_WIDTH {
                if self.display[j + DISPLAY_HEIGHT * i] == 1 {
                    print!("¶");
                } else {
                    print!(" ");
                }
            }

            println!("");
        }

        collision
    }
}

impl fmt::Debug for Interconnect {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "interconnect")
    }
}
<|endoftext|>


<commit_before>//! Handles the IPC (Inter-process Communication) protocol used by the renderer client and server.
//!
//! This is the common "language" between client/server. It defines both the protocol for
//! connection and for send messages back and forth.

mod async_ipc_receiver;
mod messages;
mod protocol;

pub use messages::*;
pub use protocol::*;

use std::io;
use std::future::Future;

use thiserror::Error;
use serde::{Serialize, Deserialize};
use tokio::sync::Mutex;
use ipc_channel::ipc::{self, IpcOneShotServer, IpcSender, IpcError};

use crate::renderer_client::ClientId;

use async_ipc_receiver::AsyncIpcReceiver;

#[derive(Debug, Error)]
#[error(transparent)]
pub enum ConnectionError {
    IpcChannelError(#[from] ipc_channel::Error),
    IOError(#[from] io::Error),
    JoinError(#[from] tokio::task::JoinError),
}

/// Represents either a sender from the connection handshake or a response
#[derive(Debug, Serialize, Deserialize)]
enum HandshakeResponse {
    /// Represents that the handshake has been completed successfully.
    ///
    /// Provides the sender that the client should use to send further requests to the server. This
    /// message is only ever sent **once** for each client at the beginning when the connection is
    /// first established.
    HandshakeFinish(IpcSender<(ClientId, ClientRequest)>),

    /// A response from the server sent in response to a request
    Response(ClientId, ServerResponse),
}

/// Represents the client side of the IPC connection
#[derive(Debug)]
pub struct ClientConnection {
    sender: Mutex<IpcSender<(ClientId, ClientRequest)>>,
    receiver: AsyncIpcReceiver<HandshakeResponse>,
}

impl ClientConnection {
    pub async fn new<S, F>(send_ipc_oneshot_name: S) -> Result<Self, ConnectionError>
        where S: FnOnce(String) -> F,
              F: Future<Output=io::Result<()>>,
    {
        // Send the oneshot token to the server which will then respond with its own oneshot token
        let (server, server_name) = IpcOneShotServer::new()?;
        send_ipc_oneshot_name(server_name).await?;

        let (receiver, response): (_, HandshakeResponse) = tokio::task::spawn_blocking(|| {
            server.accept()
        }).await??;

        let sender = match response {
            HandshakeResponse::HandshakeFinish(sender) => sender,
            _ => unreachable!("bug: server did not send back Sender at the end of handshake"),
        };

        let sender = Mutex::new(sender);
        let receiver = AsyncIpcReceiver::new(receiver);

        Ok(Self {sender, receiver})
    }

    /// Sends a request to the server via IPC
    pub async fn send(&self, id: ClientId, req: ClientRequest) -> Result<(), ipc_channel::Error> {
        self.sender.lock().await.send((id, req))
    }

    /// Waits for a response from the server via IPC
    pub async fn recv(&self) -> Result<(ClientId, ServerResponse), IpcError> {
        let response = self.receiver.recv().await?;
        match response {
            HandshakeResponse::Response(id, response) => Ok((id, response)),
            _ => unreachable!("bug: server did not send response after request"),
        }
    }
}

/// Represents the server side of the IPC connection
#[derive(Debug)]
pub struct ServerConnection {
    sender: Mutex<IpcSender<HandshakeResponse>>,
    receiver: AsyncIpcReceiver<(ClientId, ClientRequest)>,
}

impl ServerConnection {
    /// Establishes a connection to the client by reading from stdin
    #[cfg(all(not(any(feature = "test", test)), target_os = "macos"))]
    pub async fn connect_stdin() -> Result<Self, ConnectionError> {
        use tokio::io::{self, AsyncBufReadExt};

        let stdin = io::stdin();
        let mut reader = io::BufReader::new(stdin);

        let mut oneshot_name = String::new();
        reader.read_line(&mut oneshot_name).await?;
        if oneshot_name.is_empty() {
            panic!("bug: unexpected EOF when reading oneshot server name");
        }

        // Remove the trailing newline
        assert_eq!(oneshot_name.pop(), Some('\n'));
        let conn = ServerConnection::connect(oneshot_name)?;

        Ok(conn)
    }

    /// Establishes a connection with the IPC channel oneshot server with the given name
    pub fn connect(oneshot_name: String) -> Result<Self, ConnectionError> {
        let (server_sender, receiver) = ipc::channel()?;
        let sender = IpcSender::connect(oneshot_name)?;

        // Finish handshake by giving client a sender it can use to send messages to the server
        sender.send(HandshakeResponse::HandshakeFinish(server_sender))?;

        let sender = Mutex::new(sender);
        let receiver = AsyncIpcReceiver::new(receiver);

        Ok(Self {sender, receiver})
    }

    /// Returns the next request, waiting until one is available
    pub async fn recv(&self) -> Result<(ClientId, ClientRequest), IpcError> {
        self.receiver.recv().await
    }

    /// Sends a response to the client
    ///
    /// This should only ever be done in response to a request
    pub async fn send(&self, id: ClientId, res: ServerResponse) -> Result<(), ipc_channel::Error> {
        self.sender.lock().await
            .send(HandshakeResponse::Response(id, res))
    }
}
<commit_msg>Fixed typo in IPC protocol docs<commit_after>//! Handles the IPC (Inter-process Communication) protocol used by the renderer client and server.
//!
//! This is the common "language" between client/server. It defines the protocol for connection and
//! for sending messages back and forth.

mod async_ipc_receiver;
mod messages;
mod protocol;

pub use messages::*;
pub use protocol::*;

use std::io;
use std::future::Future;

use thiserror::Error;
use serde::{Serialize, Deserialize};
use tokio::sync::Mutex;
use ipc_channel::ipc::{self, IpcOneShotServer, IpcSender, IpcError};

use crate::renderer_client::ClientId;

use async_ipc_receiver::AsyncIpcReceiver;

#[derive(Debug, Error)]
#[error(transparent)]
pub enum ConnectionError {
    IpcChannelError(#[from] ipc_channel::Error),
    IOError(#[from] io::Error),
    JoinError(#[from] tokio::task::JoinError),
}

/// Represents either a sender from the connection handshake or a response
#[derive(Debug, Serialize, Deserialize)]
enum HandshakeResponse {
    /// Represents that the handshake has been completed successfully.
    ///
    /// Provides the sender that the client should use to send further requests to the server. This
    /// message is only ever sent **once** for each client at the beginning when the connection is
    /// first established.
    HandshakeFinish(IpcSender<(ClientId, ClientRequest)>),

    /// A response from the server sent in response to a request
    Response(ClientId, ServerResponse),
}

/// Represents the client side of the IPC connection
#[derive(Debug)]
pub struct ClientConnection {
    sender: Mutex<IpcSender<(ClientId, ClientRequest)>>,
    receiver: AsyncIpcReceiver<HandshakeResponse>,
}

impl ClientConnection {
    pub async fn new<S, F>(send_ipc_oneshot_name: S) -> Result<Self, ConnectionError>
        where S: FnOnce(String) -> F,
              F: Future<Output=io::Result<()>>,
    {
        // Send the oneshot token to the server which will then respond with its own oneshot token
        let (server, server_name) = IpcOneShotServer::new()?;
        send_ipc_oneshot_name(server_name).await?;

        let (receiver, response): (_, HandshakeResponse) = tokio::task::spawn_blocking(|| {
            server.accept()
        }).await??;

        let sender = match response {
            HandshakeResponse::HandshakeFinish(sender) => sender,
            _ => unreachable!("bug: server did not send back Sender at the end of handshake"),
        };

        let sender = Mutex::new(sender);
        let receiver = AsyncIpcReceiver::new(receiver);

        Ok(Self {sender, receiver})
    }

    /// Sends a request to the server via IPC
    pub async fn send(&self, id: ClientId, req: ClientRequest) -> Result<(), ipc_channel::Error> {
        self.sender.lock().await.send((id, req))
    }

    /// Waits for a response from the server via IPC
    pub async fn recv(&self) -> Result<(ClientId, ServerResponse), IpcError> {
        let response = self.receiver.recv().await?;
        match response {
            HandshakeResponse::Response(id, response) => Ok((id, response)),
            _ => unreachable!("bug: server did not send response after request"),
        }
    }
}

/// Represents the server side of the IPC connection
#[derive(Debug)]
pub struct ServerConnection {
    sender: Mutex<IpcSender<HandshakeResponse>>,
    receiver: AsyncIpcReceiver<(ClientId, ClientRequest)>,
}

impl ServerConnection {
    /// Establishes a connection to the client by reading from stdin
    #[cfg(all(not(any(feature = "test", test)), target_os = "macos"))]
    pub async fn connect_stdin() -> Result<Self, ConnectionError> {
        use tokio::io::{self, AsyncBufReadExt};

        let stdin = io::stdin();
        let mut reader = io::BufReader::new(stdin);

        let mut oneshot_name = String::new();
        reader.read_line(&mut oneshot_name).await?;
        if oneshot_name.is_empty() {
            panic!("bug: unexpected EOF when reading oneshot server name");
        }

        // Remove the trailing newline
        assert_eq!(oneshot_name.pop(), Some('\n'));
        let conn = ServerConnection::connect(oneshot_name)?;

        Ok(conn)
    }

    /// Establishes a connection with the IPC channel oneshot server with the given name
    pub fn connect(oneshot_name: String) -> Result<Self, ConnectionError> {
        let (server_sender, receiver) = ipc::channel()?;
        let sender = IpcSender::connect(oneshot_name)?;

        // Finish handshake by giving client a sender it can use to send messages to the server
        sender.send(HandshakeResponse::HandshakeFinish(server_sender))?;

        let sender = Mutex::new(sender);
        let receiver = AsyncIpcReceiver::new(receiver);

        Ok(Self {sender, receiver})
    }

    /// Returns the next request, waiting until one is available
    pub async fn recv(&self) -> Result<(ClientId, ClientRequest), IpcError> {
        self.receiver.recv().await
    }

    /// Sends a response to the client
    ///
    /// This should only ever be done in response to a request
    pub async fn send(&self, id: ClientId, res: ServerResponse) -> Result<(), ipc_channel::Error> {
        self.sender.lock().await
            .send(HandshakeResponse::Response(id, res))
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::env;
use std::process::Command;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::Write;

struct Test {
    repo: &'static str,
    name: &'static str,
    sha: &'static str,
    lock: Option<&'static str>,
}

const TEST_REPOS: &'static [Test] = &[Test {
                                          name: "bins",
                                          repo: "https://github.com/jkcclemens/bins",
                                          sha: "378da8f7d78df6e3ff0b234063de50619b16648e",
                                          lock: None,
                                      },
                                      Test {
                                          name: "cargo",
                                          repo: "https://github.com/rust-lang/cargo",
                                          sha: "b7be4f2ef2cf743492edc6dfb55d087ed88f2d76",
                                          lock: None,
                                      },
                                      Test {
                                          name: "iron",
                                          repo: "https://github.com/iron/iron",
                                          sha: "16c858ec2901e2992fe5e529780f59fa8ed12903",
                                          lock: Some(include_str!("lockfiles/iron-Cargo.lock")),
                                      },
                                      Test {
                                          name: "ripgrep",
                                          repo: "https://github.com/BurntSushi/ripgrep",
                                          sha: "5487dffefaa34e5fc04321335aa716f415082977",
                                          lock: None,
                                      },
                                      Test {
                                          name: "tokei",
                                          repo: "https://github.com/Aaronepower/tokei",
                                          sha: "9faa8d4210ba19ad76d736e46e4963cfcef329d6",
                                          lock: None,
                                      },
                                      Test {
                                          name: "treeify",
                                          repo: "https://github.com/dzamlo/treeify",
                                          sha: "999001b223152441198f117a68fb81f57bc086dd",
                                          lock: None,
                                      },
                                      Test {
                                          name: "xsv",
                                          repo: "https://github.com/BurntSushi/xsv",
                                          sha: "5ec4fff4a3f507eda887049469897f02c6fae036",
                                          lock: None,
                                      }];

fn main() {
    // One of the projects being tested here is Cargo, and when being tested
    // Cargo will at some point call `nmake.exe` on Windows MSVC. Unfortunately
    // `nmake` will read these two environment variables below and try to
    // intepret them. We're likely being run, however, from MSYS `make` which
    // uses the same variables.
    //
    // As a result, to prevent confusion and errors, we remove these variables
    // from our environment to prevent passing MSYS make flags to nmake, causing
    // it to blow up.
    if cfg!(target_env = "msvc") {
        env::remove_var("MAKE");
        env::remove_var("MAKEFLAGS");
    }

    let args = env::args().collect::<Vec<_>>();
    let ref cargo = args[1];
    let out_dir = Path::new(&args[2]);
    let ref cargo = Path::new(cargo);

    for test in TEST_REPOS.iter().rev() {
        test_repo(cargo, out_dir, test);
    }
}

fn test_repo(cargo: &Path, out_dir: &Path, test: &Test) {
    println!("testing {}", test.repo);
    let dir = clone_repo(test, out_dir);
    if let Some(lockfile) = test.lock {
        File::create(&dir.join("Cargo.lock"))
            .expect("")
            .write_all(lockfile.as_bytes())
            .expect("");
    }
    if !run_cargo_test(cargo, &dir) {
        panic!("tests failed for {}", test.repo);
    }
}

fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf {
    let out_dir = out_dir.join(test.name);

    if !out_dir.join(".git").is_dir() {
        let status = Command::new("git")
                         .arg("init")
                         .arg(&out_dir)
                         .status()
                         .expect("");
        assert!(status.success());
    }

    // Try progressively deeper fetch depths to find the commit
    let mut found = false;
    for depth in &[0, 1, 10, 100, 1000, 100000] {
        if *depth > 0 {
            let status = Command::new("git")
                             .arg("fetch")
                             .arg(test.repo)
                             .arg("master")
                             .arg(&format!("--depth={}", depth))
                             .current_dir(&out_dir)
                             .status()
                             .expect("");
            assert!(status.success());
        }

        let status = Command::new("git")
                         .arg("reset")
                         .arg(test.sha)
                         .arg("--hard")
                         .current_dir(&out_dir)
                         .status()
                         .expect("");

        if status.success() {
            found = true;
            break;
        }
    }

    if !found {
        panic!("unable to find commit {}", test.sha)
    }
    let status = Command::new("git")
                     .arg("clean")
                     .arg("-fdx")
                     .current_dir(&out_dir)
                     .status()
                     .unwrap();
    assert!(status.success());

    out_dir
}

fn run_cargo_test(cargo_path: &Path, crate_path: &Path) -> bool {
    let status = Command::new(cargo_path)
        .arg("test")
        // Disable rust-lang/cargo's cross-compile tests
        .env("CFG_DISABLE_CROSS_TESTS", "1")
        .current_dir(crate_path)
        .status()
        .expect("");

    status.success()
}
<commit_msg>Fixes for new cargo test repos<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::env;
use std::process::Command;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::Write;

struct Test {
    repo: &'static str,
    name: &'static str,
    sha: &'static str,
    lock: Option<&'static str>,
}

const TEST_REPOS: &'static [Test] = &[
    Test {
        name: "cargo",
        repo: "https://github.com/rust-lang/cargo",
        sha: "b7be4f2ef2cf743492edc6dfb55d087ed88f2d76",
        lock: None,
    },
    Test {
        name: "iron",
        repo: "https://github.com/iron/iron",
        sha: "16c858ec2901e2992fe5e529780f59fa8ed12903",
        lock: Some(include_str!("lockfiles/iron-Cargo.lock")),
    },
    Test {
        name: "ripgrep",
        repo: "https://github.com/BurntSushi/ripgrep",
        sha: "b65bb37b14655e1a89c7cd19c8b011ef3e312791",
        lock: None,
    },
    Test {
        name: "tokei",
        repo: "https://github.com/Aaronepower/tokei",
        sha: "5e11c4852fe4aa086b0e4fe5885822fbe57ba928",
        lock: None,
    },
    Test {
        name: "treeify",
        repo: "https://github.com/dzamlo/treeify",
        sha: "999001b223152441198f117a68fb81f57bc086dd",
        lock: None,
    },
    Test {
        name: "xsv",
        repo: "https://github.com/BurntSushi/xsv",
        sha: "5ec4fff4a3f507eda887049469897f02c6fae036",
        lock: None,
    },
];

fn main() {
    // One of the projects being tested here is Cargo, and when being tested
    // Cargo will at some point call `nmake.exe` on Windows MSVC. Unfortunately
    // `nmake` will read these two environment variables below and try to
    // intepret them. We're likely being run, however, from MSYS `make` which
    // uses the same variables.
    //
    // As a result, to prevent confusion and errors, we remove these variables
    // from our environment to prevent passing MSYS make flags to nmake, causing
    // it to blow up.
    if cfg!(target_env = "msvc") {
        env::remove_var("MAKE");
        env::remove_var("MAKEFLAGS");
    }

    let args = env::args().collect::<Vec<_>>();
    let ref cargo = args[1];
    let out_dir = Path::new(&args[2]);
    let ref cargo = Path::new(cargo);

    for test in TEST_REPOS.iter().rev() {
        test_repo(cargo, out_dir, test);
    }
}

fn test_repo(cargo: &Path, out_dir: &Path, test: &Test) {
    println!("testing {}", test.repo);
    let dir = clone_repo(test, out_dir);
    if let Some(lockfile) = test.lock {
        File::create(&dir.join("Cargo.lock"))
            .expect("")
            .write_all(lockfile.as_bytes())
            .expect("");
    }
    if !run_cargo_test(cargo, &dir) {
        panic!("tests failed for {}", test.repo);
    }
}

fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf {
    let out_dir = out_dir.join(test.name);

    if !out_dir.join(".git").is_dir() {
        let status = Command::new("git")
                         .arg("init")
                         .arg(&out_dir)
                         .status()
                         .expect("");
        assert!(status.success());
    }

    // Try progressively deeper fetch depths to find the commit
    let mut found = false;
    for depth in &[0, 1, 10, 100, 1000, 100000] {
        if *depth > 0 {
            let status = Command::new("git")
                             .arg("fetch")
                             .arg(test.repo)
                             .arg("master")
                             .arg(&format!("--depth={}", depth))
                             .current_dir(&out_dir)
                             .status()
                             .expect("");
            assert!(status.success());
        }

        let status = Command::new("git")
                         .arg("reset")
                         .arg(test.sha)
                         .arg("--hard")
                         .current_dir(&out_dir)
                         .status()
                         .expect("");

        if status.success() {
            found = true;
            break;
        }
    }

    if !found {
        panic!("unable to find commit {}", test.sha)
    }
    let status = Command::new("git")
                     .arg("clean")
                     .arg("-fdx")
                     .current_dir(&out_dir)
                     .status()
                     .unwrap();
    assert!(status.success());

    out_dir
}

fn run_cargo_test(cargo_path: &Path, crate_path: &Path) -> bool {
    let status = Command::new(cargo_path)
        .arg("test")
        // Disable rust-lang/cargo's cross-compile tests
        .env("CFG_DISABLE_CROSS_TESTS", "1")
        .current_dir(crate_path)
        .status()
        .expect("");

    status.success()
}
<|endoftext|>


<commit_before>use wpilib::wpilib_hal::*;
use wpilib::hal_call::*;
use wpilib::Throttler;
use std::thread;
use std::sync::mpsc;
use std::ptr;
use std::mem::transmute;
use std::ffi::CString;
use std::sync::{Arc, Condvar, Mutex};
use atom::*;
use std::time::Duration;

const MAX_JOYSTICK_PORTS: usize = 6;
const MAX_JOYSTICK_AXES: usize = 12;
const MAX_JOYSTICK_POVS: usize = 12;

#[derive(Default)]
struct Joysticks {
    axes: [HAL_JoystickAxes; MAX_JOYSTICK_PORTS],
    povs: [HAL_JoystickPOVs; MAX_JOYSTICK_PORTS],
    buttons: [HAL_JoystickButtons; MAX_JOYSTICK_PORTS],
    descriptor: [HAL_JoystickDescriptor; MAX_JOYSTICK_PORTS],
}

#[derive(Debug)]
pub enum RobotState {
    Disabled,
    Autonomous,
    Teleop,
    Test,
    EStop,
}

type DSBuffer = Box<(Joysticks, HAL_ControlWord)>;

pub struct DriverStation {
    data: Arc<Atom<DSBuffer>>,
    joysticks: Joysticks,
    pub state: RobotState,
    pub fms_attached: bool,
    pub ds_attached: bool,

    report_throttler: Throttler<f64>,

    waiter: Arc<(Mutex<bool>, Condvar)>,
}

static mut DRIVER_STATION: *mut DriverStation = 0 as *mut DriverStation;

#[derive(Debug, Copy, Clone)]
pub enum JoystickError {
    JoystickDNE,
    ChannelUnplugged,
    ChannelDNE,
}

#[derive(Debug, Copy, Clone)]
pub enum AllianceId {
    Red,
    Blue,
    Invalid,
}

impl DriverStation {
    fn new() -> DriverStation {
        let mut data_atom = Arc::new(Atom::empty());
        let mut other_atom = data_atom.clone();

        let mut waiter = Arc::new((Mutex::new(false), Condvar::new()));
        let mut other_waiter = waiter.clone();

        let join = thread::spawn(move || {
            let mut data_atom = other_atom;
            let mut waiter = other_waiter;

            loop {
                unsafe {
                    HAL_WaitForDSData();
                }

                let mut joysticks = Joysticks::default();
                for stick in 0..MAX_JOYSTICK_PORTS {
                    unsafe {
                        HAL_GetJoystickAxes(stick as i32,
                                            &mut joysticks.axes[stick] as *mut HAL_JoystickAxes);
                        HAL_GetJoystickPOVs(stick as i32,
                                            &mut joysticks.povs[stick] as *mut HAL_JoystickPOVs);
                        HAL_GetJoystickButtons(stick as i32,
                                                    &mut joysticks.buttons[stick] as
                                                    *mut HAL_JoystickButtons);
                        HAL_GetJoystickDescriptor(stick as i32,
                                                       &mut joysticks.descriptor[stick] as
                                                       *mut HAL_JoystickDescriptor);
                    }
                }

                let mut control_word: HAL_ControlWord = HAL_ControlWord::default();
                unsafe {
                    HAL_GetControlWord(&mut control_word as *mut HAL_ControlWord);
                }

                data_atom.swap(Box::new((joysticks, control_word)));

                {
                    let mut guard = waiter.0.lock().unwrap();
                    *guard = true;
                    waiter.1.notify_all();
                }
            }
        });

        DriverStation {
            data: data_atom,
            joysticks: Joysticks::default(),
            state: RobotState::Disabled,
            fms_attached: false,
            ds_attached: false,

            // For now use an interval of 0 so we don't actually throttle messages, as the FPGA
            // timer isn't implemented yet.
            report_throttler: Throttler::new(0.0, 0.0),

            waiter: waiter,
        }
    }

    fn update_data(&mut self) {
        if let Some(boxed_data) = self.data.take() {
            let new_control_word = boxed_data.1;
            self.joysticks = boxed_data.0;
            self.state = if new_control_word.enabled() {
                if new_control_word.autonomous() {
                    RobotState::Autonomous
                } else {
                    RobotState::Teleop
                }
            } else if new_control_word.eStop() {
                RobotState::EStop
            } else {
                RobotState::Disabled
            };
            self.fms_attached = new_control_word.fmsAttached();
            self.ds_attached = new_control_word.dsAttached();
        }
    }

    fn report(&self, is_error: bool, code: i32, error: &str, location: &str, stack: &str) {
        unsafe {
            HAL_SendError(is_error as i32,
                          code,
                          false as i32,
                          CString::new(error).unwrap().into_raw(),
                          CString::new(location).unwrap().into_raw(),
                          CString::new(stack).unwrap().into_raw(),
                          true as i32);
        }
    }

    fn report_error(&mut self, error: &str) {
        self.report(true, 1, error, "", "");
    }

    fn report_warning(&mut self, warning: &str) {
        self.report(false, 1, warning, "", "");
    }

    fn report_throttled(&mut self, is_error: bool, message: &str) {
        // Don't actually throttle it; FPGA timer is unimplemented
        let now = 1f64;
        if self.report_throttler.update(now) {
            self.report(is_error, 1, message, "", "");
        }
    }

    pub fn instance() -> &'static mut DriverStation {
        unsafe {
            if DRIVER_STATION == 0 as *mut DriverStation {
                DRIVER_STATION = transmute(Box::new(DriverStation::new()));
            }
            &mut *DRIVER_STATION
        }
    }

    pub fn get_joystick_axis(&mut self, stick: usize, axis: usize) -> Result<f32, JoystickError> {
        self.update_data();

        if stick >= MAX_JOYSTICK_PORTS {
            self.report_throttled(true, "Bad joystick");
            Err(JoystickError::JoystickDNE)
        } else if axis >= MAX_JOYSTICK_AXES {
            self.report_throttled(true, "Bad joystick axis");
            Err(JoystickError::ChannelDNE)
        } else if axis >= self.joysticks.axes[stick].count as usize {
            self.report_throttled(true,
                                  "Joystick axis missing, check if all controllers are plugged in");
            Err(JoystickError::ChannelUnplugged)
        } else {
            Ok(self.joysticks.axes[stick].axes[axis])
        }
    }

    pub fn get_joystick_pov(&mut self, stick: usize, pov: usize) -> Result<i16, JoystickError> {
        self.update_data();

        if stick >= MAX_JOYSTICK_POVS {
            self.report_throttled(true, "Bad joystick");
            Err(JoystickError::JoystickDNE)
        } else if pov >= MAX_JOYSTICK_AXES {
            self.report_throttled(true, "Bad joystick pov");
            Err(JoystickError::ChannelDNE)
        } else if pov >= self.joysticks.povs[stick].count as usize {
            self.report_throttled(true,
                                  "Joystick pov missing, check if all controllers are plugged in");
            Err(JoystickError::ChannelUnplugged)
        } else {
            Ok(self.joysticks.povs[stick].povs[pov])
        }
    }

    pub fn get_joystick_button(&mut self,
                               stick: usize,
                               button: usize)
                               -> Result<bool, JoystickError> {
        self.update_data();

        if stick >= MAX_JOYSTICK_POVS {
            self.report_throttled(true, "Bad joystick");
            Err(JoystickError::JoystickDNE)
        } else if button == 0 {
            self.report_throttled(true, "Bad joystick button (button IDs start from 1)");
            Err(JoystickError::ChannelDNE)
        } else if button >= self.joysticks.povs[stick].count as usize {
            self.report_throttled(true,
                                  "Joystick button missing, check if all controllers are plugged \
                                   in");
            Err(JoystickError::ChannelUnplugged)
        } else {
            let mask = 1 << (button - 1);
            Ok(self.joysticks.buttons[stick].buttons & mask != 0)
        }
    }

    pub fn get_alliance(&self) -> HalResult<AllianceId> {
        match hal_call!(HAL_GetAllianceStation())? {
            HAL_AllianceStationID::HAL_AllianceStationID_kRed1 |
            HAL_AllianceStationID::HAL_AllianceStationID_kRed2 |
            HAL_AllianceStationID::HAL_AllianceStationID_kRed3 => Ok(AllianceId::Red),
            HAL_AllianceStationID::HAL_AllianceStationID_kBlue1 |
            HAL_AllianceStationID::HAL_AllianceStationID_kBlue2 |
            HAL_AllianceStationID::HAL_AllianceStationID_kBlue3 => Ok(AllianceId::Blue),
        }
    }

    pub fn get_station(&self) -> HalResult<i32> {
        match hal_call!(HAL_GetAllianceStation())? {
            HAL_AllianceStationID::HAL_AllianceStationID_kRed1 |
            HAL_AllianceStationID::HAL_AllianceStationID_kBlue1 => Ok(1),
            HAL_AllianceStationID::HAL_AllianceStationID_kRed2 |
            HAL_AllianceStationID::HAL_AllianceStationID_kBlue2 => Ok(2),
            HAL_AllianceStationID::HAL_AllianceStationID_kRed3 |
            HAL_AllianceStationID::HAL_AllianceStationID_kBlue3 => Ok(3),
        }
    }

    /// Waits for a new driver station packet
    pub fn wait_for_data(&self) {
        let &(ref wait_lock, ref wait_cond) = &*self.waiter;
        let mut has_data = wait_lock.lock().unwrap();
        while !*has_data {
            has_data = wait_cond.wait(has_data).unwrap();
        }
    }

    /// Waits for a new driver station packet and returns true, or returns false if timeout is
    /// exceeded.
    pub fn wait_for_data_or_timeout(&self, timeout: Duration) -> bool {
        let &(ref wait_lock, ref wait_cond) = &*self.waiter;
        let mut has_data = wait_lock.lock().unwrap();

        while !*has_data {
            let result = wait_cond.wait_timeout(has_data, timeout).unwrap();
            if result.1.timed_out() {
                return false;
            } else {
                has_data = result.0;
            }
        }
        true
    }
}
<commit_msg>Clean up DriverStation<commit_after>use wpilib::wpilib_hal::*;
use wpilib::hal_call::*;
use wpilib::Throttler;

use std::{thread, ptr, time, mem, ffi, sync};
// use std::sync::{Arc, Condvar, Mutex, Once, ONCE_INIT};

use atom::Atom;

const MAX_JOYSTICK_PORTS: usize = 6;
const MAX_JOYSTICK_AXES: usize = 12;
const MAX_JOYSTICK_POVS: usize = 12;

#[derive(Default)]
struct Joysticks {
    axes: [HAL_JoystickAxes; MAX_JOYSTICK_PORTS],
    povs: [HAL_JoystickPOVs; MAX_JOYSTICK_PORTS],
    buttons: [HAL_JoystickButtons; MAX_JOYSTICK_PORTS],
    descriptor: [HAL_JoystickDescriptor; MAX_JOYSTICK_PORTS],
}

#[derive(Debug)]
pub enum RobotState {
    Disabled,
    Autonomous,
    Teleop,
    Test,
    EStop,
}

type DSBuffer = Box<(Joysticks, HAL_ControlWord)>;

pub struct DriverStation {
    data: sync::Arc<Atom<DSBuffer>>,
    joysticks: Joysticks,
    pub state: RobotState,
    pub fms_attached: bool,
    pub ds_attached: bool,

    report_throttler: Throttler<f64>,

    waiter: sync::Arc<(sync::Mutex<bool>, sync::Condvar)>,
}

static CREATE_DS: sync::Once = sync::ONCE_INIT;
static mut DRIVER_STATION: *mut DriverStation = 0 as *mut DriverStation;

#[derive(Debug, Copy, Clone)]
pub enum JoystickError {
    JoystickDNE,
    ChannelUnplugged,
    ChannelDNE,
}

#[derive(Debug, Copy, Clone)]
pub enum AllianceId {
    Red,
    Blue,
    Invalid,
}

impl DriverStation {
    fn new() -> DriverStation {
        let mut data_atom = sync::Arc::new(Atom::empty());
        let mut waiter = sync::Arc::new((sync::Mutex::new(false), sync::Condvar::new()));

        let mut ds = DriverStation {
            data: data_atom,
            joysticks: Joysticks::default(),
            state: RobotState::Disabled,
            fms_attached: false,
            ds_attached: false,

            // For now use an interval of 0 so we don't actually throttle messages, as the FPGA
            // timer isn't implemented yet.
            report_throttler: Throttler::new(0.0, 0.0),

            waiter: waiter,
        };

        ds.spawn_updater();
        ds
    }

    /// Spawn the updater thread. This should not be called after the constructor is finished.
    fn spawn_updater(&mut self) {
        let mut data_atom = self.data.clone();
        let mut waiter = self.waiter.clone();

        let join = thread::spawn(move || {
            loop {
                // Wait for the HAL to get new data
                unsafe {
                    HAL_WaitForDSData();
                }

                // Update the joysticks and control word using the new data.
                let mut joysticks = Joysticks::default();
                for stick in 0..MAX_JOYSTICK_PORTS {
                    unsafe {
                        HAL_GetJoystickAxes(stick as i32,
                                            &mut joysticks.axes[stick] as *mut HAL_JoystickAxes);
                        HAL_GetJoystickPOVs(stick as i32,
                                            &mut joysticks.povs[stick] as *mut HAL_JoystickPOVs);
                        HAL_GetJoystickButtons(stick as i32,
                                                    &mut joysticks.buttons[stick] as
                                                    *mut HAL_JoystickButtons);
                        HAL_GetJoystickDescriptor(stick as i32,
                                                       &mut joysticks.descriptor[stick] as
                                                       *mut HAL_JoystickDescriptor);
                    }
                }

                let mut control_word: HAL_ControlWord = HAL_ControlWord::default();
                unsafe {
                    HAL_GetControlWord(&mut control_word as *mut HAL_ControlWord);
                }

                // Write that data into the atom for usage by callers
                data_atom.swap(Box::new((joysticks, control_word)));

                // Notify any threads waiting for data
                {
                    let mut guard = waiter.0.lock().unwrap();
                    *guard = true;
                    waiter.1.notify_all();
                }
            }
        });
    }

    /// Read new joystick and control word data
    fn update_data(&mut self) {
        if let Some(boxed_data) = self.data.take() {
            let new_control_word = boxed_data.1;
            self.joysticks = boxed_data.0;
            self.state = if new_control_word.enabled() {
                if new_control_word.autonomous() {
                    RobotState::Autonomous
                } else {
                    RobotState::Teleop
                }
            } else if new_control_word.eStop() {
                RobotState::EStop
            } else {
                RobotState::Disabled
            };
            self.fms_attached = new_control_word.fmsAttached();
            self.ds_attached = new_control_word.dsAttached();
        }
    }

    /// Report an error to the driver station in its most general form. Don't use this directly,
    /// instead use it in other error reporting methods.
    fn report(&self, is_error: bool, code: i32, error: &str, location: &str, stack: &str) {
        unsafe {
            HAL_SendError(is_error as i32,
                          code,
                          false as i32,
                          ffi::CString::new(error).unwrap().into_raw(),
                          ffi::CString::new(location).unwrap().into_raw(),
                          ffi::CString::new(stack).unwrap().into_raw(),
                          true as i32);
        }
    }

    fn report_error(&mut self, error: &str) {
        self.report(true, 1, error, "", "");
    }

    fn report_warning(&mut self, warning: &str) {
        self.report(false, 1, warning, "", "");
    }

    /// Report a message at a throttled rate
    fn report_throttled(&mut self, is_error: bool, message: &str) {
        // Don't actually throttle it; FPGA timer is unimplemented
        let now = 1f64;
        if self.report_throttler.update(now) {
            self.report(is_error, 1, message, "", "");
        }
    }

    /// Get an instance of the driver station. This will create a new instance if one does not
    /// exist.
    pub fn instance() -> &'static mut DriverStation {
        unsafe {
            CREATE_DS.call_once(|| {
                DRIVER_STATION = mem::transmute(Box::new(DriverStation::new()));
            });
            &mut *DRIVER_STATION
        }
    }

    pub fn get_joystick_axis(&mut self, stick: usize, axis: usize) -> Result<f32, JoystickError> {
        self.update_data();

        if stick >= MAX_JOYSTICK_PORTS {
            self.report_throttled(true, "Bad joystick");
            Err(JoystickError::JoystickDNE)
        } else if axis >= MAX_JOYSTICK_AXES {
            self.report_throttled(true, "Bad joystick axis");
            Err(JoystickError::ChannelDNE)
        } else if axis >= self.joysticks.axes[stick].count as usize {
            self.report_throttled(true,
                                  "Joystick axis missing, check if all controllers are plugged in");
            Err(JoystickError::ChannelUnplugged)
        } else {
            Ok(self.joysticks.axes[stick].axes[axis])
        }
    }

    pub fn get_joystick_pov(&mut self, stick: usize, pov: usize) -> Result<i16, JoystickError> {
        self.update_data();

        if stick >= MAX_JOYSTICK_POVS {
            self.report_throttled(true, "Bad joystick");
            Err(JoystickError::JoystickDNE)
        } else if pov >= MAX_JOYSTICK_AXES {
            self.report_throttled(true, "Bad joystick pov");
            Err(JoystickError::ChannelDNE)
        } else if pov >= self.joysticks.povs[stick].count as usize {
            self.report_throttled(true,
                                  "Joystick pov missing, check if all controllers are plugged in");
            Err(JoystickError::ChannelUnplugged)
        } else {
            Ok(self.joysticks.povs[stick].povs[pov])
        }
    }

    pub fn get_joystick_button(&mut self,
                               stick: usize,
                               button: usize)
                               -> Result<bool, JoystickError> {
        self.update_data();

        if stick >= MAX_JOYSTICK_POVS {
            self.report_throttled(true, "Bad joystick");
            Err(JoystickError::JoystickDNE)
        } else if button == 0 {
            self.report_throttled(true, "Bad joystick button (button IDs start from 1)");
            Err(JoystickError::ChannelDNE)
        } else if button >= self.joysticks.povs[stick].count as usize {
            self.report_throttled(true,
                                  "Joystick button missing, check if all controllers are plugged \
                                   in");
            Err(JoystickError::ChannelUnplugged)
        } else {
            let mask = 1 << (button - 1);
            Ok(self.joysticks.buttons[stick].buttons & mask != 0)
        }
    }

    pub fn get_alliance(&self) -> HalResult<AllianceId> {
        match hal_call!(HAL_GetAllianceStation())? {
            HAL_AllianceStationID::HAL_AllianceStationID_kRed1 |
            HAL_AllianceStationID::HAL_AllianceStationID_kRed2 |
            HAL_AllianceStationID::HAL_AllianceStationID_kRed3 => Ok(AllianceId::Red),
            HAL_AllianceStationID::HAL_AllianceStationID_kBlue1 |
            HAL_AllianceStationID::HAL_AllianceStationID_kBlue2 |
            HAL_AllianceStationID::HAL_AllianceStationID_kBlue3 => Ok(AllianceId::Blue),
        }
    }

    pub fn get_station(&self) -> HalResult<i32> {
        match hal_call!(HAL_GetAllianceStation())? {
            HAL_AllianceStationID::HAL_AllianceStationID_kRed1 |
            HAL_AllianceStationID::HAL_AllianceStationID_kBlue1 => Ok(1),
            HAL_AllianceStationID::HAL_AllianceStationID_kRed2 |
            HAL_AllianceStationID::HAL_AllianceStationID_kBlue2 => Ok(2),
            HAL_AllianceStationID::HAL_AllianceStationID_kRed3 |
            HAL_AllianceStationID::HAL_AllianceStationID_kBlue3 => Ok(3),
        }
    }

    /// Waits for a new driver station packet
    pub fn wait_for_data(&self) {
        let &(ref wait_lock, ref wait_cond) = &*self.waiter;
        let mut has_data = wait_lock.lock().unwrap();
        while !*has_data {
            has_data = wait_cond.wait(has_data).unwrap();
        }
    }

    /// Waits for a new driver station packet and returns true, or returns false if timeout is
    /// exceeded.
    pub fn wait_for_data_or_timeout(&self, timeout: time::Duration) -> bool {
        let &(ref wait_lock, ref wait_cond) = &*self.waiter;
        let mut has_data = wait_lock.lock().unwrap();

        while !*has_data {
            let result = wait_cond.wait_timeout(has_data, timeout).unwrap();
            if result.1.timed_out() {
                return false;
            } else {
                has_data = result.0;
            }
        }
        true
    }
}
<|endoftext|>