<commit_before>/*!

The afsort crate implements a sorting algorithm based on
[American Flag sort](https://en.wikipedia.org/wiki/American_flag_sort). The implementation is
currently limited to sort byte slices, e.g. Strings. The main motivation is to sort strings of
text, so most of the benchmarks are based on English text strings. When sorting English words,
this implementation seems to be about 40% faster than `sort_unstable` from the Rust standard
library.

For small input, this method falls back to the standard library.

# Installation

Add the depndency to your `Cargo.toml`:

```ignore
[dependencies]
afsort = "0.1"
```
In your crate root:
```ignore
extern crate afsort;
```

# Usage

You can now use afsort to e.g. sort arrays of strings or string slices.

```rust
use afsort;
let mut strings = vec!("red", "green", "blue");
afsort::sort_unstable(&mut strings);
assert_eq!(strings, vec!["blue", "green", "red"]);
```

You can also sort by an extractor function, e.g.:

```rust
use afsort;
let mut tuples = vec![("b", 2), ("a", 1)];
afsort::sort_unstable_by(&mut tuples, |t: &(&str, _) | t.0.as_bytes());
assert_eq!(tuples, vec![("a", 1), ("b", 2)]);
```

# Motivation

Essentially, I noticed that sorting of strings took a long time when using the
[fst](https://github.com/BurntSushi/fst) crate, since it requires the input to be ordered.
Since sorting strings is a general problem, this is now a crate.

# Performance

As mentioned, this implementation seems to be about 40% faster than the sort in the standard
library, when sorting strings of random English words.  The implementation is fairly naive,
so I would not be surprised if it could be improved further.

You can run the benchmark tests using `cargo bench` (currently requires nightly rust), like this:

```ignore
% cargo bench
   Compiling afsort v0.1.0 (file:///home/anton/dev/off/afsort)
    Finished release [optimized] target(s) in 5.66 secs
     Running target/release/deps/afsort-ca28db3ba0643253

running 12 tests
test tests::sorts_strings_same_as_unstable ... ignored
test tests::sorts_tuples_same_as_unstable ... ignored
test tests::sort_100000_en_af        ... bench:  20,402,968 ns/iter (+/- 1,512,907)
test tests::sort_100000_en_std       ... bench:  30,132,067 ns/iter (+/- 1,698,223)
test tests::sort_10000_en_af         ... bench:   1,377,303 ns/iter (+/- 114,481)
test tests::sort_10000_en_lower_af   ... bench:   1,371,022 ns/iter (+/- 95,391)
test tests::sort_10000_en_lower_std  ... bench:   2,227,486 ns/iter (+/- 127,281)
test tests::sort_10000_en_sorted_af  ... bench:     878,665 ns/iter (+/- 545,256)
test tests::sort_10000_en_sorted_std ... bench:     618,329 ns/iter (+/- 536,338)
test tests::sort_10000_en_std        ... bench:   2,221,089 ns/iter (+/- 157,461)
test tests::sort_1000_en_af          ... bench:     101,625 ns/iter (+/- 6,946)
test tests::sort_1000_en_std         ... bench:     171,655 ns/iter (+/- 9,844)

test result: ok. 0 passed; 0 failed; 2 ignored; 10 measured; 0 filtered out

```
# Limitations

Currently, this crate only supports sorting elements of `AsRef<[u8]>`. I think that this is a
good first step, since it supports sorting of Strings. There is however no reason why American
Flag sorting should be limited to this data type. Any kind of element that can deliver a radix
to a certain digit/depth can be sorted using this technique.

The American Flag algorithm is unstable, in the same way that sort_unstable in the standard
library. That is, equal elements might be re-ordered.

This crate can _only_ sort strings based on their `utf-8` byte values. For many problems, this
is fine. However, if you want to sort strings for display to a user, Locale might matter. This
crate does not try to address this issue.

# Testing

Testing is done using the [quickcheck](https://github.com/BurntSushi/quickcheck) crate. We run
about 50k different variations of input strings. We treat the standard library's sort_unstable
as the gold standard.

*/

#[cfg(test)]
extern crate quickcheck;

/// Enhances slices of e.g. Strings to have a `af_sort_unstable` method, as a more idiomatic
/// way to call sort.
///
/// #Example
///
/// ```rust
/// use afsort::AFSortable;
///
/// let mut strings = vec!["c", "a", "b"];
/// strings.af_sort_unstable();
/// assert_eq!(strings, vec!["a", "b", "c"]);
/// ```

pub trait AFSortable {
    #[inline]
    fn af_sort_unstable(&mut self);
}

impl<T> AFSortable for [T]
where
    T: AsRef<[u8]>,
{
    #[inline]
    fn af_sort_unstable(&mut self) {
        sort_unstable(self);
    }
}

/// Main sort method.
///
/// #Example
///
/// ```rust
/// let mut strings = vec!["c", "a", "b"];
/// afsort::sort_unstable(&mut strings);
/// assert_eq!(strings, vec!["a", "b", "c"]);
/// ```
#[inline]
pub fn sort_unstable<'a, T>(vec: &'a mut [T])
where
    T: AsRef<[u8]>,
{
    sort_unstable_by(vec, (|s| s.as_ref()));
}

/// Sort method which accepts function to convert elements to &[u8].
///
/// #Example
///
/// ```rust
/// let mut tuples = vec![("b", 2), ("a", 1)];
///afsort::sort_unstable_by(&mut tuples, |t: &(&str, _) | t.0.as_bytes());
///assert_eq!(tuples, vec![("a", 1), ("b", 2)]);
/// ```
///
/// Footnote: The explicit type annotacion in the closure seems to be needed (even though it should
/// not). See
/// [this discussion](https://users.rust-lang.org/t/lifetime-issue-with-str-in-closure/13137).
#[inline]
pub fn sort_unstable_by< T, F>(vec: & mut [T], to_slice: F)
where
    F: Fn(& T) -> & [u8],
{
    sort_req(vec, &to_slice, 0);
}

fn sort_req< T, F>(vec: & mut [T], to_slice: &F, depth: usize)
where
    F: Fn(&T) -> &[u8],
{
    if vec.len() <= 1 {
        //vec.sort_unstable_by(|e1, e2| to_slice(e1).cmp(to_slice(e2)));
        return;
    }
    let mut min = u16::max_value();
    let mut max = 0u16;
    {
        //Find min/max to be able to allocate less memory
        for elem in vec.iter() {
            let val = to_slice(elem);
            if val.len() > depth {
                let radix_val = val[depth] as u16;
                if radix_val < min {
                    min = radix_val;
                }
                if radix_val > max {
                    max = radix_val;
                }
            }
        }
    }
    //No item had a value for this depth
    if min == u16::max_value() {
        return;
    }

    // +2 instead of +1 for special 0 bucket
    let num_items = (max - min + 2) as usize;
    let mut counts: Vec<usize> = vec![0usize; num_items as usize];
    {
        //Count occurences per value. Elements without a value gets
        //the special value 0, while others get the u8 value +1.
        for elem in vec.iter() {
            let radix_val = radix_for_str(to_slice(elem), depth, min);
            counts[radix_val as usize] += 1;
        }
    }

    let mut offsets: Vec<usize> = vec![0usize; num_items as usize];
    {
        //Sets the offsets for each count
        let mut sum = 0usize;
        for i in 0..counts.len() {
            offsets[i as usize] = sum;
            sum += counts[i as usize];
        }
    }

    {
        //Swap objects into the correct bucket, based on the offsets
        let mut next_free = offsets.clone();
        let mut block = 0usize;
        let mut i = 0usize;
        while block < counts.len() - 1 {
            if i >= offsets[block as usize + 1] as usize {
                block += 1;
            } else {
                let radix_val = radix_for_str(to_slice(&vec[i]), depth, min);
                if radix_val == block as u16 {
                    i += 1;
                } else {
                    vec.swap(i as usize, next_free[radix_val as usize] as usize);
                    next_free[radix_val as usize] += 1;
                }
            }
        }
    }
    {
        //Within each bucket, sort recursively
        for i in 0..offsets.len() - 1 {
            sort_req(
                &mut vec[offsets[i as usize] as usize..offsets[i as usize + 1] as usize],
                to_slice,
                depth + 1,
            );
        }
        sort_req(&mut vec[offsets[offsets.len() - 1]..], to_slice, depth + 1);
    }
}

fn radix_for_str(s: &[u8], d: usize, base: u16) -> u16 {
    if s.len() > d {
        s[d] as u16 + 1 - base
    } else {
        0
    }
}

#[cfg(test)]
mod tests {
    use super::AFSortable;
    use quickcheck::QuickCheck;

    #[test]
    fn sorts_strings_same_as_unstable() {
        fn compare_sort(mut strings: Vec<String>) -> bool {
            let mut copy = strings.clone();
            copy.sort_unstable();
            strings.af_sort_unstable();
            strings == copy
        }
        QuickCheck::new().tests(50000).quickcheck(
            compare_sort as
                fn(Vec<String>) -> bool,
        );
    }

