<commit_before>#![allow(
    clippy::decimal_literal_representation,
    clippy::derive_partial_eq_without_eq,
    clippy::unreadable_literal,
    clippy::shadow_unrelated
)]

use indoc::indoc;
use serde_derive::{Deserialize, Serialize};
use serde_yaml::Value;
use std::collections::BTreeMap;
use std::fmt::Debug;

fn test_serde<T>(thing: &T, yaml: &str)
where
    T: serde::Serialize + serde::de::DeserializeOwned + PartialEq + Debug,
{
    let serialized = serde_yaml::to_string(&thing).unwrap();
    assert_eq!(yaml, serialized);

    let value = serde_yaml::to_value(&thing).unwrap();
    let serialized = serde_yaml::to_string(&value).unwrap();
    assert_eq!(yaml, serialized);

    let deserialized: T = serde_yaml::from_str(yaml).unwrap();
    assert_eq!(*thing, deserialized);

    let value: Value = serde_yaml::from_str(yaml).unwrap();
    let deserialized: T = serde_yaml::from_value(value).unwrap();
    assert_eq!(*thing, deserialized);

    serde_yaml::from_str::<serde::de::IgnoredAny>(yaml).unwrap();
}

#[test]
fn test_default() {
    assert_eq!(Value::default(), Value::Null);
}