    #[test]
    fn sorts_tuples_same_as_unstable() {
        fn compare_sort(mut tuples: Vec<(String, u8)>) -> bool {
            let mut copy = tuples.clone();
            copy.sort_unstable_by(|t1, t2| t1.0.cmp(&t2.0));
            super::sort_unstable_by(&mut tuples, |t| t.0.as_bytes());
            tuples.into_iter().map(|t| t.0).collect::<Vec<String>>() ==
                copy.into_iter().map(|t| t.0).collect::<Vec<String>>()
        }
        QuickCheck::new().tests(50000).quickcheck(
            compare_sort as
                fn(Vec<(String, u8)>)
                   -> bool,
        );
    }
}
<commit_msg>Fixes bug where we would not fall back to std sort.<commit_after>/*!

The afsort crate implements a sorting algorithm based on
[American Flag sort](https://en.wikipedia.org/wiki/American_flag_sort). The implementation is
currently limited to sort byte slices, e.g. Strings. The main motivation is to sort strings of
text, so most of the benchmarks are based on English text strings. When sorting English words,
this implementation seems to be about 40% faster than `sort_unstable` from the Rust standard
library.

For small input, this method falls back to the standard library.

# Installation

Add the depndency to your `Cargo.toml`:

```ignore
[dependencies]
afsort = "0.1"
```
In your crate root:
```ignore
extern crate afsort;
```

# Usage

You can now use afsort to e.g. sort arrays of strings or string slices.

```rust
use afsort;
let mut strings = vec!("red", "green", "blue");
afsort::sort_unstable(&mut strings);
assert_eq!(strings, vec!["blue", "green", "red"]);
```

You can also sort by an extractor function, e.g.:

```rust
use afsort;
let mut tuples = vec![("b", 2), ("a", 1)];
afsort::sort_unstable_by(&mut tuples, |t: &(&str, _) | t.0.as_bytes());
assert_eq!(tuples, vec![("a", 1), ("b", 2)]);
```

# Motivation

Essentially, I noticed that sorting of strings took a long time when using the
[fst](https://github.com/BurntSushi/fst) crate, since it requires the input to be ordered.
Since sorting strings is a general problem, this is now a crate.

# Performance

As mentioned, this implementation seems to be about 40% faster than the sort in the standard
library, when sorting strings of random English words.  The implementation is fairly naive,
so I would not be surprised if it could be improved further.

You can run the benchmark tests using `cargo bench` (currently requires nightly rust), like this:

```ignore
% cargo bench
   Compiling afsort v0.1.0 (file:///home/anton/dev/off/afsort)
    Finished release [optimized] target(s) in 5.66 secs
     Running target/release/deps/afsort-ca28db3ba0643253

running 12 tests
test tests::sorts_strings_same_as_unstable ... ignored
test tests::sorts_tuples_same_as_unstable ... ignored
test tests::sort_100000_en_af        ... bench:  20,402,968 ns/iter (+/- 1,512,907)
test tests::sort_100000_en_std       ... bench:  30,132,067 ns/iter (+/- 1,698,223)
test tests::sort_10000_en_af         ... bench:   1,377,303 ns/iter (+/- 114,481)
test tests::sort_10000_en_lower_af   ... bench:   1,371,022 ns/iter (+/- 95,391)
test tests::sort_10000_en_lower_std  ... bench:   2,227,486 ns/iter (+/- 127,281)
test tests::sort_10000_en_sorted_af  ... bench:     878,665 ns/iter (+/- 545,256)
test tests::sort_10000_en_sorted_std ... bench:     618,329 ns/iter (+/- 536,338)
test tests::sort_10000_en_std        ... bench:   2,221,089 ns/iter (+/- 157,461)
test tests::sort_1000_en_af          ... bench:     101,625 ns/iter (+/- 6,946)
test tests::sort_1000_en_std         ... bench:     171,655 ns/iter (+/- 9,844)

test result: ok. 0 passed; 0 failed; 2 ignored; 10 measured; 0 filtered out

```
# Limitations

Currently, this crate only supports sorting elements of `AsRef<[u8]>`. I think that this is a
good first step, since it supports sorting of Strings. There is however no reason why American
Flag sorting should be limited to this data type. Any kind of element that can deliver a radix
to a certain digit/depth can be sorted using this technique.

The American Flag algorithm is unstable, in the same way that sort_unstable in the standard
library. That is, equal elements might be re-ordered.

This crate can _only_ sort strings based on their `utf-8` byte values. For many problems, this
is fine. However, if you want to sort strings for display to a user, Locale might matter. This
crate does not try to address this issue.

# Testing

Testing is done using the [quickcheck](https://github.com/BurntSushi/quickcheck) crate. We run
about 50k different variations of input strings. We treat the standard library's sort_unstable
as the gold standard.

*/

#[cfg(test)]
extern crate quickcheck;

/// Enhances slices of e.g. Strings to have a `af_sort_unstable` method, as a more idiomatic
/// way to call sort.
///
/// #Example
///
/// ```rust
/// use afsort::AFSortable;
///
/// let mut strings = vec!["c", "a", "b"];
/// strings.af_sort_unstable();
/// assert_eq!(strings, vec!["a", "b", "c"]);
/// ```

pub trait AFSortable {
    #[inline]
    fn af_sort_unstable(&mut self);
}

impl<T> AFSortable for [T]
where
    T: AsRef<[u8]>,
{
    #[inline]
    fn af_sort_unstable(&mut self) {
        sort_unstable(self);
    }
}

/// Main sort method.
///
/// #Example
///
/// ```rust
/// let mut strings = vec!["c", "a", "b"];
/// afsort::sort_unstable(&mut strings);
/// assert_eq!(strings, vec!["a", "b", "c"]);
/// ```
#[inline]
pub fn sort_unstable<'a, T>(vec: &'a mut [T])
where
    T: AsRef<[u8]>,
{
    sort_unstable_by(vec, (|s| s.as_ref()));
}

/// Sort method which accepts function to convert elements to &[u8].
///
/// #Example
///
/// ```rust
/// let mut tuples = vec![("b", 2), ("a", 1)];
///afsort::sort_unstable_by(&mut tuples, |t: &(&str, _) | t.0.as_bytes());
///assert_eq!(tuples, vec![("a", 1), ("b", 2)]);
/// ```
///
/// Footnote: The explicit type annotacion in the closure seems to be needed (even though it should
/// not). See
/// [this discussion](https://users.rust-lang.org/t/lifetime-issue-with-str-in-closure/13137).
#[inline]
pub fn sort_unstable_by< T, F>(vec: & mut [T], to_slice: F)
where
    F: Fn(& T) -> & [u8],
{
    sort_req(vec, &to_slice, 0);
}

fn sort_req< T, F>(vec: & mut [T], to_slice: &F, depth: usize)
where
    F: Fn(&T) -> &[u8],
{
    if vec.len() <= 32 {
        vec.sort_unstable_by(|e1, e2| to_slice(e1).cmp(to_slice(e2)));
        return;
    }
    let mut min = u16::max_value();
    let mut max = 0u16;
    {
        //Find min/max to be able to allocate less memory
        for elem in vec.iter() {
            let val = to_slice(elem);
            if val.len() > depth {
                let radix_val = val[depth] as u16;
                if radix_val < min {
                    min = radix_val;
                }
                if radix_val > max {
                    max = radix_val;
                }
            }
        }
    }
    //No item had a value for this depth
    if min == u16::max_value() {
        return;
    }

    // +2 instead of +1 for special 0 bucket
    let num_items = (max - min + 2) as usize;
    let mut counts: Vec<usize> = vec![0usize; num_items as usize];
    {
        //Count occurences per value. Elements without a value gets
        //the special value 0, while others get the u8 value +1.
        for elem in vec.iter() {
            let radix_val = radix_for_str(to_slice(elem), depth, min);
            counts[radix_val as usize] += 1;
        }
    }

    let mut offsets: Vec<usize> = vec![0usize; num_items as usize];
    {
        //Sets the offsets for each count
        let mut sum = 0usize;
        for i in 0..counts.len() {
            offsets[i as usize] = sum;
            sum += counts[i as usize];
        }
    }

    {
        //Swap objects into the correct bucket, based on the offsets
        let mut next_free = offsets.clone();
        let mut block = 0usize;
        let mut i = 0usize;
        while block < counts.len() - 1 {
            if i >= offsets[block as usize + 1] as usize {
                block += 1;
            } else {
                let radix_val = radix_for_str(to_slice(&vec[i]), depth, min);
                if radix_val == block as u16 {
                    i += 1;
                } else {
                    vec.swap(i as usize, next_free[radix_val as usize] as usize);
                    next_free[radix_val as usize] += 1;
                }
            }
        }
    }
    {
        //Within each bucket, sort recursively
        for i in 0..offsets.len() - 1 {
            sort_req(
                &mut vec[offsets[i as usize] as usize..offsets[i as usize + 1] as usize],
                to_slice,
                depth + 1,
            );
        }
        sort_req(&mut vec[offsets[offsets.len() - 1]..], to_slice, depth + 1);
    }
}

fn radix_for_str(s: &[u8], d: usize, base: u16) -> u16 {
    if s.len() > d {
        s[d] as u16 + 1 - base
    } else {
        0
    }
}

#[cfg(test)]
mod tests {
    use super::AFSortable;
    use quickcheck::QuickCheck;

    #[test]
    fn sorts_strings_same_as_unstable() {
        fn compare_sort(mut strings: Vec<String>) -> bool {
            let mut copy = strings.clone();
            copy.sort_unstable();
            strings.af_sort_unstable();
            strings == copy
        }
        QuickCheck::new().tests(50000).quickcheck(
            compare_sort as
                fn(Vec<String>) -> bool,
        );
    }

    #[test]
    fn sorts_tuples_same_as_unstable() {
        fn compare_sort(mut tuples: Vec<(String, u8)>) -> bool {
            let mut copy = tuples.clone();
            copy.sort_unstable_by(|t1, t2| t1.0.cmp(&t2.0));
            super::sort_unstable_by(&mut tuples, |t| t.0.as_bytes());
            tuples.into_iter().map(|t| t.0).collect::<Vec<String>>() ==
                copy.into_iter().map(|t| t.0).collect::<Vec<String>>()
        }
        QuickCheck::new().tests(50000).quickcheck(
            compare_sort as
                fn(Vec<(String, u8)>)
                   -> bool,
        );
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::cell::RefCell;
use std::rc::Rc;
use ast::*;
use test::Bencher;

#[derive(Clone, PartialEq)]
pub struct Env {
    pub table: HashMap<String, Expr>,
    pub parent: Option<Rc<RefCell<Env>>>
}

#[allow(unreachable_code)]
#[allow(dead_code)]
impl Env {
    pub fn new() -> Env {
        let mut res = Env {
            table: HashMap::new(),
            parent: None
        };
        res.setup();
        res
    }

    pub fn def_var(&mut self, var: String, val: Expr) {
        self.add_binding(var, val);
    }

    pub fn str_def(&mut self, var: &str, val: Expr) {
        self.add_binding(var.to_string(), val);
    }

    pub fn add_binding(&mut self, var: String, val: Expr) {
        self.table.insert(var, val);
    }

    pub fn lookup(&self, var: String) -> Option<Expr> {
        match self.table.get(&var) {
            Some(val) => return Some(val.clone()),
            _ => {}
        }
        match self.parent.clone() {
            Some(p) =>
                return p.borrow().lookup(var),
            _ => {
                return None;
            }
        };
    }

    pub fn str_lookup(&self, var: &str) -> Option<Expr> {
        self.lookup(var.to_string())
    }

    pub fn parent(&self) ->  Option<Rc<RefCell<Env>>> {
        match self.parent.clone() {
            Some(p) => return Some(p.clone()),
            _ => { return None; }
        }
    }

    pub fn extend(&mut self, vars: Expr, vals: Expr) -> Rc<RefCell<Env>> {
        let mut _vars = vars;
        let mut _vals = vals;
        let mut res = Env {
            table: HashMap::new(),
            parent: Some(Rc::new(RefCell::new(self.clone())))
        };
        loop {
            if _vars.is_last() { break; }
            res.add_binding(_vars.car().as_str(), _vals.car());
            _vars = _vars.cdr();
            _vals = _vals.cdr();
        }
        res.add_binding(_vars.car().as_str(), _vals.car());
        return Rc::new(RefCell::new(res));
    }

    fn setup(&mut self) {
        macro_rules! def_proc {
            ($func_name:ident, $raw_func_name:ident) => (
                fn $func_name(args: Expr) -> Expr {
                    Expr::Bool(BoolNode::new(args.car().$raw_func_name()))
                }
                )
        }

        macro_rules! add_proc {
            ($type_str:expr, $func_name:ident) => (
                self.def_var($type_str.to_string(),
                             Expr::Proc(ProcNode::new($func_name)))
                    )
        }

        def_proc!(is_null, is_empty);
        def_proc!(is_boolean, is_bool);
        def_proc!(is_symbol, is_symbol);
        def_proc!(is_string, is_string);
        def_proc!(is_pair, is_pair);
        def_proc!(is_char, is_char);
        def_proc!(is_int, is_int);

        add_proc!("null?", is_null);
        add_proc!("boolean?", is_boolean);
        add_proc!("symbol?", is_symbol);
        add_proc!("string?", is_string);
        add_proc!("char?", is_char);
        add_proc!("integer?", is_int);
        add_proc!("+", add);
        add_proc!("-", sub);
        add_proc!("*", mul);
        add_proc!("/", div);
        add_proc!("eq?", eq);
        add_proc!("=", eq);
        add_proc!("<", less);
        add_proc!(">", large);
        add_proc!("pair?", is_pair);
        add_proc!("car", car);
        add_proc!("cdr", cdr);
        add_proc!("cons", cons);
    }
}

fn add(args: Expr) -> Expr {
    let mut res = 0is;
    let mut exps = args;
    loop {
        if exps.is_empty() { break; }
        res += exps.car().as_int();
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn sub(args: Expr) -> Expr {
    let mut res = args.car().as_int();
    let mut exps = args.cdr();
    loop {
        if exps.is_empty() { break; }
        res -= exps.car().as_int();
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn mul(args: Expr) -> Expr {
    let mut res = 1is;
    let mut exps = args;
    loop {
        if exps.is_empty() { break; }
        res *= exps.car().as_int();
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn div(args: Expr) -> Expr {
    let mut exps = args;
    let mut res = exps.car().as_int();
    exps = exps.cdr();
    loop {
        if exps.is_empty() { break; }
        let nxt = exps.car().as_int();
        if nxt == 0 {
            return Expr::Symbol(SymbolNode::new("Fail"));
        }
        res /= nxt;
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn cons(args: Expr) -> Expr {
    let obj1 = args.car();
    let obj2 = args.c("da");
    Expr::Pair(PairNode::new(obj1, Expr::Pair(PairNode::new(obj2, Expr::Nil))))
}

fn eq(args: Expr) -> Expr {
    let obj1 = args.car();
    let obj2 = args.c("da");
    Expr::Bool(BoolNode::new(obj1 == obj2))
}

fn less(args: Expr) -> Expr {
    let val = args.car().as_int();
    let mut exps = args.cdr();
    loop {
        if exps.is_empty() { break; }
        if val >= exps.car().as_int() {
            return Expr::Bool(BoolNode::new(false));
        }
        exps = exps.cdr();
    }
    Expr::Bool(BoolNode::new(true))
}

fn car(args: Expr) -> Expr {
    assert!(args.car().is_pair());
    args.c("aa")
}

fn cdr(args: Expr) -> Expr {
    assert!(args.car().is_pair());
    args.c("ad")
}

fn large(args: Expr) -> Expr {
    let val = args.car().as_int();
    let mut exps = args.cdr();
    loop {
        if exps.is_empty() { break; }
        if val <= exps.car().as_int() {
            return Expr::Bool(BoolNode::new(false));
        }
        exps = exps.cdr();
    }
    Expr::Bool(BoolNode::new(true))
}

#[test]
fn test_env() {
    let mut env = Env::new();
    env.str_def("hello", Expr::Str(StrNode::new("world")));

    let val = env.str_lookup("hello");
    assert!(val.unwrap().as_str() == "world");

    env.str_def("1", Expr::Int(IntNode::new(1)));
    let val = env.str_lookup("1");
    assert!(val.unwrap().as_int() == 1);

    env.str_def("1", Expr::Int(IntNode::new(2)));
    let val = env.str_lookup("1");
    assert!(val.unwrap().as_int() == 2);

    env.str_def("sym", Expr::Int(IntNode::new(2)));
    let val = env.str_lookup("sym");
    assert!(val.unwrap().as_int() == 2);

    let val = env.str_lookup("null?");
    assert!(val.unwrap().is_proc());
    let val = env.str_lookup("char?");
    assert!(val.unwrap().is_proc());
    let val = env.str_lookup("integer?");
    assert!(val.unwrap().is_proc());

    let val = env.str_lookup(">");
    assert!(val.unwrap().is_proc());

    let val = env.str_lookup("<");
    assert!(val.unwrap().is_proc());

}

#[test]
fn test_env_extend() {
    let mut env = Env::new();
    env.str_def("hello", Expr::Str(StrNode::new("world")));

    let vars = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("var")), Expr::Nil));
    let vals = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("val")), Expr::Nil));

    let extend_env = env.extend(vars, vals);
    let val = extend_env.clone().borrow_mut().str_lookup("var");
    assert!(val.unwrap().as_str() == "val");

    let val = extend_env.clone().borrow_mut().str_lookup("hello");
    assert!(val.unwrap().as_str() == "world");

    let vars = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("var_x")), Expr::Nil));
    let vals = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("val_x")), Expr::Nil));

    let extend_env = extend_env.clone().borrow_mut().extend(vars, vals);
    let val = extend_env.clone().borrow_mut().str_lookup("var_x");
    assert!(val.unwrap().as_str() == "val_x");

    extend_env.clone().borrow_mut().str_def("1", Expr::Str(StrNode::new("1")));

    let val = extend_env.clone().borrow_mut().str_lookup("1");
    assert!(val.unwrap().as_str() == "1");
}

#[test]
fn test_env_parent() {
    let mut env = Env::new();
    env.str_def("hello", Expr::Str(StrNode::new("world")));

    let vars = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("var")), Expr::Nil));
    let vals = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("val")), Expr::Nil));

    let extend_env = env.extend(vars, vals);
    let parent = extend_env.clone().borrow_mut().parent().unwrap();
    let val = parent.clone().borrow_mut().str_lookup("hello");
    assert!(val.unwrap().as_str() == "world");
}

#[bench]
fn env_bench(b: &mut Bencher) {
    fn test_env() {
        let mut env = Env::new();
        for i in 1..1000 {
            let key = i.to_string();
            env.def_var(key.clone(), Expr::Str(StrNode::new("world")));
            let val = env.lookup(key);
            assert!(val.unwrap().as_str() == "world");
        }
    }

    b.iter(|| test_env());
}

#[bench]
fn env_bench_iter(b: &mut Bencher) {
    fn test_env() {
        let mut env = Env::new();
        for i in 1..1000 {
            env.str_def("hello", Expr::Str(StrNode::new("world")));
            let val = env.str_lookup("hello");
            assert!(val.unwrap().as_str() == "world");
        }
    }

    b.iter(|| test_env());
}
<commit_msg>tunning bench<commit_after>use std::collections::HashMap;
use std::cell::RefCell;
use std::rc::Rc;
use ast::*;
use test::Bencher;

#[derive(Clone, PartialEq)]
pub struct Env {
    pub table: HashMap<String, Expr>,
    pub parent: Option<Rc<RefCell<Env>>>
}

#[allow(unreachable_code)]
#[allow(dead_code)]
impl Env {
    pub fn new() -> Env {
        let mut res = Env {
            table: HashMap::new(),
            parent: None
        };
        res.setup();
        res
    }

    pub fn def_var(&mut self, var: String, val: Expr) {
        self.add_binding(var, val);
    }

    pub fn str_def(&mut self, var: &str, val: Expr) {
        self.add_binding(var.to_string(), val);
    }

    pub fn add_binding(&mut self, var: String, val: Expr) {
        self.table.insert(var, val);
    }

    pub fn lookup(&self, var: String) -> Option<Expr> {
        match self.table.get(&var) {
            Some(val) => return Some(val.clone()),
            _ => {}
        }
        match self.parent.clone() {
            Some(p) =>
                return p.borrow().lookup(var),
            _ => {
                return None;
            }
        };
    }

    pub fn str_lookup(&self, var: &str) -> Option<Expr> {
        self.lookup(var.to_string())
    }

    pub fn parent(&self) ->  Option<Rc<RefCell<Env>>> {
        match self.parent.clone() {
            Some(p) => return Some(p.clone()),
            _ => { return None; }
        }
    }

    pub fn extend(&mut self, vars: Expr, vals: Expr) -> Rc<RefCell<Env>> {
        let mut _vars = vars;
        let mut _vals = vals;
        let mut res = Env {
            table: HashMap::new(),
            parent: Some(Rc::new(RefCell::new(self.clone())))
        };
        loop {
            if _vars.is_last() { break; }
            res.add_binding(_vars.car().as_str(), _vals.car());
            _vars = _vars.cdr();
            _vals = _vals.cdr();
        }
        res.add_binding(_vars.car().as_str(), _vals.car());
        return Rc::new(RefCell::new(res));
    }

    fn setup(&mut self) {
        macro_rules! def_proc {
            ($func_name:ident, $raw_func_name:ident) => (
                fn $func_name(args: Expr) -> Expr {
                    Expr::Bool(BoolNode::new(args.car().$raw_func_name()))
                }
                )
        }

        macro_rules! add_proc {
            ($type_str:expr, $func_name:ident) => (
                self.def_var($type_str.to_string(),
                             Expr::Proc(ProcNode::new($func_name)))
                    )
        }

        def_proc!(is_null, is_empty);
        def_proc!(is_boolean, is_bool);
        def_proc!(is_symbol, is_symbol);
        def_proc!(is_string, is_string);
        def_proc!(is_pair, is_pair);
        def_proc!(is_char, is_char);
        def_proc!(is_int, is_int);

        add_proc!("null?", is_null);
        add_proc!("boolean?", is_boolean);
        add_proc!("symbol?", is_symbol);
        add_proc!("string?", is_string);
        add_proc!("char?", is_char);
        add_proc!("integer?", is_int);
        add_proc!("+", add);
        add_proc!("-", sub);
        add_proc!("*", mul);
        add_proc!("/", div);
        add_proc!("eq?", eq);
        add_proc!("=", eq);
        add_proc!("<", less);
        add_proc!(">", large);
        add_proc!("pair?", is_pair);
        add_proc!("car", car);
        add_proc!("cdr", cdr);
        add_proc!("cons", cons);
    }
}