#[test]
fn test_int() {
    let thing = 256;
    let yaml = indoc! {"
        256
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_int_max_u64() {
    let thing = u64::MAX;
    let yaml = indoc! {"
        18446744073709551615
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_int_min_i64() {
    let thing = i64::MIN;
    let yaml = indoc! {"
        -9223372036854775808
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_int_max_i64() {
    let thing = i64::MAX;
    let yaml = indoc! {"
        9223372036854775807
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_i128_small() {
    let thing: i128 = -256;
    let yaml = indoc! {"
        -256
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_u128_small() {
    let thing: u128 = 256;
    let yaml = indoc! {"
        256
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_float() {
    let thing = 25.6;
    let yaml = indoc! {"
        25.6
    "};
    test_serde(&thing, yaml);

    let thing = 25.;
    let yaml = indoc! {"
        25.0
    "};
    test_serde(&thing, yaml);

    let thing = f64::INFINITY;
    let yaml = indoc! {"
        .inf
    "};
    test_serde(&thing, yaml);

    let thing = f64::NEG_INFINITY;
    let yaml = indoc! {"
        -.inf
    "};
    test_serde(&thing, yaml);

    let float: f64 = serde_yaml::from_str(indoc! {"
        .nan
    "})
    .unwrap();
    assert!(float.is_nan());
}

#[test]
fn test_float32() {
    let thing: f32 = 25.5;
    let yaml = indoc! {"
        25.5
    "};
    test_serde(&thing, yaml);

    let thing = f32::INFINITY;
    let yaml = indoc! {"
        .inf
    "};
    test_serde(&thing, yaml);

    let thing = f32::NEG_INFINITY;
    let yaml = indoc! {"
        -.inf
    "};
    test_serde(&thing, yaml);

    let single_float: f32 = serde_yaml::from_str(indoc! {"
        .nan
    "})
    .unwrap();
    assert!(single_float.is_nan());
}

#[test]
fn test_vec() {
    let thing = vec![1, 2, 3];
    let yaml = indoc! {"
        - 1
        - 2
        - 3
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_map() {
    let mut thing = BTreeMap::new();
    thing.insert("x".to_owned(), 1);
    thing.insert("y".to_owned(), 2);
    let yaml = indoc! {"
        x: 1
        y: 2
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_basic_struct() {
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    struct Basic {
        x: isize,
        y: String,
        z: bool,
    }
    let thing = Basic {
        x: -4,
        y: "hi\tquoted".to_owned(),
        z: true,
    };
    let yaml = indoc! {r#"
        x: -4
        y: "hi\tquoted"
        z: true
    "#};
    test_serde(&thing, yaml);
}

#[test]
fn test_nested_vec() {
    let thing = vec![vec![1, 2, 3], vec![4, 5, 6]];
    let yaml = indoc! {"
        - - 1
          - 2
          - 3
        - - 4
          - 5
          - 6
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_nested_struct() {
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    struct Outer {
        inner: Inner,
    }
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    struct Inner {
        v: u16,
    }
    let thing = Outer {
        inner: Inner { v: 512 },
    };
    let yaml = indoc! {"
        inner:
          v: 512
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_option() {
    let thing = vec![Some(1), None, Some(3)];
    let yaml = indoc! {"
        - 1
        - null
        - 3
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_unit() {
    let thing = vec![(), ()];
    let yaml = indoc! {"
        - null
        - null
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_unit_struct() {
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    struct Foo;
    let thing = Foo;
    let yaml = indoc! {"
        null
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_unit_variant() {
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    enum Variant {
        First,
        Second,
    }
    let thing = Variant::First;
    let yaml = indoc! {"
        First
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_newtype_struct() {
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    struct OriginalType {
        v: u16,
    }
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    struct NewType(OriginalType);
    let thing = NewType(OriginalType { v: 1 });
    let yaml = indoc! {"
        v: 1
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_newtype_variant() {
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    enum Variant {
        Size(usize),
    }
    let thing = Variant::Size(127);
    let yaml = indoc! {"
        Size: 127
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_tuple_variant() {
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    enum Variant {
        Rgb(u8, u8, u8),
    }
    let thing = Variant::Rgb(32, 64, 96);
    let yaml = indoc! {"
        Rgb:
        - 32
        - 64
        - 96
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_struct_variant() {
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    enum Variant {
        Color { r: u8, g: u8, b: u8 },
    }
    let thing = Variant::Color {
        r: 32,
        g: 64,
        b: 96,
    };
    let yaml = indoc! {"
        Color:
          r: 32
          g: 64
          b: 96
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_value() {
    use serde_yaml::{Mapping, Number};

    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    pub struct GenericInstructions {
        #[serde(rename = "type")]
        pub typ: String,
        pub config: Value,
    }
    let thing = GenericInstructions {
        typ: "primary".to_string(),
        config: Value::Sequence(vec![
            Value::Null,
            Value::Bool(true),
            Value::Number(Number::from(65535)),
            Value::Number(Number::from(0.54321)),
            Value::String("s".into()),
            Value::Mapping(Mapping::new()),
        ]),
    };
    let yaml = indoc! {"
        type: primary
        config:
        - null
        - true
        - 65535
        - 0.54321
        - s
        - {}
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_mapping() {
    use serde_yaml::Mapping;
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    struct Data {
        pub substructure: Mapping,
    }

    let mut thing = Data {
        substructure: Mapping::new(),
    };
    thing.substructure.insert(
        Value::String("a".to_owned()),
        Value::String("foo".to_owned()),
    );
    thing.substructure.insert(
        Value::String("b".to_owned()),
        Value::String("bar".to_owned()),
    );

    let yaml = indoc! {"
        substructure:
          a: foo
          b: bar
    "};

    test_serde(&thing, yaml);
}
<commit_msg>Add test with multiline strings<commit_after>#![allow(
    clippy::decimal_literal_representation,
    clippy::derive_partial_eq_without_eq,
    clippy::unreadable_literal,
    clippy::shadow_unrelated
)]

use indoc::indoc;
use serde_derive::{Deserialize, Serialize};
use serde_yaml::Value;
use std::collections::BTreeMap;
use std::fmt::Debug;

fn test_serde<T>(thing: &T, yaml: &str)
where
    T: serde::Serialize + serde::de::DeserializeOwned + PartialEq + Debug,
{
    let serialized = serde_yaml::to_string(&thing).unwrap();
    assert_eq!(yaml, serialized);

    let value = serde_yaml::to_value(&thing).unwrap();
    let serialized = serde_yaml::to_string(&value).unwrap();
    assert_eq!(yaml, serialized);

    let deserialized: T = serde_yaml::from_str(yaml).unwrap();
    assert_eq!(*thing, deserialized);

    let value: Value = serde_yaml::from_str(yaml).unwrap();
    let deserialized: T = serde_yaml::from_value(value).unwrap();
    assert_eq!(*thing, deserialized);

    serde_yaml::from_str::<serde::de::IgnoredAny>(yaml).unwrap();
}

#[test]
fn test_default() {
    assert_eq!(Value::default(), Value::Null);
}

#[test]
fn test_int() {
    let thing = 256;
    let yaml = indoc! {"
        256
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_int_max_u64() {
    let thing = u64::MAX;
    let yaml = indoc! {"
        18446744073709551615
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_int_min_i64() {
    let thing = i64::MIN;
    let yaml = indoc! {"
        -9223372036854775808
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_int_max_i64() {
    let thing = i64::MAX;
    let yaml = indoc! {"
        9223372036854775807
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_i128_small() {
    let thing: i128 = -256;
    let yaml = indoc! {"
        -256
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_u128_small() {
    let thing: u128 = 256;
    let yaml = indoc! {"
        256
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_float() {
    let thing = 25.6;
    let yaml = indoc! {"
        25.6
    "};
    test_serde(&thing, yaml);

    let thing = 25.;
    let yaml = indoc! {"
        25.0
    "};
    test_serde(&thing, yaml);

    let thing = f64::INFINITY;
    let yaml = indoc! {"
        .inf
    "};
    test_serde(&thing, yaml);

    let thing = f64::NEG_INFINITY;
    let yaml = indoc! {"
        -.inf
    "};
    test_serde(&thing, yaml);

    let float: f64 = serde_yaml::from_str(indoc! {"
        .nan
    "})
    .unwrap();
    assert!(float.is_nan());
}

#[test]
fn test_float32() {
    let thing: f32 = 25.5;
    let yaml = indoc! {"
        25.5
    "};
    test_serde(&thing, yaml);

    let thing = f32::INFINITY;
    let yaml = indoc! {"
        .inf
    "};
    test_serde(&thing, yaml);

    let thing = f32::NEG_INFINITY;
    let yaml = indoc! {"
        -.inf
    "};
    test_serde(&thing, yaml);

    let single_float: f32 = serde_yaml::from_str(indoc! {"
        .nan
    "})
    .unwrap();
    assert!(single_float.is_nan());
}

#[test]
fn test_vec() {
    let thing = vec![1, 2, 3];
    let yaml = indoc! {"
        - 1
        - 2
        - 3
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_map() {
    let mut thing = BTreeMap::new();
    thing.insert("x".to_owned(), 1);
    thing.insert("y".to_owned(), 2);
    let yaml = indoc! {"
        x: 1
        y: 2
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_basic_struct() {
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    struct Basic {
        x: isize,
        y: String,
        z: bool,
    }
    let thing = Basic {
        x: -4,
        y: "hi\tquoted".to_owned(),
        z: true,
    };
    let yaml = indoc! {r#"
        x: -4
        y: "hi\tquoted"
        z: true
    "#};
    test_serde(&thing, yaml);
}

#[test]
fn test_multiline_string() {
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    struct Struct {
        trailing_newline: String,
        no_trailing_newline: String,
    }
    let thing = Struct {
        trailing_newline: "aaa\nbbb\n".to_owned(),
        no_trailing_newline: "aaa\nbbb".to_owned(),
    };
    let yaml = indoc! {r#"
        trailing_newline: 'aaa

          bbb

          '
        no_trailing_newline: 'aaa

          bbb'
    "#};
    test_serde(&thing, yaml);
}

#[test]
fn test_nested_vec() {
    let thing = vec![vec![1, 2, 3], vec![4, 5, 6]];
    let yaml = indoc! {"
        - - 1
          - 2
          - 3
        - - 4
          - 5
          - 6
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_nested_struct() {
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    struct Outer {
        inner: Inner,
    }
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    struct Inner {
        v: u16,
    }
    let thing = Outer {
        inner: Inner { v: 512 },
    };
    let yaml = indoc! {"
        inner:
          v: 512
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_option() {
    let thing = vec![Some(1), None, Some(3)];
    let yaml = indoc! {"
        - 1
        - null
        - 3
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_unit() {
    let thing = vec![(), ()];
    let yaml = indoc! {"
        - null
        - null
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_unit_struct() {
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    struct Foo;
    let thing = Foo;
    let yaml = indoc! {"
        null
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_unit_variant() {
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    enum Variant {
        First,
        Second,
    }
    let thing = Variant::First;
    let yaml = indoc! {"
        First
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_newtype_struct() {
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    struct OriginalType {
        v: u16,
    }
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    struct NewType(OriginalType);
    let thing = NewType(OriginalType { v: 1 });
    let yaml = indoc! {"
        v: 1
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_newtype_variant() {
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    enum Variant {
        Size(usize),
    }
    let thing = Variant::Size(127);
    let yaml = indoc! {"
        Size: 127
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_tuple_variant() {
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    enum Variant {
        Rgb(u8, u8, u8),
    }
    let thing = Variant::Rgb(32, 64, 96);
    let yaml = indoc! {"
        Rgb:
        - 32
        - 64
        - 96
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_struct_variant() {
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    enum Variant {
        Color { r: u8, g: u8, b: u8 },
    }
    let thing = Variant::Color {
        r: 32,
        g: 64,
        b: 96,
    };
    let yaml = indoc! {"
        Color:
          r: 32
          g: 64
          b: 96
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_value() {
    use serde_yaml::{Mapping, Number};

    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    pub struct GenericInstructions {
        #[serde(rename = "type")]
        pub typ: String,
        pub config: Value,
    }
    let thing = GenericInstructions {
        typ: "primary".to_string(),
        config: Value::Sequence(vec![
            Value::Null,
            Value::Bool(true),
            Value::Number(Number::from(65535)),
            Value::Number(Number::from(0.54321)),
            Value::String("s".into()),
            Value::Mapping(Mapping::new()),
        ]),
    };
    let yaml = indoc! {"
        type: primary
        config:
        - null
        - true
        - 65535
        - 0.54321
        - s
        - {}
    "};
    test_serde(&thing, yaml);
}

#[test]
fn test_mapping() {
    use serde_yaml::Mapping;
    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    struct Data {
        pub substructure: Mapping,
    }

    let mut thing = Data {
        substructure: Mapping::new(),
    };
    thing.substructure.insert(
        Value::String("a".to_owned()),
        Value::String("foo".to_owned()),
    );
    thing.substructure.insert(
        Value::String("b".to_owned()),
        Value::String("bar".to_owned()),
    );

    let yaml = indoc! {"
        substructure:
          a: foo
          b: bar
    "};

    test_serde(&thing, yaml);
}
<|endoftext|>


<commit_before>fn use(_i: int) {}

fn foo() {
    // Here, i is *moved* into the closure: Not actually OK
    let mut i = 0;
    do task::spawn {
        use(i); //~ ERROR mutable variables cannot be implicitly captured
    }
}

fn bar() {
    // Here, i would be implicitly *copied* but it
    // is mutable: bad
    let mut i = 0;
    while i < 10 {
        do task::spawn {
            use(i); //~ ERROR mutable variables cannot be implicitly captured
        }
        i += 1;
    }
}

fn car() {
    // Here, i is mutable, but *explicitly* copied:
    let mut i = 0;
    while i < 10 {
        do task::spawn |copy i| {
            use(i);
        }
        i += 1;
    }
}

fn main() {
}
<commit_msg>Dodge 'use' keyword in testsuite. Was burning tree.<commit_after>fn user(_i: int) {}

fn foo() {
    // Here, i is *moved* into the closure: Not actually OK
    let mut i = 0;
    do task::spawn {
        user(i); //~ ERROR mutable variables cannot be implicitly captured
    }
}

fn bar() {
    // Here, i would be implicitly *copied* but it
    // is mutable: bad
    let mut i = 0;
    while i < 10 {
        do task::spawn {
            use(i); //~ ERROR mutable variables cannot be implicitly captured
        }
        i += 1;
    }
}

fn car() {
    // Here, i is mutable, but *explicitly* copied:
    let mut i = 0;
    while i < 10 {
        do task::spawn |copy i| {
            use(i);
        }
        i += 1;
    }
}

fn main() {
}
<|endoftext|>


<commit_before>#![feature(test)]

#[macro_use]
extern crate maplit;
extern crate test;
extern crate abra;

use test::Bencher;

use abra::term::Term;
use abra::token::Token;
use abra::document::Document;
use abra::store::{IndexStore, IndexReader};
use abra::store::memory::{MemoryIndexStore, MemoryIndexStoreReader};
use abra::query_set::QuerySetIterator;

fn make_test_store() -> MemoryIndexStore {
    let mut store = MemoryIndexStore::new();

    for i in 0..10000 {
        let mut tokens = Vec::new();

        if i % 3 == 0 {
            let position = tokens.len() as u32 + 1;
            tokens.push(Token {
                term: Term::String("fizz".to_string()),
                position: position,
            });
        }

        if i % 5 == 0 {
            let position = tokens.len() as u32 + 1;
            tokens.push(Token {
                term: Term::String("buzz".to_string()),
                position: position,
            });
        }

        store.insert_or_update_document(Document {
            key: i.to_string(),
            fields: btreemap! {
                "body".to_string() => tokens
            }
        });
    }

    store
}

#[bench]
fn bench_all(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();

    b.iter(|| {
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::All {
            iter: reader.iter_docids_all(),
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_fizz_term(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();

    let fizz_term = Term::String("fizz".to_string()).to_bytes();

    b.iter(|| {
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&fizz_term, "body").unwrap(),
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_buzz_term(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();

    let buzz_term = Term::String("buzz".to_string()).to_bytes();

    b.iter(|| {
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&buzz_term, "body").unwrap(),
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_fizzbuzz_conjunction(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();

    let fizz_term = Term::String("fizz".to_string()).to_bytes();
    let buzz_term = Term::String("buzz".to_string()).to_bytes();

    b.iter(|| {
        let mut fizz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&fizz_term, "body").unwrap(),
        };
        let mut buzz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&buzz_term, "body").unwrap(),
        };
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Conjunction {
            iter_a: Box::new(fizz_iterator),
            iter_b: Box::new(buzz_iterator),
            initialised: false,
            current_doc_a: None,
            current_doc_b: None,
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_fizzbuzz_disjunction(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();

    let fizz_term = Term::String("fizz".to_string()).to_bytes();
    let buzz_term = Term::String("buzz".to_string()).to_bytes();

    b.iter(|| {
        let mut fizz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&fizz_term, "body").unwrap(),
        };
        let mut buzz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&buzz_term, "body").unwrap(),
        };
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Disjunction {
            iter_a: Box::new(fizz_iterator),
            iter_b: Box::new(buzz_iterator),
            initialised: false,
            current_doc_a: None,
            current_doc_b: None,
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_fizzbuzz_exclusion(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();

    let fizz_term = Term::String("fizz".to_string()).to_bytes();
    let buzz_term = Term::String("buzz".to_string()).to_bytes();

    b.iter(|| {
        let mut fizz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&fizz_term, "body").unwrap(),
        };
        let mut buzz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&buzz_term, "body").unwrap(),
        };
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Exclusion {
            iter_a: Box::new(fizz_iterator),
            iter_b: Box::new(buzz_iterator),
            initialised: false,
            current_doc_a: None,
            current_doc_b: None,
        };

        for doc_id in iterator {}
    });
}
<commit_msg>Updated benchmarks for schema changes<commit_after>#![feature(test)]

#[macro_use]
extern crate maplit;
extern crate test;
extern crate abra;

use test::Bencher;

use abra::term::Term;
use abra::token::Token;
use abra::schema::FieldType;
use abra::document::Document;
use abra::store::{IndexStore, IndexReader};
use abra::store::memory::{MemoryIndexStore, MemoryIndexStoreReader};
use abra::query_set::QuerySetIterator;

fn make_test_store() -> MemoryIndexStore {
    let mut store = MemoryIndexStore::new();
    let body_field = store.add_field("body".to_string(), FieldType::Text).unwrap();

    for i in 0..10000 {
        let mut tokens = Vec::new();

        if i % 3 == 0 {
            let position = tokens.len() as u32 + 1;
            tokens.push(Token {
                term: Term::String("fizz".to_string()),
                position: position,
            });
        }

        if i % 5 == 0 {
            let position = tokens.len() as u32 + 1;
            tokens.push(Token {
                term: Term::String("buzz".to_string()),
                position: position,
            });
        }

        store.insert_or_update_document(Document {
            key: i.to_string(),
            fields: hashmap! {
                body_field => tokens
            }
        });
    }

    store
}

#[bench]
fn bench_all(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();

    b.iter(|| {
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::All {
            iter: reader.iter_docids_all(),
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_fizz_term(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();
    let body_field = reader.schema().get_field_by_name("body").unwrap();

    let fizz_term = Term::String("fizz".to_string()).to_bytes();

    b.iter(|| {
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&fizz_term, &body_field).unwrap(),
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_buzz_term(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();
    let body_field = reader.schema().get_field_by_name("body").unwrap();

    let buzz_term = Term::String("buzz".to_string()).to_bytes();

    b.iter(|| {
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&buzz_term, &body_field).unwrap(),
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_fizzbuzz_conjunction(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();
    let body_field = reader.schema().get_field_by_name("body").unwrap();

    let fizz_term = Term::String("fizz".to_string()).to_bytes();
    let buzz_term = Term::String("buzz".to_string()).to_bytes();

    b.iter(|| {
        let mut fizz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&fizz_term, &body_field).unwrap(),
        };
        let mut buzz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&buzz_term, &body_field).unwrap(),
        };
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Conjunction {
            iter_a: Box::new(fizz_iterator),
            iter_b: Box::new(buzz_iterator),
            initialised: false,
            current_doc_a: None,
            current_doc_b: None,
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_fizzbuzz_disjunction(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();
    let body_field = reader.schema().get_field_by_name("body").unwrap();

    let fizz_term = Term::String("fizz".to_string()).to_bytes();
    let buzz_term = Term::String("buzz".to_string()).to_bytes();

    b.iter(|| {
        let mut fizz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&fizz_term, &body_field).unwrap(),
        };
        let mut buzz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&buzz_term, &body_field).unwrap(),
        };
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Disjunction {
            iter_a: Box::new(fizz_iterator),
            iter_b: Box::new(buzz_iterator),
            initialised: false,
            current_doc_a: None,
            current_doc_b: None,
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_fizzbuzz_exclusion(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();
    let body_field = reader.schema().get_field_by_name("body").unwrap();

    let fizz_term = Term::String("fizz".to_string()).to_bytes();
    let buzz_term = Term::String("buzz".to_string()).to_bytes();

    b.iter(|| {
        let mut fizz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&fizz_term, &body_field).unwrap(),
        };
        let mut buzz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&buzz_term, &body_field).unwrap(),
        };
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Exclusion {
            iter_a: Box::new(fizz_iterator),
            iter_b: Box::new(buzz_iterator),
            initialised: false,
            current_doc_a: None,
            current_doc_b: None,
        };

        for doc_id in iterator {}
    });
}
<|endoftext|>


<commit_before>extern crate piston_window;

extern crate turtleide;

use canvas::{TurtleCanvas, Command, Radians};

fn main() {
    let canvas = TurtleCanvas::new();

    let dashed = false;
    for i in 0..361 {
        if dashed {
            canvas.apply(Command::Pen {
                enabled: i % 2 == 0,
            });
        }
        canvas.apply(Command::Move {
            distance: 2.,
        });
        canvas.apply(Command::Rotate {
            angle: Radians(1f64.to_radians()),
            clockwise: true,
        });
    }
}

mod canvas {
    use std::thread;
    use std::process;
    use std::time::{Instant, Duration};
    use std::sync::mpsc::{self, TryRecvError};
    use std::ops::{Add, Sub, Mul, Div, Rem, Neg};
    use std::f64::consts::PI;

    use piston_window::*;

    use turtleide::Speed;

    #[derive(Default, Clone, Copy, Debug, PartialOrd, PartialEq)]
    pub struct Radians(pub f64);

    impl Radians {
        pub fn cos(self) -> f64 {
            self.0.cos()
        }

        pub fn sin(self) -> f64 {
            self.0.sin()
        }
    }

    impl Add for Radians {
        type Output = Self;

        fn add(self, other: Self) -> Self {
            Radians(self.0 + other.0)
        }
    }

    impl Sub for Radians {
        type Output = Self;

        fn sub(self, other: Self) -> Self {
            Radians(self.0 - other.0)
        }
    }

    impl Mul<f64> for Radians {
        type Output = Self;

        fn mul(self, other: f64) -> Self {
            Radians(self.0 * other)
        }
    }

    impl Div<f64> for Radians {
        type Output = Self;

        fn div(self, other: f64) -> Self {
            Radians(self.0 / other)
        }
    }

    impl Rem<f64> for Radians {
        type Output = Self;

        fn rem(self, other: f64) -> Self {
            Radians(self.0 % other)
        }
    }

    impl Neg for Radians {
        type Output = Self;

        fn neg(self) -> Self {
            Radians(-self.0)
        }
    }

    trait ToCanvasCoordinates : Copy {
        fn to_canvas_coords(self, center: [f64; 2]) -> Self;
    }

    impl ToCanvasCoordinates for [f64; 2] {
        /// Transforms the given local coordinate into a point that can be drawn on the canvas.
        ///
        /// Takes into account the direction of the axis and center when converting
        /// `local` from cartesian coordinates.
        ///
        /// Origin in window is the top left corner and the y-axis goes down instead of up.
        fn to_canvas_coords(self, center: [f64; 2]) -> [f64; 2] {
            [center[0] + self[0], center[1] - self[1]]
        }
    }

    trait AsMillis {
        fn as_millis(&self) -> u64;
    }

    impl AsMillis for Duration {
        fn as_millis(&self) -> u64 {
            self.as_secs() * 1000 + (self.subsec_nanos() / 1_000_000) as u64
        }
    }

    pub enum Command {
        Move {
            distance: f64,
        },
        Rotate {
            angle: Radians,
            clockwise: bool,
        },
        Pen {
            enabled: bool,
        },
    }

    #[derive(Debug, Clone, Copy)]
    pub enum Color {
        Black,
        White,
        Transparent,
    }

    impl From<Color> for types::Color {
        fn from(color: Color) -> Self {
            match color {
                Color::Black => [0., 0., 0., 255.],
                Color::White => [255., 255., 255., 255.],
                Color::Transparent => [0., 0., 0., 0.],
            }
        }
    }

    #[derive(Debug, Clone)]
    struct Path {
        start: [f64; 2],
        end: [f64; 2],
        pen: Pen,
    }

    type Response = Result<(), ()>;

    struct TurtleState {
        pub position: [f64; 2],
        pub heading: Radians,
        pub speed: Speed,
    }

    impl Default for TurtleState {
        fn default() -> TurtleState {
            TurtleState {
                position: Default::default(),
                heading: Radians(90f64.to_radians()),
                speed: Speed::Instant,
            }
        }
    }

    struct DrawingState {
        pen: Pen,
        //pub background: Color,
    }

    #[derive(Debug, Clone)]
    struct Pen {
        pub enabled: bool,
        pub thickness: f64,
        pub color: Color,
    }

    struct Animation {
        kind: AnimationKind,
        speed: Speed,
        start: Instant,
    }

    enum AnimationKind {
        Move {
            path: Path,
        },
        Rotation {
            target_angle: Radians,
            clockwise: bool,
        },
    }

    pub struct TurtleCanvas {
        thread_handle: Option<thread::JoinHandle<()>>,
        transmitter: mpsc::Sender<Command>,
        receiver: mpsc::Receiver<Response>,
    }

    impl TurtleCanvas {
        pub fn new() -> TurtleCanvas {
            let (drawing_tx, drawing_rx) = mpsc::channel();
            let (main_tx, main_rx) = mpsc::channel();

            let handle = thread::spawn(move || {
                let mut window: PistonWindow = WindowSettings::new(
                    "Turtle IDE", [800, 600]
                ).exit_on_esc(true).build().unwrap();
                let mut paths: Vec<Path> = Vec::new();
                let mut animation: Option<Animation> = None;
                let mut turtle = TurtleState::default();
                let mut drawing = DrawingState {
                    pen: Pen {
                        enabled: true,
                        thickness: 1.,
                        color: Color::Black,
                    },
                };

                while let Some(e) = window.next() {
                    match drawing_rx.try_recv() {
                        Ok(command) => {
                            if animation.is_some() {
                                unreachable!("The main thread did not wait for the animation to complete before sending another command")
                            }
                            match command {
                                Command::Move {distance} => {
                                    if distance != 0. {
                                        let start = turtle.position;
                                        let x = distance * turtle.heading.cos();
                                        let y = distance * turtle.heading.sin();
                                        let end = math::add(start, [x, y]);
                                        animation = Some(Animation {
                                            kind: AnimationKind::Move {
                                                path: Path {
                                                    start, end,
                                                    pen: drawing.pen.clone(),
                                                },
                                            },
                                            speed: turtle.speed,
                                            start: Instant::now(),
                                        });
                                    }
                                },
                                Command::Rotate {angle, clockwise} => {
                                    if angle != Radians(0.) {
                                        let target_angle = turtle.heading + if clockwise {
                                            -angle
                                        }
                                        else {
                                            angle
                                        };
                                        assert!(target_angle != turtle.heading);
                                        animation = Some(Animation {
                                            kind: AnimationKind::Rotation {
                                                target_angle,
                                                clockwise,
                                            },
                                            speed: turtle.speed,
                                            start: Instant::now(),
                                        });
                                    }
                                },
                                Command::Pen {enabled} => {
                                    drawing.pen.enabled = enabled;
                                    main_tx.send(Ok(())).unwrap();
                                },
                            }
                        },
                        Err(TryRecvError::Empty) => {}, // Do nothing
                        Err(TryRecvError::Disconnected) => break, // Quit
                    }

                    window.draw_2d(&e, |c, g| {
                        clear([1.0; 4], g);

                        let view = c.get_view_size();
                        let width = view[0] as f64;
                        let height = view[1] as f64;
                        let center = [width * 0.5, height * 0.5];

                        let mut animation_complete = false;
                        if let Some(Animation {ref kind, ref speed, ref start}) = animation {
                            let elapsed = start.elapsed().as_millis() as f64;

                            match *kind {
                                AnimationKind::Move {ref path} => {
                                    // This code finds the point on the line between start and
                                    // end that we are supposed to be at right now using some
                                    // vector math.
                                    //
                                    // The basic idea is to find the vector that represents the
                                    // line between start and end, normalize it into a direction,
                                    // and then scale that vector to be the size that it should be
                                    // at the elapsed time based on the speed.
                                    let &Path {start, end, ref pen} = path;
                                    let speed = speed.to_absolute(); // px per second
                                    let path_line = math::sub(start, end);
                                    let path_length = math::square_len(path_line).sqrt();
                                    let direction = math::mul_scalar(path_line, 1./path_length);
                                    debug_assert_eq!((math::square_len(direction).sqrt() * 1000.).round(), 1000.);
                                    // (px / sec) * (sec / 1000ms) * ms => px
                                    let offset = math::mul_scalar(direction, speed / 1000. * elapsed);
                                    let offset_length = math::square_len(offset).sqrt();

                                    let current = if speed.is_infinite() || offset_length >= path_length {
                                        paths.push(path.clone());
                                        animation_complete = true;
                                        end
                                    }
                                    else {
                                        math::add(start, offset)
                                    };

                                    turtle.position = current;

                                    let &Pen {thickness, color, enabled} = pen;
                                    if enabled {
                                        let start = start.to_canvas_coords(center);
                                        let current = current.to_canvas_coords(center);

                                        line(color.into(), thickness,
                                            [start[0], start[1], current[0], current[1]],
                                            c.transform, g);
                                    }
                                },
                                AnimationKind::Rotation {target_angle, clockwise} => {
                                    // TODO: Use the returned value in Radians and impl Div for Radians
                                    let speed = Radians(speed.to_rotation());
                                    let target_angle = target_angle % (2.*PI);

                                    let heading = turtle.heading;
                                    let current = (heading + speed / 1000. * elapsed) % (2.*PI);
                                    let current = if speed.0.is_infinite() || current > target_angle {
                                        animation_complete = true;
                                        target_angle
                                    }
                                    else {
                                        let current = if clockwise {
                                            Radians(2.*PI) - current
                                        } else { current };

                                        current
                                    };
                                    assert!(!current.0.is_nan(), "heading became NaN");
                                    turtle.heading = current;
                                },
                            }
                        }
                        if animation_complete {
                            animation = None;
                            main_tx.send(Ok(())).unwrap();
                        }

                        for path in &paths {
                            if !path.pen.enabled {
                                continue;
                            }

                            let Path {start, end, ref pen} = *path;
                            let start = start.to_canvas_coords(center);
                            let end = end.to_canvas_coords(center);

                            line(pen.color.into(), pen.thickness,
                                [start[0], start[1], end[0], end[1]],
                                c.transform, g);
                        }

                        // Draw the turtle's shell
                        let cos = turtle.heading.cos();
                        let sin = turtle.heading.sin();
                        let turtle_x = turtle.position[0];
                        let turtle_y = turtle.position[1];
                        let shell: Vec<_> = [
                            [0., 15.],
                            [10., 0.],
                            [0., -15.],
                        ].into_iter().map(|pt| {
                            // Rotate each point by the heading and add the current turtle position
                            let x = cos * pt[0] - sin * pt[1] + turtle_x;
                            let y = sin * pt[0] + cos * pt[1] + turtle_y;
                            [x, y].to_canvas_coords(center)
                        }).collect();

                        polygon(Color::White.into(), &shell, c.transform, g);
                        for i in 0..shell.len() {
                            let start = shell[i];
                            let end = shell[(i + 1) % shell.len()];

                            line(Color::Black.into(), 1.,
                                [start[0], start[1], end[0], end[1]],
                                c.transform, g);
                        }
                    });
                }
            });

            Self {
                thread_handle: Some(handle),
                transmitter: drawing_tx,
                receiver: main_rx,
            }
        }

        pub fn apply(&self, command: Command) {
            let result = self.transmitter.send(command).map_err(|_| ());
            let result = result.and_then(|_| {
                // Wait for the drawing animation to complete
                self.receiver.recv().map_err(|_| ())
            });
            match result {
                Ok(_) => {},
                Err(_) => {
                    // The connection has been closed so the window was closed
                    // or an error occurred on that thread
                    process::exit(0);
                },
            }
        }
    }

    impl Drop for TurtleCanvas {
        fn drop(&mut self) {
            if let Some(handle) = self.thread_handle.take() {
                handle.join().unwrap();
            }
        }
    }
}
<commit_msg>Failed attempt at making things faster using shared memory<commit_after>extern crate piston_window;

extern crate turtleide;

use canvas::{TurtleCanvas, Command, Radians};

fn main() {
    let canvas = TurtleCanvas::new();

    let dashed = false;
    for i in 0..361 {
        if dashed {
            canvas.apply(Command::Pen {
                enabled: i % 2 == 0,
            });
        }
        canvas.apply(Command::Move {
            distance: 2.,
        });
        canvas.apply(Command::Rotate {
            angle: Radians(1f64.to_radians()),
            clockwise: true,
        });
    }
}

mod canvas {
    use std::thread;
    use std::process;
    use std::time::{Instant, Duration};
    use std::sync::{Mutex, MutexGuard, Arc, TryLockError};
    use std::ops::{Add, Sub, Mul, Div, Rem, Neg};
    use std::f64::consts::PI;

    use piston_window::*;

    use turtleide::Speed;

    #[derive(Default, Clone, Copy, Debug, PartialOrd, PartialEq)]
    pub struct Radians(pub f64);

    impl Radians {
        pub fn cos(self) -> f64 {
            self.0.cos()
        }

        pub fn sin(self) -> f64 {
            self.0.sin()
        }
    }

    impl Add for Radians {
        type Output = Self;

        fn add(self, other: Self) -> Self {
            Radians(self.0 + other.0)
        }
    }

    impl Sub for Radians {
        type Output = Self;

        fn sub(self, other: Self) -> Self {
            Radians(self.0 - other.0)
        }
    }

    impl Mul<f64> for Radians {
        type Output = Self;

        fn mul(self, other: f64) -> Self {
            Radians(self.0 * other)
        }
    }

    impl Div<f64> for Radians {
        type Output = Self;

        fn div(self, other: f64) -> Self {
            Radians(self.0 / other)
        }
    }

    impl Rem<f64> for Radians {
        type Output = Self;

        fn rem(self, other: f64) -> Self {
            Radians(self.0 % other)
        }
    }

    impl Neg for Radians {
        type Output = Self;

        fn neg(self) -> Self {
            Radians(-self.0)
        }
    }

    trait ToCanvasCoordinates : Copy {
        fn to_canvas_coords(self, center: [f64; 2]) -> Self;
    }

    impl ToCanvasCoordinates for [f64; 2] {
        /// Transforms the given local coordinate into a point that can be drawn on the canvas.
        ///
        /// Takes into account the direction of the axis and center when converting
        /// `local` from cartesian coordinates.
        ///
        /// Origin in window is the top left corner and the y-axis goes down instead of up.
        fn to_canvas_coords(self, center: [f64; 2]) -> [f64; 2] {
            [center[0] + self[0], center[1] - self[1]]
        }
    }

    trait AsMillis {
        fn as_millis(&self) -> u64;
    }

    impl AsMillis for Duration {
        fn as_millis(&self) -> u64 {
            self.as_secs() * 1000 + (self.subsec_nanos() / 1_000_000) as u64
        }
    }

    pub enum Command {
        Move {
            distance: f64,
        },
        Rotate {
            angle: Radians,
            clockwise: bool,
        },
        Pen {
            enabled: bool,
        },
    }

    #[derive(Debug, Clone, Copy)]
    pub enum Color {
        Black,
        White,
        Transparent,
    }

    impl From<Color> for types::Color {
        fn from(color: Color) -> Self {
            match color {
                Color::Black => [0., 0., 0., 255.],
                Color::White => [255., 255., 255., 255.],
                Color::Transparent => [0., 0., 0., 0.],
            }
        }
    }

    #[derive(Debug, Clone)]
    struct Path {
        start: [f64; 2],
        end: [f64; 2],
        pen: Pen,
    }

    type Response = Result<(), ()>;

    struct TurtleState {
        pub position: [f64; 2],
        pub heading: Radians,
        pub speed: Speed,
    }

    impl Default for TurtleState {
        fn default() -> TurtleState {
            TurtleState {
                position: Default::default(),
                heading: Radians(90f64.to_radians()),
                speed: Speed::Instant,
            }
        }
    }

    struct DrawingState {
        pen: Pen,
        //pub background: Color,
    }

    #[derive(Debug, Clone)]
    struct Pen {
        pub enabled: bool,
        pub thickness: f64,
        pub color: Color,
    }

    struct Animation {
        kind: AnimationKind,
        speed: Speed,
        start: Instant,
    }

    enum AnimationKind {
        Move {
            path: Path,
        },
        Rotation {
            target_angle: Radians,
            clockwise: bool,
        },
    }

    pub struct TurtleCanvas {
        thread_handle: Option<thread::JoinHandle<()>>,
        command: Arc<Mutex<Option<Command>>>,
    }

    impl TurtleCanvas {
        pub fn new() -> TurtleCanvas {
            let command = Arc::new(Mutex::new(None));

            let command_queue = command.clone();
            let handle = thread::spawn(move || {
                let mut window: PistonWindow = WindowSettings::new(
                    "Turtle IDE", [800, 600]
                ).exit_on_esc(true).build().unwrap();
                let mut paths: Vec<Path> = Vec::new();
                let mut animation: Option<Animation> = None;
                let mut turtle = TurtleState::default();
                let mut drawing = DrawingState {
                    pen: Pen {
                        enabled: true,
                        thickness: 1.,
                        color: Color::Black,
                    },
                };
                // Keeps the lock until the animation is complete
                let mut lock: Option<MutexGuard<_>> = None;
                let mut pending_command: Option<Command> = None;

                while let Some(e) = window.next() {
                    match command_queue.try_lock() {
                        Ok(mut command_lock) => {
                            pending_command = command_lock.take();
                            if pending_command.is_some() {
                                // Start the animation and block until it is complete
                                println!("acquired", );
                                lock = Some(command_lock);
                            }
                        },
                        Ok(_) |
                        Err(TryLockError::WouldBlock) => {}, // Do nothing
                        Err(TryLockError::Poisoned(..)) => break, // Quit
                    }

                    if let Some(command) = pending_command.take() {
                        if animation.is_some() {
                            unreachable!("The main thread did not wait for the animation to complete before sending another command")
                        }
                        match command {
                            Command::Move {distance} => {
                                if distance != 0. {
                                    let start = turtle.position;
                                    let x = distance * turtle.heading.cos();
                                    let y = distance * turtle.heading.sin();
                                    let end = math::add(start, [x, y]);
                                    animation = Some(Animation {
                                        kind: AnimationKind::Move {
                                            path: Path {
                                                start, end,
                                                pen: drawing.pen.clone(),
                                            },
                                        },
                                        speed: turtle.speed,
                                        start: Instant::now(),
                                    });
                                }
                            },
                            Command::Rotate {angle, clockwise} => {
                                if angle != Radians(0.) {
                                    let target_angle = turtle.heading + if clockwise {
                                        -angle
                                    }
                                    else {
                                        angle
                                    };
                                    assert!(target_angle != turtle.heading);
                                    animation = Some(Animation {
                                        kind: AnimationKind::Rotation {
                                            target_angle,
                                            clockwise,
                                        },
                                        speed: turtle.speed,
                                        start: Instant::now(),
                                    });
                                }
                            },
                            Command::Pen {enabled} => {
                                drawing.pen.enabled = enabled;
                                println!("released", );
                                lock.take();
                            },
                        }
                    }

                    window.draw_2d(&e, |c, g| {
                        clear([1.0; 4], g);

                        let view = c.get_view_size();
                        let width = view[0] as f64;
                        let height = view[1] as f64;
                        let center = [width * 0.5, height * 0.5];

                        let mut animation_complete = false;
                        if let Some(Animation {ref kind, ref speed, ref start}) = animation {
                            let elapsed = start.elapsed().as_millis() as f64;

                            match *kind {
                                AnimationKind::Move {ref path} => {
                                    // This code finds the point on the line between start and
                                    // end that we are supposed to be at right now using some
                                    // vector math.
                                    //
                                    // The basic idea is to find the vector that represents the
                                    // line between start and end, normalize it into a direction,
                                    // and then scale that vector to be the size that it should be
                                    // at the elapsed time based on the speed.
                                    let &Path {start, end, ref pen} = path;
                                    let speed = speed.to_absolute(); // px per second
                                    let path_line = math::sub(start, end);
                                    let path_length = math::square_len(path_line).sqrt();
                                    let direction = math::mul_scalar(path_line, 1./path_length);
                                    debug_assert_eq!((math::square_len(direction).sqrt() * 1000.).round(), 1000.);
                                    // (px / sec) * (sec / 1000ms) * ms => px
                                    let offset = math::mul_scalar(direction, speed / 1000. * elapsed);
                                    let offset_length = math::square_len(offset).sqrt();

                                    let current = if speed.is_infinite() || offset_length >= path_length {
                                        paths.push(path.clone());
                                        animation_complete = true;
                                        end
                                    }
                                    else {
                                        math::add(start, offset)
                                    };

                                    turtle.position = current;

                                    let &Pen {thickness, color, enabled} = pen;
                                    if enabled {
                                        let start = start.to_canvas_coords(center);
                                        let current = current.to_canvas_coords(center);

                                        line(color.into(), thickness,
                                            [start[0], start[1], current[0], current[1]],
                                            c.transform, g);
                                    }
                                },
                                AnimationKind::Rotation {target_angle, clockwise} => {
                                    // TODO: Use the returned value in Radians and impl Div for Radians
                                    let speed = Radians(speed.to_rotation());
                                    let target_angle = target_angle % (2.*PI);

                                    let heading = turtle.heading;
                                    let current = (heading + speed / 1000. * elapsed) % (2.*PI);
                                    let current = if speed.0.is_infinite() || current > target_angle {
                                        animation_complete = true;
                                        target_angle
                                    }
                                    else {
                                        let current = if clockwise {
                                            Radians(2.*PI) - current
                                        } else { current };

                                        current
                                    };
                                    assert!(!current.0.is_nan(), "heading became NaN");
                                    turtle.heading = current;
                                },
                            }
                        }
                        if animation_complete {
                            animation = None;
                            println!("released", );
                            lock.take();
                        }

                        for path in &paths {
                            if !path.pen.enabled {
                                continue;
                            }

                            let Path {start, end, ref pen} = *path;
                            let start = start.to_canvas_coords(center);
                            let end = end.to_canvas_coords(center);

                            line(pen.color.into(), pen.thickness,
                                [start[0], start[1], end[0], end[1]],
                                c.transform, g);
                        }

                        // Draw the turtle's shell
                        let cos = turtle.heading.cos();
                        let sin = turtle.heading.sin();
                        let turtle_x = turtle.position[0];
                        let turtle_y = turtle.position[1];
                        let shell: Vec<_> = [
                            [0., 15.],
                            [10., 0.],
                            [0., -15.],
                        ].into_iter().map(|pt| {
                            // Rotate each point by the heading and add the current turtle position
                            let x = cos * pt[0] - sin * pt[1] + turtle_x;
                            let y = sin * pt[0] + cos * pt[1] + turtle_y;
                            [x, y].to_canvas_coords(center)
                        }).collect();

                        polygon(Color::White.into(), &shell, c.transform, g);
                        for i in 0..shell.len() {
                            let start = shell[i];
                            let end = shell[(i + 1) % shell.len()];

                            line(Color::Black.into(), 1.,
                                [start[0], start[1], end[0], end[1]],
                                c.transform, g);
                        }
                    });
                }
            });

            Self {
                thread_handle: Some(handle),
                command,
            }
        }

        pub fn apply(&self, command: Command) {
            self.command.lock().map(|mut cmd| {
                println!("{:?}", cmd.is_some());
                *cmd = Some(command);
                println!("placed command", );
            }).map_err(|_| {
                // The connection has been closed so the window was closed
                // or an error occurred on that thread
                process::exit(0);
            });
        }
    }

    impl Drop for TurtleCanvas {
        fn drop(&mut self) {
            if let Some(handle) = self.thread_handle.take() {
                handle.join().unwrap();
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate docopt;
extern crate flac;
extern crate rustc_serialize;

use docopt::Docopt;
use flac::{ReadStream, Stream, StreamProducer};
use flac::metadata;
use flac::metadata::{SeekPoint, VorbisComment};

use std::env;
use std::io;
use std::io::Write;
use std::fs::File;

const USAGE: &'static str = "
Usage: metadata streaminfo [options] <filename>
       metadata comments [options] <filename>
       metadata seektable <filename>
       metadata picture [options] <filename>
       metadata --help

Options:
  --block-size       Show both the max and min block size from StreamInfo.
  --frame-size       Show both the max and min frame size from StreamInfo.
  --sample-rate      Show the sample rate from StreamInfo.
  --channels         Show the number of channels from StreamInfo.
  --bits-per-sample  Show the size in bits for each sample from StreamInfo.
  --total-samples    Show total number of samples from StreamInfo.
  --md5              Show the MD5 signature from StreamInfo.
  --vendor           Show the vendor string from VorbisComment.
  --name=NAME        Show the comments matching the `NAME` from VorbisComment.
  --export=FILE      Export VorbisComment or Picture to file.
  -h, --help         Show this message.
";

#[derive(Debug, RustcDecodable)]
struct Arguments {
  arg_filename: String,
  cmd_streaminfo: bool,
  cmd_comments: bool,
  cmd_seektable: bool,
  cmd_picture: bool,
  flag_block_size: bool,
  flag_frame_size: bool,
  flag_sample_rate: bool,
  flag_channels: bool,
  flag_bits_per_sample: bool,
  flag_total_samples: bool,
  flag_md5: bool,
  flag_vendor: bool,
  flag_name: Option<String>,
  flag_export: Option<String>,
}

macro_rules! format_print (
  ($format_str: expr, $opt_str: expr, $data: expr, $no_flag: expr) => (
    {
      println!($format_str, if $no_flag {
        $opt_str
      } else {
        ""
      }, $data);
    }
  );
);

fn print_stream_info<P>(stream: &Stream<P>, args: &Arguments)
 where P: StreamProducer {
  let info     = stream.info();
  let no_flags = (args.flag_block_size      || args.flag_frame_size    ||
                  args.flag_sample_rate     || args.flag_channels      ||
                  args.flag_bits_per_sample || args.flag_total_samples ||
                  args.flag_md5) == false;

  if no_flags || args.flag_block_size {
    println!("Minimum block size: {} samples", info.min_block_size);
    println!("Maximum block size: {} samples", info.max_block_size);
  }

  if no_flags || args.flag_frame_size {
    println!("Minimum frame size: {} bytes", info.min_frame_size);
    println!("Maximum frame size: {} bytes", info.max_frame_size);
  }

  if no_flags || args.flag_sample_rate {
    format_print!("{}{} Hz", "Sample rate: ", info.sample_rate, no_flags);
  }

  if no_flags || args.flag_channels {
    format_print!("{}{}", "Number of channels: ", info.channels, no_flags);
  }

  if no_flags || args.flag_bits_per_sample {
    format_print!("{}{}", "Bits per samples: ", info.bits_per_sample,
                                                no_flags);
  }

  if no_flags || args.flag_total_samples {
    format_print!("{}{}", "Total samples: ", info.total_samples, no_flags);
  }

  if no_flags || args.flag_md5 {
    let mut md5  = String::with_capacity(32);

    for byte in &info.md5_sum {
      let hex = format!("{:02x}", byte);

      md5.push_str(&hex);
    }

    format_print!("{}{}", "MD5 sum: ", md5, no_flags);
  }
}

fn print_vorbis_comments(vorbis_comment: &VorbisComment, args: &Arguments) {
  let no_flags  = (args.flag_vendor || args.flag_name.is_some()) == false;

  if no_flags || args.flag_vendor {
    format_print!("{}{}", "Vendor string: ", vorbis_comment.vendor_string,
                                             no_flags);
  }

  if no_flags {
    let mut index = 1;

    println!("Number of Comments: {}", vorbis_comment.comments.len());

    for (name, value) in &vorbis_comment.comments {
      println!("  {}: \"{}\" = {}", index, name, value);

      index += 1;
    }
  } else {
    if let Some(ref name) = args.flag_name {
      vorbis_comment.comments.get(name)
                             .map(|value| println!("{}", value));
    }
  }
}

fn export_vorbis_comments(vorbis_comment: &VorbisComment, filename: &str)
                          -> io::Result<()> {
  let mut file  = try!(File::create(filename));

  for (name, value) in &vorbis_comment.comments {
    try!(write!(file, "{}={}\n", name, value));
  }

  Ok(())
}

fn print_seek_table(seek_points: &[SeekPoint]) {
  let mut count = 0;

  println!("Number of Seek Points: {}", seek_points.len());

  for seek_point in seek_points {
    println!("Seek Point #{}", count);
    println!("  Sample number: {}", seek_point.sample_number);
    println!("  Stream offset: {}", seek_point.stream_offset);
    println!("  Frame samples: {}", seek_point.frame_samples);
    count += 1;
  }
}

fn main() {
  let args: Arguments = Docopt::new(USAGE)
    .and_then(|d| d.argv(env::args()).decode())
    .unwrap_or_else(|e| e.exit());

  let stream = Stream::<ReadStream<File>>::from_file(&args.arg_filename)
                 .expect("Couldn't parse file");

  if args.cmd_streaminfo {
    print_stream_info(&stream, &args);
  }

  for meta in stream.metadata() {
    match meta.data {
      metadata::Data::VorbisComment(ref v) => {
        if args.cmd_comments {
          if let Some(ref filename) = args.flag_export {
            export_vorbis_comments(v, filename)
              .expect("couldn't write to file")
          } else {
            print_vorbis_comments(v, &args)
          }
        }
      }
      metadata::Data::SeekTable(ref s)     => {
        if args.cmd_seektable {
          print_seek_table(s);
        }
      }
      _                                    => continue,
    }
  }
}
<commit_msg>Fix indention for variable assignment<commit_after>extern crate docopt;
extern crate flac;
extern crate rustc_serialize;

use docopt::Docopt;
use flac::{ReadStream, Stream, StreamProducer};
use flac::metadata;
use flac::metadata::{SeekPoint, VorbisComment};

use std::env;
use std::io;
use std::io::Write;
use std::fs::File;

const USAGE: &'static str = "
Usage: metadata streaminfo [options] <filename>
       metadata comments [options] <filename>
       metadata seektable <filename>
       metadata picture [options] <filename>
       metadata --help

Options:
  --block-size       Show both the max and min block size from StreamInfo.
  --frame-size       Show both the max and min frame size from StreamInfo.
  --sample-rate      Show the sample rate from StreamInfo.
  --channels         Show the number of channels from StreamInfo.
  --bits-per-sample  Show the size in bits for each sample from StreamInfo.
  --total-samples    Show total number of samples from StreamInfo.
  --md5              Show the MD5 signature from StreamInfo.
  --vendor           Show the vendor string from VorbisComment.
  --name=NAME        Show the comments matching the `NAME` from VorbisComment.
  --export=FILE      Export VorbisComment or Picture to file.
  -h, --help         Show this message.
";

#[derive(Debug, RustcDecodable)]
struct Arguments {
  arg_filename: String,
  cmd_streaminfo: bool,
  cmd_comments: bool,
  cmd_seektable: bool,
  cmd_picture: bool,
  flag_block_size: bool,
  flag_frame_size: bool,
  flag_sample_rate: bool,
  flag_channels: bool,
  flag_bits_per_sample: bool,
  flag_total_samples: bool,
  flag_md5: bool,
  flag_vendor: bool,
  flag_name: Option<String>,
  flag_export: Option<String>,
}

macro_rules! format_print (
  ($format_str: expr, $opt_str: expr, $data: expr, $no_flag: expr) => (
    {
      println!($format_str, if $no_flag {
        $opt_str
      } else {
        ""
      }, $data);
    }
  );
);

fn print_stream_info<P>(stream: &Stream<P>, args: &Arguments)
 where P: StreamProducer {
  let info     = stream.info();
  let no_flags = (args.flag_block_size      || args.flag_frame_size    ||
                  args.flag_sample_rate     || args.flag_channels      ||
                  args.flag_bits_per_sample || args.flag_total_samples ||
                  args.flag_md5) == false;

  if no_flags || args.flag_block_size {
    println!("Minimum block size: {} samples", info.min_block_size);
    println!("Maximum block size: {} samples", info.max_block_size);
  }

  if no_flags || args.flag_frame_size {
    println!("Minimum frame size: {} bytes", info.min_frame_size);
    println!("Maximum frame size: {} bytes", info.max_frame_size);
  }

  if no_flags || args.flag_sample_rate {
    format_print!("{}{} Hz", "Sample rate: ", info.sample_rate, no_flags);
  }

  if no_flags || args.flag_channels {
    format_print!("{}{}", "Number of channels: ", info.channels, no_flags);
  }

  if no_flags || args.flag_bits_per_sample {
    format_print!("{}{}", "Bits per samples: ", info.bits_per_sample,
                                                no_flags);
  }

  if no_flags || args.flag_total_samples {
    format_print!("{}{}", "Total samples: ", info.total_samples, no_flags);
  }

  if no_flags || args.flag_md5 {
    let mut md5  = String::with_capacity(32);

    for byte in &info.md5_sum {
      let hex = format!("{:02x}", byte);

      md5.push_str(&hex);
    }

    format_print!("{}{}", "MD5 sum: ", md5, no_flags);
  }
}

fn print_vorbis_comments(vorbis_comment: &VorbisComment, args: &Arguments) {
  let no_flags  = (args.flag_vendor || args.flag_name.is_some()) == false;

  if no_flags || args.flag_vendor {
    format_print!("{}{}", "Vendor string: ", vorbis_comment.vendor_string,
                                             no_flags);
  }

  if no_flags {
    let mut index = 1;

    println!("Number of Comments: {}", vorbis_comment.comments.len());

    for (name, value) in &vorbis_comment.comments {
      println!("  {}: \"{}\" = {}", index, name, value);

      index += 1;
    }
  } else {
    if let Some(ref name) = args.flag_name {
      vorbis_comment.comments.get(name)
                             .map(|value| println!("{}", value));
    }
  }
}

fn export_vorbis_comments(vorbis_comment: &VorbisComment, filename: &str)
                          -> io::Result<()> {
  let mut file = try!(File::create(filename));

  for (name, value) in &vorbis_comment.comments {
    try!(write!(file, "{}={}\n", name, value));
  }

  Ok(())
}

fn print_seek_table(seek_points: &[SeekPoint]) {
  let mut count = 0;

  println!("Number of Seek Points: {}", seek_points.len());

  for seek_point in seek_points {
    println!("Seek Point #{}", count);
    println!("  Sample number: {}", seek_point.sample_number);
    println!("  Stream offset: {}", seek_point.stream_offset);
    println!("  Frame samples: {}", seek_point.frame_samples);
    count += 1;
  }
}

fn main() {
  let args: Arguments = Docopt::new(USAGE)
    .and_then(|d| d.argv(env::args()).decode())
    .unwrap_or_else(|e| e.exit());

  let stream = Stream::<ReadStream<File>>::from_file(&args.arg_filename)
                 .expect("Couldn't parse file");

  if args.cmd_streaminfo {
    print_stream_info(&stream, &args);
  }

  for meta in stream.metadata() {
    match meta.data {
      metadata::Data::VorbisComment(ref v) => {
        if args.cmd_comments {
          if let Some(ref filename) = args.flag_export {
            export_vorbis_comments(v, filename)
              .expect("couldn't write to file")
          } else {
            print_vorbis_comments(v, &args)
          }
        }
      }
      metadata::Data::SeekTable(ref s)     => {
        if args.cmd_seektable {
          print_seek_table(s);
        }
      }
      _                                    => continue,
    }
  }
}
<|endoftext|>


<commit_before>extern crate docopt;
extern crate flac;
extern crate rustc_serialize;

#[macro_use]
mod commands;

use std::env;

use commands::{streaminfo, comments, seektable, picture};
use docopt::Docopt;

const USAGE: &'static str = "
Usage: metadata <command> [<args>...]
       metadata [options]

Options:
  -h, --help  Show this message.

Commands:
  streaminfo  Display stream information.
  comments    Display or export comment tags.
  seektable   Display seek table.
  picture     Export picutes.
";

#[derive(Debug, RustcDecodable)]
struct Arguments {
  arg_command: Option<Command>,
  arg_args: Vec<String>,
}

#[derive(Debug, RustcDecodable)]
enum Command {
  StreamInfo,
  Comments,
  SeekTable,
  Picture,
}

fn main() {
  let args: Arguments = Docopt::new(USAGE)
    .and_then(|d| d.options_first(true).decode())
    .unwrap_or_else(|e| e.exit());

  match args.arg_command.unwrap() {
    Command::StreamInfo => {
      let sub_args: streaminfo::Arguments = Docopt::new(streaminfo::USAGE)
        .and_then(|d| d.argv(env::args()).decode())
        .unwrap_or_else(|e| e.exit());

      streaminfo::run(&sub_args)
    }
    Command::Comments   => {
      let sub_args: comments::Arguments = Docopt::new(comments::USAGE)
        .and_then(|d| d.argv(env::args()).decode())
        .unwrap_or_else(|e| e.exit());

      comments::run(&sub_args)
    }
    Command::SeekTable  => {
      let sub_args: seektable::Arguments = Docopt::new(seektable::USAGE)
        .and_then(|d| d.argv(env::args()).decode())
        .unwrap_or_else(|e| e.exit());

      seektable::run(&sub_args)
    }
    Command::Picture    => {
      let sub_args: picture::Arguments = Docopt::new(picture::USAGE)
        .and_then(|d| d.argv(env::args()).decode())
        .unwrap_or_else(|e| e.exit());

      picture::run(&sub_args)
    }
  }
}
<commit_msg>Allow `Command` to be copied<commit_after>extern crate docopt;
extern crate flac;
extern crate rustc_serialize;

#[macro_use]
mod commands;

use std::env;

use commands::{streaminfo, comments, seektable, picture};
use docopt::Docopt;

const USAGE: &'static str = "
Usage: metadata <command> [<args>...]
       metadata [options]

Options:
  -h, --help  Show this message.

Commands:
  streaminfo  Display stream information.
  comments    Display or export comment tags.
  seektable   Display seek table.
  picture     Export picutes.
";

#[derive(Debug, RustcDecodable)]
struct Arguments {
  arg_command: Option<Command>,
  arg_args: Vec<String>,
}

#[derive(Clone, Copy, Debug, RustcDecodable)]
enum Command {
  StreamInfo,
  Comments,
  SeekTable,
  Picture,
}

fn main() {
  let args: Arguments = Docopt::new(USAGE)
    .and_then(|d| d.options_first(true).decode())
    .unwrap_or_else(|e| e.exit());

  match args.arg_command.unwrap() {
    Command::StreamInfo => {
      let sub_args: streaminfo::Arguments = Docopt::new(streaminfo::USAGE)
        .and_then(|d| d.argv(env::args()).decode())
        .unwrap_or_else(|e| e.exit());

      streaminfo::run(&sub_args)
    }
    Command::Comments   => {
      let sub_args: comments::Arguments = Docopt::new(comments::USAGE)
        .and_then(|d| d.argv(env::args()).decode())
        .unwrap_or_else(|e| e.exit());

      comments::run(&sub_args)
    }
    Command::SeekTable  => {
      let sub_args: seektable::Arguments = Docopt::new(seektable::USAGE)
        .and_then(|d| d.argv(env::args()).decode())
        .unwrap_or_else(|e| e.exit());

      seektable::run(&sub_args)
    }
    Command::Picture    => {
      let sub_args: picture::Arguments = Docopt::new(picture::USAGE)
        .and_then(|d| d.argv(env::args()).decode())
        .unwrap_or_else(|e| e.exit());

      picture::run(&sub_args)
    }
  }
}
<|endoftext|>


<commit_before>use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};

use common::mutex::Mutex;

use scheduler;
use scheduler::context::{context_switch, Context};

struct RecursiveMutexInner {
    owner: usize,
    count: usize
}

pub struct RecursiveMutex<T> {
    inner: Mutex<RecursiveMutexInner>,
    value: UnsafeCell<T>
}

impl<T> RecursiveMutex<T> {
    /// Create a new mutex with value `value`.
    pub fn new(value: T) -> Self {
        RecursiveMutex {
            inner: Mutex::new(RecursiveMutexInner {
                owner: 0,
                count: 0
            }),
            value: UnsafeCell::new(value),
        }
    }
}

impl<T: ?Sized> RecursiveMutex<T> {
    /// Lock mutex
    pub fn lock(&self) -> RecursiveMutexGuard<T> {
        let pid;
        unsafe {
            let reenable = scheduler::start_no_ints();
            if let Some(current) = Context::current() {
                pid = current.pid;
            }else{
                pid = 0;
            }
            scheduler::end_no_ints(reenable);
        }

        loop {
            {
                let mut inner = self.inner.lock();
                if inner.owner == pid || inner.count == 0 {
                    inner.owner = pid;
                    inner.count += 1;
                    break;
                }
            }
            unsafe { context_switch(false) };
        }

        RecursiveMutexGuard::new(&self.inner, &self.value)
    }
}

unsafe impl<T: ?Sized + Send> Send for RecursiveMutex<T> { }

unsafe impl<T: ?Sized + Send> Sync for RecursiveMutex<T> { }

/// A recursive mutex guard (returned by .lock())
pub struct RecursiveMutexGuard<'a, T: ?Sized + 'a> {
    inner: &'a Mutex<RecursiveMutexInner>,
    data: &'a UnsafeCell<T>,
}

impl<'rmutex, T: ?Sized> RecursiveMutexGuard<'rmutex, T> {
    fn new(inner: &'rmutex Mutex<RecursiveMutexInner>, data: &'rmutex UnsafeCell<T>) -> Self {
        RecursiveMutexGuard {
            inner: inner,
            data: data,
        }
    }
}

impl<'rmutex, T: ?Sized> Deref for RecursiveMutexGuard<'rmutex, T> {
    type Target = T;

    fn deref<'a>(&'a self) -> &'a T {
        unsafe { &*self.data.get() }
    }
}

impl<'rmutex, T: ?Sized> DerefMut for RecursiveMutexGuard<'rmutex, T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe { &mut *self.data.get() }
    }
}

impl<'a, T: ?Sized> Drop for RecursiveMutexGuard<'a, T> {
    fn drop(&mut self) {
        let mut inner = self.inner.lock();
        inner.count -= 1;
    }
}
<commit_msg>Fixes for recursive mutex<commit_after>use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};
use core::usize;

use common::mutex::Mutex;

use scheduler;
use scheduler::context::{context_switch, Context};

struct RecursiveMutexInner {
    owner: usize,
    count: usize
}

pub struct RecursiveMutex<T> {
    inner: Mutex<RecursiveMutexInner>,
    value: UnsafeCell<T>
}

impl<T> RecursiveMutex<T> {
    /// Create a new mutex with value `value`.
    pub fn new(value: T) -> Self {
        RecursiveMutex {
            inner: Mutex::new(RecursiveMutexInner {
                owner: 0,
                count: 0
            }),
            value: UnsafeCell::new(value),
        }
    }
}

impl<T: ?Sized> RecursiveMutex<T> {
    /// Lock mutex
    pub fn lock(&self) -> RecursiveMutexGuard<T> {
        let pid;
        unsafe {
            let reenable = scheduler::start_no_ints();
            if let Some(current) = Context::current() {
                pid = current.pid;
            }else{
                pid = usize::MAX;
            }
            scheduler::end_no_ints(reenable);
        }

        loop {
            {
                let mut inner = self.inner.lock();
                if inner.count == 0 || inner.owner == pid  {
                    inner.owner = pid;
                    inner.count += 1;
                    break;
                }
            }
            unsafe { context_switch(false) };
        }

        RecursiveMutexGuard::new(&self.inner, &self.value)
    }
}

unsafe impl<T: ?Sized + Send> Send for RecursiveMutex<T> { }

unsafe impl<T: ?Sized + Send> Sync for RecursiveMutex<T> { }

/// A recursive mutex guard (returned by .lock())
pub struct RecursiveMutexGuard<'a, T: ?Sized + 'a> {
    inner: &'a Mutex<RecursiveMutexInner>,
    data: &'a UnsafeCell<T>,
}

impl<'rmutex, T: ?Sized> RecursiveMutexGuard<'rmutex, T> {
    fn new(inner: &'rmutex Mutex<RecursiveMutexInner>, data: &'rmutex UnsafeCell<T>) -> Self {
        RecursiveMutexGuard {
            inner: inner,
            data: data,
        }
    }
}

impl<'rmutex, T: ?Sized> Deref for RecursiveMutexGuard<'rmutex, T> {
    type Target = T;

    fn deref<'a>(&'a self) -> &'a T {
        unsafe { &*self.data.get() }
    }
}

impl<'rmutex, T: ?Sized> DerefMut for RecursiveMutexGuard<'rmutex, T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe { &mut *self.data.get() }
    }
}

impl<'a, T: ?Sized> Drop for RecursiveMutexGuard<'a, T> {
    fn drop(&mut self) {
        let mut inner = self.inner.lock();
        inner.count -= 1;
        if inner.count == 0 {
            inner.owner = 0;
        }
    }
}
<|endoftext|>