fn add(args: Expr) -> Expr {
    let mut res = 0is;
    let mut exps = args;
    loop {
        if exps.is_empty() { break; }
        res += exps.car().as_int();
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn sub(args: Expr) -> Expr {
    let mut res = args.car().as_int();
    let mut exps = args.cdr();
    loop {
        if exps.is_empty() { break; }
        res -= exps.car().as_int();
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn mul(args: Expr) -> Expr {
    let mut res = 1is;
    let mut exps = args;
    loop {
        if exps.is_empty() { break; }
        res *= exps.car().as_int();
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn div(args: Expr) -> Expr {
    let mut exps = args;
    let mut res = exps.car().as_int();
    exps = exps.cdr();
    loop {
        if exps.is_empty() { break; }
        let nxt = exps.car().as_int();
        if nxt == 0 {
            return Expr::Symbol(SymbolNode::new("Fail"));
        }
        res /= nxt;
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn cons(args: Expr) -> Expr {
    let obj1 = args.car();
    let obj2 = args.c("da");
    Expr::Pair(PairNode::new(obj1, Expr::Pair(PairNode::new(obj2, Expr::Nil))))
}

fn eq(args: Expr) -> Expr {
    let obj1 = args.car();
    let obj2 = args.c("da");
    Expr::Bool(BoolNode::new(obj1 == obj2))
}

fn less(args: Expr) -> Expr {
    let val = args.car().as_int();
    let mut exps = args.cdr();
    loop {
        if exps.is_empty() { break; }
        if val >= exps.car().as_int() {
            return Expr::Bool(BoolNode::new(false));
        }
        exps = exps.cdr();
    }
    Expr::Bool(BoolNode::new(true))
}

fn car(args: Expr) -> Expr {
    assert!(args.car().is_pair());
    args.c("aa")
}

fn cdr(args: Expr) -> Expr {
    assert!(args.car().is_pair());
    args.c("ad")
}

fn large(args: Expr) -> Expr {
    let val = args.car().as_int();
    let mut exps = args.cdr();
    loop {
        if exps.is_empty() { break; }
        if val <= exps.car().as_int() {
            return Expr::Bool(BoolNode::new(false));
        }
        exps = exps.cdr();
    }
    Expr::Bool(BoolNode::new(true))
}

#[test]
fn test_env() {
    let mut env = Env::new();
    env.str_def("hello", Expr::Str(StrNode::new("world")));

    let val = env.str_lookup("hello");
    assert!(val.unwrap().as_str() == "world");

    env.str_def("1", Expr::Int(IntNode::new(1)));
    let val = env.str_lookup("1");
    assert!(val.unwrap().as_int() == 1);

    env.str_def("1", Expr::Int(IntNode::new(2)));
    let val = env.str_lookup("1");
    assert!(val.unwrap().as_int() == 2);

    env.str_def("sym", Expr::Int(IntNode::new(2)));
    let val = env.str_lookup("sym");
    assert!(val.unwrap().as_int() == 2);

    let val = env.str_lookup("null?");
    assert!(val.unwrap().is_proc());
    let val = env.str_lookup("char?");
    assert!(val.unwrap().is_proc());
    let val = env.str_lookup("integer?");
    assert!(val.unwrap().is_proc());

    let val = env.str_lookup(">");
    assert!(val.unwrap().is_proc());

    let val = env.str_lookup("<");
    assert!(val.unwrap().is_proc());

}

#[test]
fn test_env_extend() {
    let mut env = Env::new();
    env.str_def("hello", Expr::Str(StrNode::new("world")));

    let vars = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("var")), Expr::Nil));
    let vals = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("val")), Expr::Nil));

    let extend_env = env.extend(vars, vals);
    let val = extend_env.clone().borrow_mut().str_lookup("var");
    assert!(val.unwrap().as_str() == "val");

    let val = extend_env.clone().borrow_mut().str_lookup("hello");
    assert!(val.unwrap().as_str() == "world");

    let vars = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("var_x")), Expr::Nil));
    let vals = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("val_x")), Expr::Nil));

    let extend_env = extend_env.clone().borrow_mut().extend(vars, vals);
    let val = extend_env.clone().borrow_mut().str_lookup("var_x");
    assert!(val.unwrap().as_str() == "val_x");

    extend_env.clone().borrow_mut().str_def("1", Expr::Str(StrNode::new("1")));

    let val = extend_env.clone().borrow_mut().str_lookup("1");
    assert!(val.unwrap().as_str() == "1");
}

#[test]
fn test_env_parent() {
    let mut env = Env::new();
    env.str_def("hello", Expr::Str(StrNode::new("world")));

    let vars = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("var")), Expr::Nil));
    let vals = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("val")), Expr::Nil));

    let extend_env = env.extend(vars, vals);
    let parent = extend_env.clone().borrow_mut().parent().unwrap();
    let val = parent.clone().borrow_mut().str_lookup("hello");
    assert!(val.unwrap().as_str() == "world");
}

#[bench]
fn env_bench(b: &mut Bencher) {
    fn test_env() {
        let mut env = Env::new();
        for i in 1..10000 {
            let key = i.to_string();
            env.def_var(key.clone(), Expr::Str(StrNode::new("world")));
            let val = env.lookup(key);
            assert!(val.unwrap().as_str() == "world");
        }
    }

    b.iter(|| test_env());
}

#[bench]
fn env_bench_iter(b: &mut Bencher) {
    fn test_env() {
        let mut env = Env::new();
        for i in 1..1000 {
            env.str_def("hello", Expr::Str(StrNode::new("world")));
            let val = env.str_lookup("hello");
            assert!(val.unwrap().as_str() == "world");
        }
    }

    b.iter(|| test_env());
}
<|endoftext|>


<commit_before>use std::fmt;
use std::iter::Iterator;
use std::slice::Iter;

use xml::attribute::OwnedAttribute;
use xml::name::OwnedName;
use xml::namespace::Namespace;

/// Describes an XML Document.
pub struct Document {
    pub root: Element,
}

/// Describes an element of the tree.
pub struct Element {
    pub name: OwnedName,
    pub attributes: Vec<OwnedAttribute>,
    pub namespace: Namespace,
    children: Vec<Box<Node>>,
}

impl Element {

    /// Create a new Element from the XmlEvent::StartElement's data.
    pub fn new(name: OwnedName, attributes: Vec<OwnedAttribute>, namespace: Namespace) -> Element {
        Element {
            name: name,
            attributes: attributes,
            namespace: namespace,
            children: Vec::new(),
        }
    }

    /// Add a child to this element's children list.
    pub fn add_child(&mut self, child: Node) {
        self.children.push(Box::new(child));
    }

    /// Return the number of child nodes.
    pub fn len(&self) -> usize {
        self.children.len()
    }

    /// Find children by name.
    pub fn find<'a>(&'a self, name: &str) -> Vec<&'a Element> {
        self.iter_elements().filter(|&elem| elem.name.borrow().local_name == name).collect()
    }

    /// Get the text nodes of this Element concatenated.
    pub fn text(&self) -> String {
        let mut buff = String::new();
        for child in self.children.iter() {
            match **child {
                Node::Text(ref text) => {
                    buff.push_str(text);
                }
                _ => continue,
            }
        }
        buff
    }

    /// Create an iterator that only yields Node::Element node types.
    pub fn iter_elements(&self) -> ElementIterator {
        ElementIterator { source: Box::new(self.children.iter()) }
    }

    /// Print this element in a pretty way.
    fn pretty_indent(&self, f: &mut fmt::Formatter, indent: &str) -> fmt::Result {
        let name = self.name.borrow().local_name;
        let next_indent = String::from_str(indent) + "  ";

        try!(write!(f, "{}<{}>\n", indent, name));
        for child in self.children.iter() {
            try!(child.pretty_indent(f, next_indent.as_slice()));
        }
        try!(write!(f, "{}</{}>\n", indent, name));

        Ok(())
    }

}

impl fmt::Debug for Element {

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.pretty_indent(f, "")
    }

}

impl fmt::Display for Element {

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = self.name.borrow().local_name;

        try!(write!(f, "<{}>", name));
        for child in self.children.iter() {
            try!(child.fmt(f));
        }
        try!(write!(f, "</{}>", name));

        Ok(())
    }

}

pub struct ElementIterator<'a> {
    source: Box<Iter<'a, Box<Node>>>,
}

impl<'a> Iterator for ElementIterator<'a> {

    type Item = &'a Element;

    fn next(&mut self) -> Option<&'a Element> {
        loop {
            let it = self.source.next();
            match it {
                None => return None,
                Some(node) => {
                    match **node {
                        Node::Text(_) => continue,
                        Node::Element(ref elem) => return Some(elem),
                    }
                }
            }
        }
    }

}

/// Node of the tree.
/// A node can be a Text node or an Element node.
/// Text nodes do not have children.
pub enum Node {
    Text(String),
    Element(Element),
}

impl Node {

    fn pretty_indent(&self, f: &mut fmt::Formatter, indent: &str) -> fmt::Result {
        match *self {
            Node::Text(ref text) => write!(f, "{}{}\n", indent, text),
            Node::Element(ref elem) => elem.pretty_indent(f, indent),
        }
    }

}

impl fmt::Debug for Node {

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.pretty_indent(f, "")
    }

}

impl fmt::Display for Node {

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Node::Text(ref text) => write!(f, "{}", text),
            Node::Element(ref elem) => elem.fmt(f),
        }
    }

}

#[cfg(test)]
mod tests {

    use std::old_io::{Buffer, MemReader};

    use {build, Document, Element, ElementIterator};

    use xml::EventReader;

    fn xml_to_doc(text: &str) -> Document {
        let mut reader = EventReader::new(MemReader::new(text.as_bytes().to_vec()));
        build(&mut reader).ok().unwrap()
    }

    #[test]
    fn test_find() {
        let xml = "<root><item>aa</item><item>bb</item><item>cc</item><notitem></notitem></root>";
        let doc = xml_to_doc(xml);

        let elems = doc.root.find("item");
        assert_eq!(elems.len(), 3);
    }

    #[test]
    fn test_text_simple() {
        let xml = "<root>abc</root>";
        let doc = xml_to_doc(xml);

        assert_eq!(doc.root.text(), "abc");
    }

    #[test]
    fn test_test_complex() {
        let xml = "<root>abc<sep></sep>def</root>";
        let doc = xml_to_doc(xml);

        assert_eq!(doc.root.text(), "abcdef");
    }

    #[test]
    fn test_iter_elements() {
        let xml = "<root>abc<sep></sep>def<oy></oy></root>";
        let doc = xml_to_doc(xml);

        let it: ElementIterator = doc.root.iter_elements();
        let v: Vec<&Element> = it.collect();

        assert_eq!(doc.root.len(), 4);
        assert_eq!(v.len(), 2);
    }

}
<commit_msg>Add TextIterator and use it in text().<commit_after>use std::fmt;
use std::iter::Iterator;
use std::slice::Iter;

use xml::attribute::OwnedAttribute;
use xml::name::OwnedName;
use xml::namespace::Namespace;

/// Describes an XML Document.
pub struct Document {
    pub root: Element,
}

/// Describes an element of the tree.
pub struct Element {
    pub name: OwnedName,
    pub attributes: Vec<OwnedAttribute>,
    pub namespace: Namespace,
    children: Vec<Box<Node>>,
}

impl Element {

    /// Create a new Element from the XmlEvent::StartElement's data.
    pub fn new(name: OwnedName, attributes: Vec<OwnedAttribute>, namespace: Namespace) -> Element {
        Element {
            name: name,
            attributes: attributes,
            namespace: namespace,
            children: Vec::new(),
        }
    }

    /// Add a child to this element's children list.
    pub fn add_child(&mut self, child: Node) {
        self.children.push(Box::new(child));
    }

    /// Return the number of child nodes.
    pub fn len(&self) -> usize {
        self.children.len()
    }

    /// Find children by name.
    pub fn find<'a>(&'a self, name: &str) -> Vec<&'a Element> {
        self.iter_elements().filter(|&elem| elem.name.borrow().local_name == name).collect()
    }

    /// Get the text nodes of this Element concatenated.
    pub fn text(&self) -> String {
        let mut buf = String::new();
        for text in self.iter_text() {
            buf.push_str(text);
        }
        buf
    }

    /// Create an iterator that only yields Node::Element node types.
    pub fn iter_elements(&self) -> ElementIterator {
        ElementIterator { source: Box::new(self.children.iter()) }
    }

    // Create an iterator that only yields Node::Text node types.
    pub fn iter_text(&self) -> TextIterator {
        TextIterator { source: Box::new(self.children.iter()) }
    }

    /// Print this element in a pretty way.
    fn pretty_indent(&self, f: &mut fmt::Formatter, indent: &str) -> fmt::Result {
        let name = self.name.borrow().local_name;
        let next_indent = String::from_str(indent) + "  ";

        try!(write!(f, "{}<{}>\n", indent, name));
        for child in self.children.iter() {
            try!(child.pretty_indent(f, next_indent.as_slice()));
        }
        try!(write!(f, "{}</{}>\n", indent, name));

        Ok(())
    }

}

impl fmt::Debug for Element {

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.pretty_indent(f, "")
    }

}

impl fmt::Display for Element {

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = self.name.borrow().local_name;

        try!(write!(f, "<{}>", name));
        for child in self.children.iter() {
            try!(child.fmt(f));
        }
        try!(write!(f, "</{}>", name));

        Ok(())
    }

}

/// Iterator for element nodes.
pub struct ElementIterator<'a> {
    source: Box<Iter<'a, Box<Node>>>,
}

impl<'a> Iterator for ElementIterator<'a> {

    type Item = &'a Element;

    fn next(&mut self) -> Option<&'a Element> {
        loop {
            let it = self.source.next();
            match it {
                None => return None,
                Some(node) => {
                    match **node {
                        Node::Text(_) => continue,
                        Node::Element(ref elem) => return Some(elem),
                    }
                }
            }
        }
    }

}

/// Iterator for text nodes.
pub struct TextIterator<'a> {
    source: Box<Iter<'a, Box<Node>>>,
}

impl<'a> Iterator for TextIterator<'a> {

    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        loop {
            let it = self.source.next();
            match it {
                None => return None,
                Some(node) => {
                    match **node {
                        Node::Element(_) => continue,
                        Node::Text(ref text) => return Some(text.as_slice()),
                    }
                }
            }
        }
    }

}

/// Node of the tree.
/// A node can be a Text node or an Element node.
/// Text nodes do not have children.
pub enum Node {
    Text(String),
    Element(Element),
}

impl Node {

    fn pretty_indent(&self, f: &mut fmt::Formatter, indent: &str) -> fmt::Result {
        match *self {
            Node::Text(ref text) => write!(f, "{}{}\n", indent, text),
            Node::Element(ref elem) => elem.pretty_indent(f, indent),
        }
    }

}

impl fmt::Debug for Node {

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.pretty_indent(f, "")
    }

}

impl fmt::Display for Node {

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Node::Text(ref text) => write!(f, "{}", text),
            Node::Element(ref elem) => elem.fmt(f),
        }
    }

}

#[cfg(test)]
mod tests {

    use std::old_io::{Buffer, MemReader};

    use {build, Document, Element, ElementIterator};

    use xml::EventReader;

    fn xml_to_doc(text: &str) -> Document {
        let mut reader = EventReader::new(MemReader::new(text.as_bytes().to_vec()));
        build(&mut reader).ok().unwrap()
    }

    #[test]
    fn test_find() {
        let xml = "<root><item>aa</item><item>bb</item><item>cc</item><notitem></notitem></root>";
        let doc = xml_to_doc(xml);

        let elems = doc.root.find("item");
        assert_eq!(elems.len(), 3);
    }

    #[test]
    fn test_text_simple() {
        let xml = "<root>abc</root>";
        let doc = xml_to_doc(xml);

        assert_eq!(doc.root.text(), "abc");
    }

    #[test]
    fn test_test_complex() {
        let xml = "<root>abc<sep></sep>def</root>";
        let doc = xml_to_doc(xml);

        assert_eq!(doc.root.text(), "abcdef");
    }

    #[test]
    fn test_iter_elements() {
        let xml = "<root>abc<sep></sep>def<oy></oy></root>";
        let doc = xml_to_doc(xml);

        let it: ElementIterator = doc.root.iter_elements();
        let v: Vec<&Element> = it.collect();

        assert_eq!(doc.root.len(), 4);
        assert_eq!(v.len(), 2);
    }

    #[test]
    fn test_iter_text() {
        let xml = "<root>abc<sep></sep>def<oy></oy></root>";
        let doc = xml_to_doc(xml);

        let it = doc.root.iter_text();
        let v: Vec<&str> = it.collect();

        assert_eq!(doc.root.len(), 4);
        assert_eq!(v.len(), 2);
    }

}
<|endoftext|>


<commit_before>//! Providing the features between "full" and "derive" of syn.
//!
//! This crate provides the following two unique data structures.
//!
//! * [`syn_mid::ItemFn`] -- A function whose body is not parsed.
//!
//!   ```text
//!   fn process(n: usize) -> Result<()> { ... }
//!   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^     ^
//!   ```
//!
//! * [`syn_mid::Block`] -- A block whose body is not parsed.
//!
//!   ```text
//!   { ... }
//!   ^     ^
//!   ```
//!
//! Other data structures are the same as data structures of [syn]. These are defined in this crate
//! because they cannot be used in [syn] without "full" feature.
//!
//! ## Optional features
//!
//! syn-mid in the default features aims to provide the features between "full"
//! and "derive" of [syn].
//!
//! * **`clone-impls`** — Clone impls for all syntax tree types.
//!
//! [`syn_mid::ItemFn`]: struct.ItemFn.html
//! [`syn_mid::Block`]: struct.Block.html
//! [syn]: https://github.com/dtolnay/syn
//!

#![doc(html_root_url = "https://docs.rs/syn-mid/0.4.0")]
#![doc(test(attr(deny(warnings), allow(dead_code, unused_assignments, unused_variables))))]
#![warn(unsafe_code)]
#![warn(rust_2018_idioms, unreachable_pub)]
#![warn(single_use_lifetimes)]
#![warn(clippy::all, clippy::pedantic)]
#![allow(
    clippy::eval_order_dependence,
    clippy::large_enum_variant,
    clippy::module_name_repetitions,
    clippy::use_self
)]

// Many of the code contained in this crate are copies from https://github.com/dtolnay/syn.

#[macro_use]
mod macros;

mod arg;
mod pat;
mod path;

pub use self::arg::*;
pub use self::pat::*;

use proc_macro2::TokenStream;
use syn::{
    punctuated::Punctuated, token, Abi, Attribute, Generics, Ident, ReturnType, Token, Visibility,
};

ast_struct! {
    /// A braced block containing Rust statements.
    pub struct Block {
        pub brace_token: token::Brace,
        /// Statements in a block
        pub stmts: TokenStream,
    }
}

ast_struct! {
    /// A free-standing function: `fn process(n: usize) -> Result<()> { ...
    /// }`.
    pub struct ItemFn {
        pub attrs: Vec<Attribute>,
        pub vis: Visibility,
        pub constness: Option<Token![const]>,
        pub asyncness: Option<Token![async]>,
        pub unsafety: Option<Token![unsafe]>,
        pub abi: Option<Abi>,
        pub fn_token: Token![fn],
        pub ident: Ident,
        pub generics: Generics,
        pub paren_token: token::Paren,
        pub inputs: Punctuated<FnArg, Token![,]>,
        pub output: ReturnType,
        pub block: Block,
    }
}

mod parsing {
    use syn::{
        braced, parenthesized,
        parse::{Parse, ParseStream, Result},
        Abi, Attribute, Generics, Ident, ReturnType, Token, Visibility, WhereClause,
    };

    use super::{Block, FnArg, ItemFn};

    impl Parse for Block {
        fn parse(input: ParseStream<'_>) -> Result<Self> {
            let content;
            Ok(Self {
                brace_token: braced!(content in input),
                stmts: content.parse()?,
            })
        }
    }

    impl Parse for ItemFn {
        fn parse(input: ParseStream<'_>) -> Result<Self> {
            let attrs = input.call(Attribute::parse_outer)?;
            let vis: Visibility = input.parse()?;
            let constness: Option<Token![const]> = input.parse()?;
            let asyncness: Option<Token![async]> = input.parse()?;
            let unsafety: Option<Token![unsafe]> = input.parse()?;
            let abi: Option<Abi> = input.parse()?;
            let fn_token: Token![fn] = input.parse()?;
            let ident: Ident = input.parse()?;
            let generics: Generics = input.parse()?;

            let content;
            let paren_token = parenthesized!(content in input);
            let inputs = content.parse_terminated(FnArg::parse)?;

            let output: ReturnType = input.parse()?;
            let where_clause: Option<WhereClause> = input.parse()?;

            let block = input.parse()?;

            Ok(Self {
                attrs,
                vis,
                constness,
                asyncness,
                unsafety,
                abi,
                fn_token,
                ident,
                generics: Generics {
                    where_clause,
                    ..generics
                },
                paren_token,
                inputs,
                output,
                block,
            })
        }
    }
}

mod printing {
    use proc_macro2::TokenStream;
    use quote::{ToTokens, TokenStreamExt};

    use super::{Block, ItemFn};

    impl ToTokens for Block {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.brace_token.surround(tokens, |tokens| {
                tokens.append_all(self.stmts.clone());
            });
        }
    }

    impl ToTokens for ItemFn {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            tokens.append_all(&self.attrs);
            self.vis.to_tokens(tokens);
            self.constness.to_tokens(tokens);
            self.asyncness.to_tokens(tokens);
            self.unsafety.to_tokens(tokens);
            self.abi.to_tokens(tokens);
            self.fn_token.to_tokens(tokens);
            self.ident.to_tokens(tokens);
            self.generics.to_tokens(tokens);
            self.paren_token.surround(tokens, |tokens| {
                self.inputs.to_tokens(tokens);
            });
            self.output.to_tokens(tokens);
            self.generics.where_clause.to_tokens(tokens);
            self.block.brace_token.surround(tokens, |tokens| {
                tokens.append_all(self.block.stmts.clone());
            });
        }
    }
}
<commit_msg>Deny rust_2018_idioms and single_use_lifetimes for doc tests<commit_after>//! Providing the features between "full" and "derive" of syn.
//!
//! This crate provides the following two unique data structures.
//!
//! * [`syn_mid::ItemFn`] -- A function whose body is not parsed.
//!
//!   ```text
//!   fn process(n: usize) -> Result<()> { ... }
//!   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^     ^
//!   ```
//!
//! * [`syn_mid::Block`] -- A block whose body is not parsed.
//!
//!   ```text
//!   { ... }
//!   ^     ^
//!   ```
//!
//! Other data structures are the same as data structures of [syn]. These are defined in this crate
//! because they cannot be used in [syn] without "full" feature.
//!
//! ## Optional features
//!
//! syn-mid in the default features aims to provide the features between "full"
//! and "derive" of [syn].
//!
//! * **`clone-impls`** — Clone impls for all syntax tree types.
//!
//! [`syn_mid::ItemFn`]: struct.ItemFn.html
//! [`syn_mid::Block`]: struct.Block.html
//! [syn]: https://github.com/dtolnay/syn
//!

#![doc(html_root_url = "https://docs.rs/syn-mid/0.4.0")]
#![doc(test(
    no_crate_inject,
    attr(
        deny(warnings, rust_2018_idioms, single_use_lifetimes),
        allow(dead_code)
    )
))]
#![warn(unsafe_code)]
#![warn(rust_2018_idioms, unreachable_pub)]
#![warn(single_use_lifetimes)]
#![warn(clippy::all, clippy::pedantic)]
#![allow(
    clippy::eval_order_dependence,
    clippy::large_enum_variant,
    clippy::module_name_repetitions,
    clippy::use_self
)]

// Many of the code contained in this crate are copies from https://github.com/dtolnay/syn.

#[macro_use]
mod macros;

mod arg;
mod pat;
mod path;

pub use self::arg::*;
pub use self::pat::*;

use proc_macro2::TokenStream;
use syn::{
    punctuated::Punctuated, token, Abi, Attribute, Generics, Ident, ReturnType, Token, Visibility,
};

ast_struct! {
    /// A braced block containing Rust statements.
    pub struct Block {
        pub brace_token: token::Brace,
        /// Statements in a block
        pub stmts: TokenStream,
    }
}

ast_struct! {
    /// A free-standing function: `fn process(n: usize) -> Result<()> { ...
    /// }`.
    pub struct ItemFn {
        pub attrs: Vec<Attribute>,
        pub vis: Visibility,
        pub constness: Option<Token![const]>,
        pub asyncness: Option<Token![async]>,
        pub unsafety: Option<Token![unsafe]>,
        pub abi: Option<Abi>,
        pub fn_token: Token![fn],
        pub ident: Ident,
        pub generics: Generics,
        pub paren_token: token::Paren,
        pub inputs: Punctuated<FnArg, Token![,]>,
        pub output: ReturnType,
        pub block: Block,
    }
}

mod parsing {
    use syn::{
        braced, parenthesized,
        parse::{Parse, ParseStream, Result},
        Abi, Attribute, Generics, Ident, ReturnType, Token, Visibility, WhereClause,
    };

    use super::{Block, FnArg, ItemFn};

    impl Parse for Block {
        fn parse(input: ParseStream<'_>) -> Result<Self> {
            let content;
            Ok(Self {
                brace_token: braced!(content in input),
                stmts: content.parse()?,
            })
        }
    }

    impl Parse for ItemFn {
        fn parse(input: ParseStream<'_>) -> Result<Self> {
            let attrs = input.call(Attribute::parse_outer)?;
            let vis: Visibility = input.parse()?;
            let constness: Option<Token![const]> = input.parse()?;
            let asyncness: Option<Token![async]> = input.parse()?;
            let unsafety: Option<Token![unsafe]> = input.parse()?;
            let abi: Option<Abi> = input.parse()?;
            let fn_token: Token![fn] = input.parse()?;
            let ident: Ident = input.parse()?;
            let generics: Generics = input.parse()?;

            let content;
            let paren_token = parenthesized!(content in input);
            let inputs = content.parse_terminated(FnArg::parse)?;

            let output: ReturnType = input.parse()?;
            let where_clause: Option<WhereClause> = input.parse()?;

            let block = input.parse()?;

            Ok(Self {
                attrs,
                vis,
                constness,
                asyncness,
                unsafety,
                abi,
                fn_token,
                ident,
                generics: Generics {
                    where_clause,
                    ..generics
                },
                paren_token,
                inputs,
                output,
                block,
            })
        }
    }
}

mod printing {
    use proc_macro2::TokenStream;
    use quote::{ToTokens, TokenStreamExt};

    use super::{Block, ItemFn};

    impl ToTokens for Block {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.brace_token.surround(tokens, |tokens| {
                tokens.append_all(self.stmts.clone());
            });
        }
    }

    impl ToTokens for ItemFn {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            tokens.append_all(&self.attrs);
            self.vis.to_tokens(tokens);
            self.constness.to_tokens(tokens);
            self.asyncness.to_tokens(tokens);
            self.unsafety.to_tokens(tokens);
            self.abi.to_tokens(tokens);
            self.fn_token.to_tokens(tokens);
            self.ident.to_tokens(tokens);
            self.generics.to_tokens(tokens);
            self.paren_token.surround(tokens, |tokens| {
                self.inputs.to_tokens(tokens);
            });
            self.output.to_tokens(tokens);
            self.generics.where_clause.to_tokens(tokens);
            self.block.brace_token.surround(tokens, |tokens| {
                tokens.append_all(self.block.stmts.clone());
            });
        }
    }
}
<|endoftext|>


<commit_before>use std::error;
use std::fmt;

// TODO(stjepang): Reword documentation in this module.

/// An error returned from the [`Sender::send`] method.
///
/// A send operation can only fail if the receiving end of a channel is disconnected, implying that
/// the data could never be received. The error contains the data being sent as a payload so it can
/// be recovered.
///
/// [`Sender::send`]: struct.Sender.html#method.send
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct SendError<T>(pub T);

/// This enumeration is the list of the possible error outcomes for the [`try_send`] method.
///
/// [`try_send`]: struct.Sender.html#method.try_send
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum TrySendError<T> {
    /// The data could not be sent on the channel because it would require that the callee block to
    /// send the data.
    ///
    /// If this is a zero-capacity channel, then the error indicates that there was no receiver
    /// available to receive the message at the time.
    Full(T),

    /// This channel's receiving half has disconnected, so the data could not be sent. The data is
    /// returned back to the callee in this case.
    Disconnected(T),
}

/// This enumeration is the list of possible errors that made [`send_timeout`] unable to return
/// data when called. This can occur with bounded channels only.
///
/// [`send_timeout`]: struct.Sender.html#method.send_timeout
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum SendTimeoutError<T> {
    /// This channel is currently full, but the receivers have not yet disconnected.
    Timeout(T),

    /// The channel's receiving half has become disconnected.
    Disconnected(T),
}

/// An error returned from the [`Receiver::recv`] method.
///
/// The [`recv`] operation can only fail if the sending half of a channel is disconnected and the
/// channel is empty, implying that no further messages will ever be received.
///
/// [`Receiver::recv`]: struct.Receiver.html#method.recv
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct RecvError;

/// This enumeration is the list of the possible reasons that [`try_recv`] could not return data
/// when called. This can occur with both bounded and unbounded channels.
///
/// [`try_recv`]: struct.Receiver.html#method.recv
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum TryRecvError {
    /// This channel is currently empty, but the senders have not yet disconnected, so data may yet
    /// become available.
    ///
    /// If this is a zero-capacity channel, then the error indicates that there was no sender
    /// available to at the time.
    Empty,

    /// The channel's sending half has become disconnected, and there will never be any more data
    /// received on it.
    Disconnected,
}

/// This enumeration is the list of possible errors that made [`recv_timeout`] unable to return
/// data when called. This can occur with both bounded and unbounded channels.
///
/// [`recv_timeout`]: struct.Receiver.html#method.recv_timeout
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum RecvTimeoutError {
    /// This channel is currently empty, but the senders have not yet disconnected, so data may yet
    /// become available.
    Timeout,

    /// The channel's sending half has become disconnected, and there will never be any more data
    /// received on it.
    Disconnected,
}

/// An error returned from the [`Select::try_select`] method.
///
/// [`Select::try_select`]: struct.Select.html#method.try_select
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct TrySelectError;

/// An error returned from the [`Select::select_timeout`] method.
///
/// [`Select::select_timeout`]: struct.Select.html#method.select_timeout
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct SelectTimeoutError;

impl<T> fmt::Debug for SendError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "SendError(..)".fmt(f)
    }
}

impl<T> fmt::Display for SendError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "sending on a disconnected channel".fmt(f)
    }
}

impl<T: Send> error::Error for SendError<T> {
    fn description(&self) -> &str {
        "sending on a disconnected channel"
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl<T> SendError<T> {
    /// Unwraps the value.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use crossbeam_channel::unbounded;
    ///
    /// let (tx, rx) = unbounded();
    /// drop(rx);
    ///
    /// if let Err(err) = tx.send("foo") {
    ///     assert_eq!(err.into_inner(), "foo");
    /// }
    /// ```
    pub fn into_inner(self) -> T {
        self.0
    }
}

impl<T> fmt::Debug for TrySendError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            TrySendError::Full(..) => "Full(..)".fmt(f),
            TrySendError::Disconnected(..) => "Disconnected(..)".fmt(f),
        }
    }
}

impl<T> fmt::Display for TrySendError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            TrySendError::Full(..) => "sending on a full channel".fmt(f),
            TrySendError::Disconnected(..) => "sending on a disconnected channel".fmt(f),
        }
    }
}

impl<T: Send> error::Error for TrySendError<T> {
    fn description(&self) -> &str {
        match *self {
            TrySendError::Full(..) => "sending on a full channel",
            TrySendError::Disconnected(..) => "sending on a disconnected channel",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl<T> From<SendError<T>> for TrySendError<T> {
    fn from(err: SendError<T>) -> TrySendError<T> {
        match err {
            SendError(t) => TrySendError::Disconnected(t),
        }
    }
}

impl<T> TrySendError<T> {
    /// Unwraps the value.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use crossbeam_channel::bounded;
    ///
    /// let (tx, rx) = bounded(0);
    ///
    /// if let Err(err) = tx.try_send("foo") {
    ///     assert_eq!(err.into_inner(), "foo");
    /// }
    /// ```
    pub fn into_inner(self) -> T {
        match self {
            TrySendError::Full(v) => v,
            TrySendError::Disconnected(v) => v,
        }
    }
}

impl<T> fmt::Debug for SendTimeoutError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "SendTimeoutError(..)".fmt(f)
    }
}

impl<T> fmt::Display for SendTimeoutError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SendTimeoutError::Timeout(..) => "timed out waiting on channel".fmt(f),
            SendTimeoutError::Disconnected(..) => "sending on a disconnected channel".fmt(f),
        }
    }
}

impl<T: Send> error::Error for SendTimeoutError<T> {
    fn description(&self) -> &str {
        "sending on an empty and disconnected channel"
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl<T> From<SendError<T>> for SendTimeoutError<T> {
    fn from(err: SendError<T>) -> SendTimeoutError<T> {
        match err {
            SendError(e) => SendTimeoutError::Disconnected(e),
        }
    }
}

impl<T> SendTimeoutError<T> {
    /// Unwraps the value.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use std::time::Duration;
    /// use crossbeam_channel::unbounded;
    ///
    /// let (tx, rx) = unbounded();
    ///
    /// if let Err(err) = tx.send_timeout("foo", Duration::from_secs(0)) {
    ///     assert_eq!(err.into_inner(), "foo");
    /// }
    /// ```
    pub fn into_inner(self) -> T {
        match self {
            SendTimeoutError::Timeout(v) => v,
            SendTimeoutError::Disconnected(v) => v,
        }
    }
}

impl fmt::Display for RecvError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "receiving on an empty and disconnected channel".fmt(f)
    }
}

impl error::Error for RecvError {
    fn description(&self) -> &str {
        "receiving on an empty and disconnected channel"
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl fmt::Display for TryRecvError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            TryRecvError::Empty => "receiving on an empty channel".fmt(f),
            TryRecvError::Disconnected => "receiving on an empty and disconnected channel".fmt(f),
        }
    }
}

impl error::Error for TryRecvError {
    fn description(&self) -> &str {
        match *self {
            TryRecvError::Empty => "receiving on an empty channel",
            TryRecvError::Disconnected => "receiving on an empty and disconnected channel",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl From<RecvError> for TryRecvError {
    fn from(err: RecvError) -> TryRecvError {
        match err {
            RecvError => TryRecvError::Disconnected,
        }
    }
}

impl fmt::Display for RecvTimeoutError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            RecvTimeoutError::Timeout => "timed out waiting on channel".fmt(f),
            RecvTimeoutError::Disconnected => "channel is empty and disconnected".fmt(f),
        }
    }
}

impl error::Error for RecvTimeoutError {
    fn description(&self) -> &str {
        match *self {
            RecvTimeoutError::Timeout => "timed out waiting on channel",
            RecvTimeoutError::Disconnected => "channel is empty and sending half is Disconnected",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl From<RecvError> for RecvTimeoutError {
    fn from(err: RecvError) -> RecvTimeoutError {
        match err {
            RecvError => RecvTimeoutError::Disconnected,
        }
    }
}

impl fmt::Display for TrySelectError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "all cases in select would block".fmt(f)
    }
}

impl error::Error for TrySelectError {
    fn description(&self) -> &str {
        "all cases in select would block"
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl fmt::Display for SelectTimeoutError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "timed out waiting on select".fmt(f)
    }
}

impl error::Error for SelectTimeoutError {
    fn description(&self) -> &str {
        "timed out waiting on select"
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}
<commit_msg>Update docs<commit_after>use std::error;
use std::fmt;

/// An error returned from the [`send`] method.
///
/// A send operation can only fail if the channel is disconnected, implying that the message could
/// never be sent.
///
/// The error contains the message being sent so it can be recovered.
///
/// [`send`]: struct.Sender.html#method.send
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct SendError<T>(pub T);

/// An error returned from the [`try_send`] method.
///
/// The error contains the message being sent so it can be recovered.
///
/// [`try_send`]: struct.Sender.html#method.try_send
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum TrySendError<T> {
    /// The message could not be sent because the channel is full.
    ///
    /// If this is a zero-capacity channel, then the error indicates that there was no receiver
    /// available to receive the message at the time.
    Full(T),

    /// The message could not be sent because the channel is disconnected.
    Disconnected(T),
}

/// An error returned from the [`send_timeout`] method.
///
/// The error contains the message being sent so it can be recovered.
///
/// [`send_timeout`]: struct.Sender.html#method.send_timeout
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum SendTimeoutError<T> {
    /// The message could not be sent because the channel is full and the operation timed out.
    ///
    /// If this is a zero-capacity channel, then the error indicates that there was no receiver
    /// available to receive the message and the operation timed out.
    Timeout(T),

    /// The message could not be sent because the channel is disconnected.
    Disconnected(T),
}

/// An error returned from the [`recv`] method.
///
/// A receive operation can only fail if the channel is empty and disconnected.
/// implying that a message could never be received.
///
/// [`recv`]: struct.Receiver.html#method.recv
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct RecvError;

/// An error returned from the [`try_recv`] method.
///
/// [`try_recv`]: struct.Receiver.html#method.recv
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum TryRecvError {
    /// A message could not be received because the channel is empty.
    ///
    /// If this is a zero-capacity channel, then the error indicates that there was no sender
    /// available to send a message at the time.
    Empty,

    /// The message could not be received because the channel is empty and disconnected.
    Disconnected,
}

/// An error returned from the [`recv_timeout`] method.
///
/// [`recv_timeout`]: struct.Receiver.html#method.recv_timeout
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum RecvTimeoutError {
    /// A message could not be received because the channel is empty and the operation timed out.
    ///
    /// If this is a zero-capacity channel, then the error indicates that there was no sender
    /// available to send a message and the operation timed out.
    Timeout,

    /// The message could not be received because the channel is empty and disconnected.
    Disconnected,
}

/// An error returned from the [`try_select`] method.
///
/// [`try_select`]: struct.Select.html#method.try_select
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct TrySelectError;

/// An error returned from the [`select_timeout`] method.
///
/// [`select_timeout`]: struct.Select.html#method.select_timeout
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct SelectTimeoutError;

impl<T> fmt::Debug for SendError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "SendError(..)".fmt(f)
    }
}

impl<T> fmt::Display for SendError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "sending on a disconnected channel".fmt(f)
    }
}

impl<T: Send> error::Error for SendError<T> {
    fn description(&self) -> &str {
        "sending on a disconnected channel"
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl<T> SendError<T> {
    /// Unwraps the message.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use crossbeam_channel as channel;
    ///
    /// let (s, r) = channel::unbounded();
    /// drop(r);
    ///
    /// if let Err(err) = s.send("foo") {
    ///     assert_eq!(err.into_inner(), "foo");
    /// }
    /// ```
    pub fn into_inner(self) -> T {
        self.0
    }
}

impl<T> fmt::Debug for TrySendError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            TrySendError::Full(..) => "Full(..)".fmt(f),
            TrySendError::Disconnected(..) => "Disconnected(..)".fmt(f),
        }
    }
}

impl<T> fmt::Display for TrySendError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            TrySendError::Full(..) => "sending on a full channel".fmt(f),
            TrySendError::Disconnected(..) => "sending on a disconnected channel".fmt(f),
        }
    }
}

impl<T: Send> error::Error for TrySendError<T> {
    fn description(&self) -> &str {
        match *self {
            TrySendError::Full(..) => "sending on a full channel",
            TrySendError::Disconnected(..) => "sending on a disconnected channel",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl<T> From<SendError<T>> for TrySendError<T> {
    fn from(err: SendError<T>) -> TrySendError<T> {
        match err {
            SendError(t) => TrySendError::Disconnected(t),
        }
    }
}

impl<T> TrySendError<T> {
    /// Unwraps the message.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use crossbeam_channel as bounded;
    ///
    /// let (s, r) = channel::bounded(0);
    ///
    /// if let Err(err) = s.try_send("foo") {
    ///     assert_eq!(err.into_inner(), "foo");
    /// }
    /// ```
    pub fn into_inner(self) -> T {
        match self {
            TrySendError::Full(v) => v,
            TrySendError::Disconnected(v) => v,
        }
    }
}

impl<T> fmt::Debug for SendTimeoutError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "SendTimeoutError(..)".fmt(f)
    }
}

impl<T> fmt::Display for SendTimeoutError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SendTimeoutError::Timeout(..) => "timed out waiting on send operation".fmt(f),
            SendTimeoutError::Disconnected(..) => "sending on a disconnected channel".fmt(f),
        }
    }
}

impl<T: Send> error::Error for SendTimeoutError<T> {
    fn description(&self) -> &str {
        "sending on an empty and disconnected channel"
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl<T> From<SendError<T>> for SendTimeoutError<T> {
    fn from(err: SendError<T>) -> SendTimeoutError<T> {
        match err {
            SendError(e) => SendTimeoutError::Disconnected(e),
        }
    }
}

impl<T> SendTimeoutError<T> {
    /// Unwraps the message.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use std::time::Duration;
    /// use crossbeam_channel as channel;
    ///
    /// let (s, r) = channel::unbounded();
    ///
    /// if let Err(err) = s.send_timeout("foo", Duration::from_secs(0)) {
    ///     assert_eq!(err.into_inner(), "foo");
    /// }
    /// ```
    pub fn into_inner(self) -> T {
        match self {
            SendTimeoutError::Timeout(v) => v,
            SendTimeoutError::Disconnected(v) => v,
        }
    }
}

impl fmt::Display for RecvError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "receiving on an empty and disconnected channel".fmt(f)
    }
}

impl error::Error for RecvError {
    fn description(&self) -> &str {
        "receiving on an empty and disconnected channel"
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl fmt::Display for TryRecvError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            TryRecvError::Empty => "receiving on an empty channel".fmt(f),
            TryRecvError::Disconnected => "receiving on an empty and disconnected channel".fmt(f),
        }
    }
}

impl error::Error for TryRecvError {
    fn description(&self) -> &str {
        match *self {
            TryRecvError::Empty => "receiving on an empty channel",
            TryRecvError::Disconnected => "receiving on an empty and disconnected channel",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl From<RecvError> for TryRecvError {
    fn from(err: RecvError) -> TryRecvError {
        match err {
            RecvError => TryRecvError::Disconnected,
        }
    }
}

impl fmt::Display for RecvTimeoutError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            RecvTimeoutError::Timeout => "timed out waiting on receive operation".fmt(f),
            RecvTimeoutError::Disconnected => "channel is empty and disconnected".fmt(f),
        }
    }
}

impl error::Error for RecvTimeoutError {
    fn description(&self) -> &str {
        match *self {
            RecvTimeoutError::Timeout => "timed out waiting on receive operation",
            RecvTimeoutError::Disconnected => "channel is empty and disconnected",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl From<RecvError> for RecvTimeoutError {
    fn from(err: RecvError) -> RecvTimeoutError {
        match err {
            RecvError => RecvTimeoutError::Disconnected,
        }
    }
}

impl fmt::Display for TrySelectError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "all cases in select would block".fmt(f)
    }
}

impl error::Error for TrySelectError {
    fn description(&self) -> &str {
        "all cases in select would block"
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl fmt::Display for SelectTimeoutError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "timed out waiting on select".fmt(f)
    }
}

impl error::Error for SelectTimeoutError {
    fn description(&self) -> &str {
        "timed out waiting on select"
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}
<|endoftext|>


<commit_before>// Copyright 2015, Paul Osborne <osbpau@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/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.
//
// Portions of this implementation are based on work by Nat Pryce:
// https://github.com/npryce/rusty-pi/blob/master/src/pi/gpio.rs

#![crate_type = "lib"]
#![crate_name = "sysfs_gpio"]
#![feature(io)]

///! GPIO access under Linux using the GPIO sysfs interface
///!
///! The methods exposed by this library are centered around
///! the `Pin` struct and map pretty directly the API exposed
///! by the kernel in syfs (https://www.kernel.org/doc/Documentation/gpio/sysfs.txt).
///!
///! # Examples
///!
///! Typical usage for systems where one wants to ensure that
///! the pins in use are unexported upon completion looks like
///! the follwoing:
///!
///! ```rust
///! extern crate sysfs_gpio;
///! use sysfs_gpio::Pin;
///!
///!
///! ```

use std::io::prelude::*;
use std::io;
use std::io::{Error, ErrorKind};
use std::fs;
use std::fs::{File};

pub struct Pin {
    pin_num : u64,
}

#[derive(Copy,Debug)]
pub enum Direction {In, Out, High, Low}

#[derive(Copy,Debug)]
pub enum Edge {NoInterrupt, RisingEdge, FallingEdge, BothEdges}

#[macro_export]
macro_rules! try_unexport {
    ($gpio:ident, $e:expr) => (match $e {
        Ok(res) => res,
        Err(e) => { try!($gpio.unexport()); return Err(e) },
    });
}

impl Pin {
    /// Write all of the provided contents to the specified devFile
    fn write_to_device_file(&self, dev_file_name: &str, value: &str) -> io::Result<()> {
        let gpio_path = format!("/sys/class/gpio/gpio{}/{}", self.pin_num, dev_file_name);
        let mut dev_file = try!(File::create(&gpio_path));
        try!(dev_file.write_all(value.as_bytes()));
        Ok(())
    }

    /// Create a new Pin with the provided `pin_num`
    ///
    /// This function does not export the provided pin_num.  If that
    /// functionality is desired, `export` should be used instead.
    pub fn new(pin_num : u64) -> Pin {
        Pin {
            pin_num: pin_num,
        }
    }

    /// Export the GPIO
    ///
    /// This is equivalent to `echo N > /sys/class/gpio/export` with
    /// the exception that the case where the GPIO is already exported
    /// is not an error.
    ///
    /// # Errors
    ///
    /// The main cases in which this function will fail and return an
    /// error are the following:
    /// 1. The system does not support the GPIO sysfs interface
    /// 2. The requested GPIO is out of range and cannot be exported
    /// 3. The requested GPIO is in use by the kernel and cannot
    ///    be exported by use in userspace
    ///
    /// # Example
    /// ```rust
    /// use sysfs_gpio::Pin;
    ///
    /// gpio = Pin::new(24);
    /// match gpio.export() {
    ///     Ok(()) => println!("Gpio {} exported!", gpio.pin),
    ///     Err(err) => println!("Gpio {} could not be exported: {}", gpio.pin, err),
    /// }
    /// ```
    pub fn export(&self) -> io::Result<()> {
        match fs::metadata(&format!("/sys/class/gpio/gpio{}", self.pin_num)) {
            Ok(_) => {},
            Err(_) => {
                let mut export_file = try!(File::create("/sys/class/gpio/export"));
                try!(export_file.write_all(format!("{}", self.pin_num).as_bytes()));
            }
        };
        Ok(())
    }

    /// Unexport the GPIO
    ///
    /// This function will unexport the provided by from syfs if
    /// it is currently exported.  If the pin is not currently
    /// exported, it will return without error.  That is, whenever
    /// this function returns Ok, the GPIO is not exported.
    pub fn unexport(&self) -> io::Result<()> {
        match fs::metadata(&format!("/sys/class/gpio/{}", self.pin_num)) {
            Ok(_) => {
                let mut unexport_file = try!(File::create("/sys/class/gpio/unexport"));
                try!(unexport_file.write_all(format!("{}", self.pin_num).as_bytes()));
            },
            Err(_) => {} // not exported
        };
        Ok(())
    }

    /// Set this GPIO as either an input or an output
    ///
    /// The basic values allowed here are `Direction::In` and
    /// `Direction::Out` which set the Pin as either an input
    /// or output respectively.  In addition to those, two
    /// additional settings of `Direction::High` and
    /// `Direction::Low`.  These both set the Pin as an output
    /// but do so with an initial value of high or low respectively.
    /// This allows for glitch-free operation.
    ///
    /// Note that this entry may not exist if the kernel does
    /// not support changing the direction of a pin in userspace.  If
    /// this is the case, you will get an error.
    pub fn set_direction(&self, dir : Direction) -> io::Result<()> {
        self.write_to_device_file("direction", match dir {
            Direction::In => "in",
            Direction::Out => "out",
            Direction::High => "high",
            Direction::Low => "low",
        })
    }

    /// Get the value of the Pin (0 or 1)
    ///
    /// If successful, 1 will be returned if the pin is high
    /// and 0 will be returned if the pin is low (this may or may
    /// not match the signal level of the actual signal depending
    /// on the GPIO "active_low" entry).
    pub fn get_value(&self) -> io::Result<u8> {
        let mut dev_file = try!(File::open(&format!("/sys/class/gpio/gpio{}/value", self.pin_num)));
        let mut s = String::with_capacity(10);
        try!(dev_file.read_to_string(&mut s));
        match s[..1].parse::<u8>() {
            Ok(n) => Ok(n),
            Err(_) => Err(Error::new(ErrorKind::Other, "Unexpected Error", None)),
        }
    }

    /// Set the value of the Pin
    ///
    /// This will set the value of the pin either high or low.
    /// A 0 value will set the pin low and any other value will
    /// set the pin high (1 is typical).
    pub fn set_value(&self, value : u8) -> io::Result<()> {
        let val = if value == 0 {
            "0"
        } else {
            "1"
        };
        self.write_to_device_file("value", val)
    }
}
<commit_msg>tests: don't rune examples as rust doc-tests<commit_after>// Copyright 2015, Paul Osborne <osbpau@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/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.
//
// Portions of this implementation are based on work by Nat Pryce:
// https://github.com/npryce/rusty-pi/blob/master/src/pi/gpio.rs

#![crate_type = "lib"]
#![crate_name = "sysfs_gpio"]
#![feature(io)]

///! GPIO access under Linux using the GPIO sysfs interface
///!
///! The methods exposed by this library are centered around
///! the `Pin` struct and map pretty directly the API exposed
///! by the kernel in syfs (https://www.kernel.org/doc/Documentation/gpio/sysfs.txt).
///!
///! # Examples
///!
///! Typical usage for systems where one wants to ensure that
///! the pins in use are unexported upon completion looks like
///! the follwoing:
///!
///! ```rust,ignore
///! extern crate sysfs_gpio;
///! use sysfs_gpio::Pin;
///!
///!
///! ```

use std::io::prelude::*;
use std::io;
use std::io::{Error, ErrorKind};
use std::fs;
use std::fs::{File};

pub struct Pin {
    pin_num : u64,
}

#[derive(Copy,Debug)]
pub enum Direction {In, Out, High, Low}

#[derive(Copy,Debug)]
pub enum Edge {NoInterrupt, RisingEdge, FallingEdge, BothEdges}

#[macro_export]
macro_rules! try_unexport {
    ($gpio:ident, $e:expr) => (match $e {
        Ok(res) => res,
        Err(e) => { try!($gpio.unexport()); return Err(e) },
    });
}

impl Pin {
    /// Write all of the provided contents to the specified devFile
    fn write_to_device_file(&self, dev_file_name: &str, value: &str) -> io::Result<()> {
        let gpio_path = format!("/sys/class/gpio/gpio{}/{}", self.pin_num, dev_file_name);
        let mut dev_file = try!(File::create(&gpio_path));
        try!(dev_file.write_all(value.as_bytes()));
        Ok(())
    }

    /// Create a new Pin with the provided `pin_num`
    ///
    /// This function does not export the provided pin_num.  If that
    /// functionality is desired, `export` should be used instead.
    pub fn new(pin_num : u64) -> Pin {
        Pin {
            pin_num: pin_num,
        }
    }

    /// Export the GPIO
    ///
    /// This is equivalent to `echo N > /sys/class/gpio/export` with
    /// the exception that the case where the GPIO is already exported
    /// is not an error.
    ///
    /// # Errors
    ///
    /// The main cases in which this function will fail and return an
    /// error are the following:
    /// 1. The system does not support the GPIO sysfs interface
    /// 2. The requested GPIO is out of range and cannot be exported
    /// 3. The requested GPIO is in use by the kernel and cannot
    ///    be exported by use in userspace
    ///
    /// # Example
    /// ```rust,ignore
    /// use sysfs_gpio::Pin;
    ///
    /// gpio = Pin::new(24);
    /// match gpio.export() {
    ///     Ok(()) => println!("Gpio {} exported!", gpio.pin),
    ///     Err(err) => println!("Gpio {} could not be exported: {}", gpio.pin, err),
    /// }
    /// ```
    pub fn export(&self) -> io::Result<()> {
        match fs::metadata(&format!("/sys/class/gpio/gpio{}", self.pin_num)) {
            Ok(_) => {},
            Err(_) => {
                let mut export_file = try!(File::create("/sys/class/gpio/export"));
                try!(export_file.write_all(format!("{}", self.pin_num).as_bytes()));
            }
        };
        Ok(())
    }

    /// Unexport the GPIO
    ///
    /// This function will unexport the provided by from syfs if
    /// it is currently exported.  If the pin is not currently
    /// exported, it will return without error.  That is, whenever
    /// this function returns Ok, the GPIO is not exported.
    pub fn unexport(&self) -> io::Result<()> {
        match fs::metadata(&format!("/sys/class/gpio/{}", self.pin_num)) {
            Ok(_) => {
                let mut unexport_file = try!(File::create("/sys/class/gpio/unexport"));
                try!(unexport_file.write_all(format!("{}", self.pin_num).as_bytes()));
            },
            Err(_) => {} // not exported
        };
        Ok(())
    }

    /// Set this GPIO as either an input or an output
    ///
    /// The basic values allowed here are `Direction::In` and
    /// `Direction::Out` which set the Pin as either an input
    /// or output respectively.  In addition to those, two
    /// additional settings of `Direction::High` and
    /// `Direction::Low`.  These both set the Pin as an output
    /// but do so with an initial value of high or low respectively.
    /// This allows for glitch-free operation.
    ///
    /// Note that this entry may not exist if the kernel does
    /// not support changing the direction of a pin in userspace.  If
    /// this is the case, you will get an error.
    pub fn set_direction(&self, dir : Direction) -> io::Result<()> {
        self.write_to_device_file("direction", match dir {
            Direction::In => "in",
            Direction::Out => "out",
            Direction::High => "high",
            Direction::Low => "low",
        })
    }

    /// Get the value of the Pin (0 or 1)
    ///
    /// If successful, 1 will be returned if the pin is high
    /// and 0 will be returned if the pin is low (this may or may
    /// not match the signal level of the actual signal depending
    /// on the GPIO "active_low" entry).
    pub fn get_value(&self) -> io::Result<u8> {
        let mut dev_file = try!(File::open(&format!("/sys/class/gpio/gpio{}/value", self.pin_num)));
        let mut s = String::with_capacity(10);
        try!(dev_file.read_to_string(&mut s));
        match s[..1].parse::<u8>() {
            Ok(n) => Ok(n),
            Err(_) => Err(Error::new(ErrorKind::Other, "Unexpected Error", None)),
        }
    }

    /// Set the value of the Pin
    ///
    /// This will set the value of the pin either high or low.
    /// A 0 value will set the pin low and any other value will
    /// set the pin high (1 is typical).
    pub fn set_value(&self, value : u8) -> io::Result<()> {
        let val = if value == 0 {
            "0"
        } else {
            "1"
        };
        self.write_to_device_file("value", val)
    }
}
<|endoftext|>