<commit_before>/// The Toml Set extensions

use toml::Value;

use tokenizer::tokenize_with_seperator;
use tokenizer::Token;
use error::*;

pub trait TomlValueSetExt {

    /// Extension function for setting a value in the current toml::Value document
    /// using a custom seperator
    ///
    /// # Semantics
    ///
    /// The function _never_ creates intermediate data structures (Tables or Arrays) in the
    /// document.
    ///
    /// # Return value
    ///
    /// * If the set operation worked correctly, `Ok(None)` is returned.
    /// * If the set operation replaced an existing value `Ok(Some(old_value))` is returned
    /// * On failure, `Err(e)` is returned:
    ///     * If the query is `"a.b.c"` but there is no table `"b"`: error
    ///     * If the query is `"a.b.[0]"` but "`b"` is not an array: error
    ///     * If the query is `"a.b.[3]"` but the array at "`b"` has no index `3`: error
    ///     * etc.
    ///
    fn set_with_seperator(&mut self, query: &String, sep: char, value: Value) -> Result<Option<Value>>;

    /// Extension function for setting a value from the current toml::Value document
    ///
    /// See documentation of `TomlValueSetExt::set_with_seperator`
    fn set(&mut self, query: &String, value: Value) -> Result<Option<Value>> {
        self.set_with_seperator(query, '.', value)
    }

}

impl TomlValueSetExt for Value {

    fn set_with_seperator(&mut self, query: &String, sep: char, value: Value) -> Result<Option<Value>> {
        use resolver::mut_resolver::resolve;

        let mut tokens = try!(tokenize_with_seperator(query, sep));
        let last = tokens.pop_last();

        let mut val = try!(resolve(self, &tokens));
        let last = last.unwrap_or_else(|| Box::new(tokens));

        match *last {
            Token::Identifier { ident, .. } => {
                match val {
                    &mut Value::Table(ref mut t) => {
                        Ok(t.insert(ident, value))
                    }
                    _ => unimplemented!()
                }
            }

            Token::Index { idx, .. } => {
                match val {
                    &mut Value::Array(ref mut a) => {
                        if a.len() > idx {
                            let result = a.swap_remove(idx);
                            a.insert(idx, value);
                            Ok(Some(result))
                        } else {
                            a.push(value);
                            Ok(None)
                        }
                    }
                    _ => unimplemented!()
                }
            }

        }
    }

}

#[cfg(test)]
mod test {
    use super::*;
    use toml::Value;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_set_with_seperator_into_table() {
        let mut toml : Value = toml_from_str(r#"
        [table]
        a = 0
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("table.a"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::Integer(0)));

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let inner = t.get("table");
                assert!(inner.is_some());

                let inner = inner.unwrap();
                assert!(is_match!(inner, &Value::Table(_)));
                match inner {
                    &Value::Table(ref t) => {
                        assert!(!t.is_empty());

                        let a = t.get("a");
                        assert!(a.is_some());

                        let a = a.unwrap();
                        assert!(is_match!(a, &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_set_with_seperator_into_table_key_nonexistent() {
        let mut toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("table.a"), '.', Value::Integer(1));

        assert!(res.is_ok());
        let res = res.unwrap();

        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let inner = t.get("table");
                assert!(inner.is_some());

                let inner = inner.unwrap();
                assert!(is_match!(inner, &Value::Table(_)));
                match inner {
                    &Value::Table(ref t) => {
                        assert!(!t.is_empty());

                        let a = t.get("a");
                        assert!(a.is_some());

                        let a = a.unwrap();
                        assert!(is_match!(a, &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_set_with_seperator_into_array() {
        use std::ops::Index;

        let mut toml : Value = toml_from_str(r#"
        array = [ 0 ]
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("array.[0]"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::Integer(0)));

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let inner = t.get("array");
                assert!(inner.is_some());

                let inner = inner.unwrap();
                assert!(is_match!(inner, &Value::Array(_)));
                match inner {
                    &Value::Array(ref a) => {
                        assert!(!a.is_empty());
                        assert!(is_match!(a.index(0), &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_set_with_seperator_into_table_index_nonexistent() {
        use std::ops::Index;

        let mut toml : Value = toml_from_str(r#"
        array = []
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("array.[0]"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let inner = t.get("array");
                assert!(inner.is_some());

                let inner = inner.unwrap();
                assert!(is_match!(inner, &Value::Array(_)));
                match inner {
                    &Value::Array(ref a) => {
                        assert!(!a.is_empty());
                        assert!(is_match!(a.index(0), &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_set_with_seperator_into_nested_table() {
        let mut toml : Value = toml_from_str(r#"
        [a.b.c]
        d = 0
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("a.b.c.d"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::Integer(0)));

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let a = t.get("a");
                assert!(a.is_some());

                let a = a.unwrap();
                assert!(is_match!(a, &Value::Table(_)));
                match a {
                    &Value::Table(ref a) => {
                        assert!(!a.is_empty());

                        let b_tab = a.get("b");
                        assert!(b_tab.is_some());

                        let b_tab = b_tab.unwrap();
                        assert!(is_match!(b_tab, &Value::Table(_)));
                        match b_tab {
                            &Value::Table(ref b) => {
                                assert!(!b.is_empty());

                                let c_tab = b.get("c");
                                assert!(c_tab.is_some());

                                let c_tab = c_tab.unwrap();
                                assert!(is_match!(c_tab, &Value::Table(_)));
                                match c_tab {
                                    &Value::Table(ref c) => {
                                        assert!(!c.is_empty());

                                        let d = c.get("d");
                                        assert!(d.is_some());

                                        let d = d.unwrap();
                                        assert!(is_match!(d, &Value::Integer(1)));
                                    },
                                    _ => panic!("What just happenend?"),
                                }
                            },
                            _ => panic!("What just happenend?"),
                        }
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_set_with_seperator_into_nonexistent_table() {
        let mut toml : Value = toml_from_str("").unwrap();

        let res = toml.set_with_seperator(&String::from("table.a"), '.', Value::Integer(1));

        assert!(res.is_err());

        let res = res.unwrap_err();
        assert!(is_match!(res.kind(), &ErrorKind::IdentifierNotFoundInDocument(_)));
    }

    #[test]
    fn test_set_with_seperator_into_nonexistent_array() {
        let mut toml : Value = toml_from_str("").unwrap();

        let res = toml.set_with_seperator(&String::from("[0]"), '.', Value::Integer(1));

        assert!(res.is_err());

        let res = res.unwrap_err();
        assert!(is_match!(res.kind(), &ErrorKind::NoIndexInTable(0)));
    }

}

<commit_msg>Add tests for setting values in wrong type of structures<commit_after>/// The Toml Set extensions

use toml::Value;

use tokenizer::tokenize_with_seperator;
use tokenizer::Token;
use error::*;

pub trait TomlValueSetExt {

    /// Extension function for setting a value in the current toml::Value document
    /// using a custom seperator
    ///
    /// # Semantics
    ///
    /// The function _never_ creates intermediate data structures (Tables or Arrays) in the
    /// document.
    ///
    /// # Return value
    ///
    /// * If the set operation worked correctly, `Ok(None)` is returned.
    /// * If the set operation replaced an existing value `Ok(Some(old_value))` is returned
    /// * On failure, `Err(e)` is returned:
    ///     * If the query is `"a.b.c"` but there is no table `"b"`: error
    ///     * If the query is `"a.b.[0]"` but "`b"` is not an array: error
    ///     * If the query is `"a.b.[3]"` but the array at "`b"` has no index `3`: error
    ///     * etc.
    ///
    fn set_with_seperator(&mut self, query: &String, sep: char, value: Value) -> Result<Option<Value>>;

    /// Extension function for setting a value from the current toml::Value document
    ///
    /// See documentation of `TomlValueSetExt::set_with_seperator`
    fn set(&mut self, query: &String, value: Value) -> Result<Option<Value>> {
        self.set_with_seperator(query, '.', value)
    }

}

impl TomlValueSetExt for Value {

    fn set_with_seperator(&mut self, query: &String, sep: char, value: Value) -> Result<Option<Value>> {
        use resolver::mut_resolver::resolve;

        let mut tokens = try!(tokenize_with_seperator(query, sep));
        let last = tokens.pop_last();

        let mut val = try!(resolve(self, &tokens));
        let last = last.unwrap_or_else(|| Box::new(tokens));

        match *last {
            Token::Identifier { ident, .. } => {
                match val {
                    &mut Value::Table(ref mut t) => {
                        Ok(t.insert(ident, value))
                    }
                    _ => unimplemented!()
                }
            }

            Token::Index { idx, .. } => {
                match val {
                    &mut Value::Array(ref mut a) => {
                        if a.len() > idx {
                            let result = a.swap_remove(idx);
                            a.insert(idx, value);
                            Ok(Some(result))
                        } else {
                            a.push(value);
                            Ok(None)
                        }
                    }
                    _ => unimplemented!()
                }
            }

        }
    }

}

#[cfg(test)]
mod test {
    use super::*;
    use toml::Value;
    use toml::from_str as toml_from_str;

    #[test]
    fn test_set_with_seperator_into_table() {
        let mut toml : Value = toml_from_str(r#"
        [table]
        a = 0
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("table.a"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::Integer(0)));

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let inner = t.get("table");
                assert!(inner.is_some());

                let inner = inner.unwrap();
                assert!(is_match!(inner, &Value::Table(_)));
                match inner {
                    &Value::Table(ref t) => {
                        assert!(!t.is_empty());

                        let a = t.get("a");
                        assert!(a.is_some());

                        let a = a.unwrap();
                        assert!(is_match!(a, &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_set_with_seperator_into_table_key_nonexistent() {
        let mut toml : Value = toml_from_str(r#"
        [table]
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("table.a"), '.', Value::Integer(1));

        assert!(res.is_ok());
        let res = res.unwrap();

        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let inner = t.get("table");
                assert!(inner.is_some());

                let inner = inner.unwrap();
                assert!(is_match!(inner, &Value::Table(_)));
                match inner {
                    &Value::Table(ref t) => {
                        assert!(!t.is_empty());

                        let a = t.get("a");
                        assert!(a.is_some());

                        let a = a.unwrap();
                        assert!(is_match!(a, &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_set_with_seperator_into_array() {
        use std::ops::Index;

        let mut toml : Value = toml_from_str(r#"
        array = [ 0 ]
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("array.[0]"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::Integer(0)));

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let inner = t.get("array");
                assert!(inner.is_some());

                let inner = inner.unwrap();
                assert!(is_match!(inner, &Value::Array(_)));
                match inner {
                    &Value::Array(ref a) => {
                        assert!(!a.is_empty());
                        assert!(is_match!(a.index(0), &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_set_with_seperator_into_table_index_nonexistent() {
        use std::ops::Index;

        let mut toml : Value = toml_from_str(r#"
        array = []
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("array.[0]"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_none());

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let inner = t.get("array");
                assert!(inner.is_some());

                let inner = inner.unwrap();
                assert!(is_match!(inner, &Value::Array(_)));
                match inner {
                    &Value::Array(ref a) => {
                        assert!(!a.is_empty());
                        assert!(is_match!(a.index(0), &Value::Integer(1)));
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_set_with_seperator_into_nested_table() {
        let mut toml : Value = toml_from_str(r#"
        [a.b.c]
        d = 0
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("a.b.c.d"), '.', Value::Integer(1));

        assert!(res.is_ok());

        let res = res.unwrap();
        assert!(res.is_some());
        let res = res.unwrap();
        assert!(is_match!(res, Value::Integer(0)));

        assert!(is_match!(toml, Value::Table(_)));
        match toml {
            Value::Table(ref t) => {
                assert!(!t.is_empty());

                let a = t.get("a");
                assert!(a.is_some());

                let a = a.unwrap();
                assert!(is_match!(a, &Value::Table(_)));
                match a {
                    &Value::Table(ref a) => {
                        assert!(!a.is_empty());

                        let b_tab = a.get("b");
                        assert!(b_tab.is_some());

                        let b_tab = b_tab.unwrap();
                        assert!(is_match!(b_tab, &Value::Table(_)));
                        match b_tab {
                            &Value::Table(ref b) => {
                                assert!(!b.is_empty());

                                let c_tab = b.get("c");
                                assert!(c_tab.is_some());

                                let c_tab = c_tab.unwrap();
                                assert!(is_match!(c_tab, &Value::Table(_)));
                                match c_tab {
                                    &Value::Table(ref c) => {
                                        assert!(!c.is_empty());

                                        let d = c.get("d");
                                        assert!(d.is_some());

                                        let d = d.unwrap();
                                        assert!(is_match!(d, &Value::Integer(1)));
                                    },
                                    _ => panic!("What just happenend?"),
                                }
                            },
                            _ => panic!("What just happenend?"),
                        }
                    },
                    _ => panic!("What just happenend?"),
                }
            },
            _ => panic!("What just happenend?"),
        }
    }

    #[test]
    fn test_set_with_seperator_into_nonexistent_table() {
        let mut toml : Value = toml_from_str("").unwrap();

        let res = toml.set_with_seperator(&String::from("table.a"), '.', Value::Integer(1));

        assert!(res.is_err());

        let res = res.unwrap_err();
        assert!(is_match!(res.kind(), &ErrorKind::IdentifierNotFoundInDocument(_)));
    }

    #[test]
    fn test_set_with_seperator_into_nonexistent_array() {
        let mut toml : Value = toml_from_str("").unwrap();

        let res = toml.set_with_seperator(&String::from("[0]"), '.', Value::Integer(1));

        assert!(res.is_err());

        let res = res.unwrap_err();
        assert!(is_match!(res.kind(), &ErrorKind::NoIndexInTable(0)));
    }

    #[test]
    fn test_set_with_seperator_ident_into_ary() {
        let mut toml : Value = toml_from_str(r#"
        array = [ 0 ]
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("array.foo"), '.', Value::Integer(2));

        assert!(res.is_err());
        let res = res.unwrap_err();

        assert!(is_match!(res.kind(), &ErrorKind::NoIdentifierInArray(_)));
    }

    #[test]
    fn test_set_with_seperator_index_into_table() {
        let mut toml : Value = toml_from_str(r#"
        foo = { bar = 1 }
        "#).unwrap();

        let res = toml.set_with_seperator(&String::from("foo.[0]"), '.', Value::Integer(2));

        assert!(res.is_err());
        let res = res.unwrap_err();

        assert!(is_match!(res.kind(), &ErrorKind::NoIndexInTable(_)));
    }

}

<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at https://mozilla.org/MPL/2.0/.
use crate::common;

/// An element of the [Table of contents](struct.Toc.html)
///
/// # Example
///
/// ```
/// use epub_builder::TocElement;
/// TocElement::new("chapter_1.xhtml", "Chapter 1")
///     .child(TocElement::new("chapter_1.xhtml#1", "Chapter 1, section 1")
///               .child(TocElement::new("chapter_1.xhtml#1-1", "Chapter 1, section 1, subsection 1")));
/// ```
#[derive(Debug, Clone)]
pub struct TocElement {
    /// The level. 0: part, 1: chapter, 2: section, ...
    pub level: i32,
    /// The link
    pub url: String,
    /// Title of this entry
    pub title: String,
    /// Inner elements
    pub children: Vec<TocElement>,
}

impl TocElement {
    /// Creates a new element of the toc
    ///
    /// By default, the element's level is `1` and it has no children.
    pub fn new<S1: Into<String>, S2: Into<String>>(url: S1, title: S2) -> TocElement {
        TocElement {
            level: 1,
            url: url.into(),
            title: title.into(),
            children: vec![],
        }
    }

    /// Sets the level of a TocElement
    pub fn level(mut self, level: i32) -> Self {
        self.level = level;
        self
    }

    /// Change level, recursively, so the structure keeps having some sense
    fn level_up(&mut self, level: i32) {
        self.level = level;
        for child in &mut self.children {
            if child.level <= self.level {
                child.level_up(level + 1);
            }
        }
    }

    /// Add a child to this element.
    ///
    /// This adjust the level of the child to be the level of its parents, plus 1;
    /// this means that there is no point in manually setting the level to elements
    /// added with this method.
    ///
    /// # Example
    ///
    /// ```
    /// use epub_builder::TocElement;
    /// let elem = TocElement::new("foo.xhtml", "Foo")
    ///     .child(TocElement::new("bar.xhtml", "Bar")
    ///          .level(42));
    ///
    /// // `Bar`'s level wiss still be `2`.
    /// ```
    pub fn child(mut self, mut child: TocElement) -> Self {
        if child.level <= self.level {
            child.level_up(self.level + 1);
        }
        self.children.push(child);
        self
    }

    /// Add element to self or to children, according to its level
    ///
    /// This will adds `element` directly to `self` if its level is equal or less
    /// to the last children element; else it will insert it to the last child.
    ///
    /// See the `add` method of [`Toc](struct.toc.html).
    pub fn add(&mut self, element: TocElement) {
        let mut inserted = false;
        if let Some(ref mut last_elem) = self.children.last_mut() {
            if element.level > last_elem.level {
                last_elem.add(element.clone());
                inserted = true;
            }
        }
        if !inserted {
            self.children.push(element);
        }
    }

    /// Render element for Epub's toc.ncx format
    #[doc(hidden)]
    pub fn render_epub(&self, mut offset: u32) -> (u32, String) {
        offset += 1;
        let id = offset;
        let children = if self.children.is_empty() {
            String::new()
        } else {
            let mut output: Vec<String> = Vec::new();
            for child in &self.children {
                let (n, s) = child.render_epub(offset);
                offset = n;
                output.push(s);
            }
            format!("\n{}", common::indent(output.join("\n"), 1))
        };
        // Try to sanitize the escape title of all HTML elements; if it fails, insert it as is
        let escaped_title = html_escape::encode_text(&self.title);
        (
            offset,
            format!(
                "\
<navPoint id=\"navPoint-{id}\">
  <navLabel>
   <text>{title}</text>
  </navLabel>
  <content src=\"{url}\"/>{children}
</navPoint>",
                id = id,
                title = escaped_title.trim(),
                url = self.url,
                children = children
            ),
        )
    }

    /// Render element as a list element
    #[doc(hidden)]
    pub fn render(&self, numbered: bool) -> String {
        if self.title.is_empty() {
            return String::new();
        }
        if self.children.is_empty() {
            format!(
                "
{title}
",
                link = self.url,
                title = self.title,
            )
        } else {
            let mut output: Vec<String> = Vec::new();
            for child in &self.children {
                output.push(child.render(numbered));
            }
            let children = format!(
                "<{oul}>\n{children}\n</{oul}>",
                oul = if numbered { "ol" } else { "ul" },
                children = common::indent(output.join("\n"), 1)
            );
            format!(
                "\

  {title}
{children}

",
                link = self.url,
                // escape < > symbols by < > using 'encode_text()' in link's Title
                title = html_escape::encode_text(&self.title),
                children = common::indent(children, 1)
            )
        }
    }
}

/// A Table Of Contents
///
/// It basically contains a list of [`TocElement`](struct.TocElement.html)s.
///
/// # Example
///
/// Creates a Toc, fills it, and render it to HTML:
///
/// ```
/// use epub_builder::{Toc, TocElement};
/// Toc::new()
///    // add a level-1 element
///    .add(TocElement::new("intro.xhtml", "Introduction"))
///    // add a level-1 element with children
///    .add(TocElement::new("chapter_1.xhtml", "Chapter 1")
///            .child(TocElement::new("chapter_1.xhtml#section1", "1.1: Some section"))
///            .child(TocElement::new("chapter_1.xhtml#section2", "1.2: another section")))
///    // add a level-2 element, which will thus get "attached" to previous level-1 element
///    .add(TocElement::new("chapter_1.xhtml#section3", "1.3: yet another section")
///            .level(2))
///    // render the toc (non-numbered list) and returns a string
///    .render(false);
/// ```
#[derive(Debug, Default)]
pub struct Toc {
    /// The elements composing the TOC
    pub elements: Vec<TocElement>,
}

impl Toc {
    /// Creates a new, empty, Toc
    pub fn new() -> Toc {
        Toc { elements: vec![] }
    }

    /// Returns `true` if the toc is empty, `false` else.
    ///
    /// Note that `empty` here means that the the toc has zero *or one*
    /// element, since it's still not worth displaying it in this case.
    pub fn is_empty(&self) -> bool {
        self.elements.len() <= 1
    }

    /// Adds a [`TocElement`](struct.TocElement.html) to the Toc.
    ///
    /// This will look at the element's level and will insert it as a child of the last
    /// element of the Toc that has an inferior level.
    ///
    /// # Example
    ///
    /// ```
    /// # use epub_builder::{Toc, TocElement};
    /// let mut toc = Toc::new();
    /// // Insert an element at default level (1)
    /// toc.add(TocElement::new("chapter_1.xhtml", "Chapter 1"));
    ///
    /// // Insert an element at level 2
    /// toc.add(TocElement::new("section_1.xhtml", "Section 1")
    ///           .level(2));
    /// // "Section 1" is now a child of "Chapter 1"
    /// ```
    ///
    /// There are some cases where this behaviour might not be what you want; however,
    /// it makes sure that the TOC can still be renderer correctly for HTML and EPUB.
    pub fn add(&mut self, element: TocElement) -> &mut Self {
        let mut inserted = false;
        if let Some(ref mut last_elem) = self.elements.last_mut() {
            if element.level > last_elem.level {
                last_elem.add(element.clone());
                inserted = true;
            }
        }
        if !inserted {
            self.elements.push(element);
        }

        self
    }

    /// Render the Toc in a toc.ncx compatible way, for EPUB.
    pub fn render_epub(&mut self) -> String {
        let mut output: Vec<String> = Vec::new();
        let mut offset = 0;
        for elem in &self.elements {
            let (n, s) = elem.render_epub(offset);
            offset = n;
            output.push(s);
        }
        common::indent(output.join("\n"), 2)
    }

    /// Render the Toc in either
 or
 form (according to numbered)
    pub fn render(&mut self, numbered: bool) -> String {
        let mut output: Vec<String> = Vec::new();
        for elem in &self.elements {
            debug!("rendered elem: {:?}", &elem.render(numbered));
            output.push(elem.render(numbered));
        }
        common::indent(
            format!(
                "<{oul}>\n{output}\n</{oul}>",
                output = common::indent(output.join("\n"), 1),
                oul = if numbered { "ol" } else { "ul" }
            ),
            2,
        )
    }
}

/////////////////////////////////////////////////////////////////////////////////
///                                  TESTS                                     //
/////////////////////////////////////////////////////////////////////////////////

#[test]
fn toc_simple() {
    let mut toc = Toc::new();
    toc.add(TocElement::new("#1", "0.0.1").level(3));
    toc.add(TocElement::new("#2", "1").level(1));
    toc.add(TocElement::new("#3", "1.0.1").level(3));
    toc.add(TocElement::new("#4", "1.1").level(2));
    toc.add(TocElement::new("#5", "2"));
    let actual = toc.render(false);
    let expected = "

0.0.1

        1

1.0.1

1.1

2

";
    assert_eq!(&actual, expected);
}

#[test]
fn toc_epub_simple() {
    let mut toc = Toc::new();
    toc.add(TocElement::new("#1", "1"));
    toc.add(TocElement::new("#2", "2"));
    let actual = toc.render_epub();
    let expected = "    <navPoint id=\"navPoint-1\">
      <navLabel>
       <text>1</text>
      </navLabel>
      <content src=\"#1\"/>
    </navPoint>
    <navPoint id=\"navPoint-2\">
      <navLabel>
       <text>2</text>
      </navLabel>
      <content src=\"#2\"/>
    </navPoint>";
    assert_eq!(&actual, expected);
}

#[test]
fn toc_epub_simple_sublevels() {
    let mut toc = Toc::new();
    toc.add(TocElement::new("#1", "1"));
    toc.add(TocElement::new("#1.1", "1.1").level(2));
    toc.add(TocElement::new("#2", "2"));
    toc.add(TocElement::new("#2.1", "2.1").level(2));
    let actual = toc.render_epub();
    let expected = "    <navPoint id=\"navPoint-1\">
      <navLabel>
       <text>1</text>
      </navLabel>
      <content src=\"#1\"/>
      <navPoint id=\"navPoint-2\">
        <navLabel>
         <text>1.1</text>
        </navLabel>
        <content src=\"#1.1\"/>
      </navPoint>
    </navPoint>
    <navPoint id=\"navPoint-3\">
      <navLabel>
       <text>2</text>
      </navLabel>
      <content src=\"#2\"/>
      <navPoint id=\"navPoint-4\">
        <navLabel>
         <text>2.1</text>
        </navLabel>
        <content src=\"#2.1\"/>
      </navPoint>
    </navPoint>";
    assert_eq!(&actual, expected);
}

#[test]
fn toc_epub_broken_sublevels() {
    let mut toc = Toc::new();
    toc.add(TocElement::new("#1.1", "1.1").level(2));
    toc.add(TocElement::new("#2", "2"));
    toc.add(TocElement::new("#2.1", "2.1").level(2));
    let actual = toc.render_epub();
    let expected = "    <navPoint id=\"navPoint-1\">
      <navLabel>
       <text>1.1</text>
      </navLabel>
      <content src=\"#1.1\"/>
    </navPoint>
    <navPoint id=\"navPoint-2\">
      <navLabel>
       <text>2</text>
      </navLabel>
      <content src=\"#2\"/>
      <navPoint id=\"navPoint-3\">
        <navLabel>
         <text>2.1</text>
        </navLabel>
        <content src=\"#2.1\"/>
      </navPoint>
    </navPoint>";
    assert_eq!(&actual, expected);
}

#[test]
fn toc_epub_title_escaped() {
    let mut toc = Toc::new();
    toc.add(TocElement::new("#1", "D&D"));
    let actual = toc.render_epub();
    let expected = "    <navPoint id=\"navPoint-1\">
      <navLabel>
       <text>D&D</text>
      </navLabel>
      <content src=\"#1\"/>
    </navPoint>";
    assert_eq!(&actual, expected);
}
<commit_msg>toc.ncx is escaped, but not nav.xhtml<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at https://mozilla.org/MPL/2.0/.
use crate::common;

/// An element of the [Table of contents](struct.Toc.html)
///
/// # Example
///
/// ```
/// use epub_builder::TocElement;
/// TocElement::new("chapter_1.xhtml", "Chapter 1")
///     .child(TocElement::new("chapter_1.xhtml#1", "Chapter 1, section 1")
///               .child(TocElement::new("chapter_1.xhtml#1-1", "Chapter 1, section 1, subsection 1")));
/// ```
#[derive(Debug, Clone)]
pub struct TocElement {
    /// The level. 0: part, 1: chapter, 2: section, ...
    pub level: i32,
    /// The link
    pub url: String,
    /// Title of this entry
    pub title: String,
    /// Inner elements
    pub children: Vec<TocElement>,
}

impl TocElement {
    /// Creates a new element of the toc
    ///
    /// By default, the element's level is `1` and it has no children.
    pub fn new<S1: Into<String>, S2: Into<String>>(url: S1, title: S2) -> TocElement {
        TocElement {
            level: 1,
            url: url.into(),
            title: title.into(),
            children: vec![],
        }
    }

    /// Sets the level of a TocElement
    pub fn level(mut self, level: i32) -> Self {
        self.level = level;
        self
    }

    /// Change level, recursively, so the structure keeps having some sense
    fn level_up(&mut self, level: i32) {
        self.level = level;
        for child in &mut self.children {
            if child.level <= self.level {
                child.level_up(level + 1);
            }
        }
    }

    /// Add a child to this element.
    ///
    /// This adjust the level of the child to be the level of its parents, plus 1;
    /// this means that there is no point in manually setting the level to elements
    /// added with this method.
    ///
    /// # Example
    ///
    /// ```
    /// use epub_builder::TocElement;
    /// let elem = TocElement::new("foo.xhtml", "Foo")
    ///     .child(TocElement::new("bar.xhtml", "Bar")
    ///          .level(42));
    ///
    /// // `Bar`'s level wiss still be `2`.
    /// ```
    pub fn child(mut self, mut child: TocElement) -> Self {
        if child.level <= self.level {
            child.level_up(self.level + 1);
        }
        self.children.push(child);
        self
    }

    /// Add element to self or to children, according to its level
    ///
    /// This will adds `element` directly to `self` if its level is equal or less
    /// to the last children element; else it will insert it to the last child.
    ///
    /// See the `add` method of [`Toc](struct.toc.html).
    pub fn add(&mut self, element: TocElement) {
        let mut inserted = false;
        if let Some(ref mut last_elem) = self.children.last_mut() {
            if element.level > last_elem.level {
                last_elem.add(element.clone());
                inserted = true;
            }
        }
        if !inserted {
            self.children.push(element);
        }
    }

    /// Render element for Epub's toc.ncx format
    #[doc(hidden)]
    pub fn render_epub(&self, mut offset: u32) -> (u32, String) {
        offset += 1;
        let id = offset;
        let children = if self.children.is_empty() {
            String::new()
        } else {
            let mut output: Vec<String> = Vec::new();
            for child in &self.children {
                let (n, s) = child.render_epub(offset);
                offset = n;
                output.push(s);
            }
            format!("\n{}", common::indent(output.join("\n"), 1))
        };
        // Try to sanitize the escape title of all HTML elements; if it fails, insert it as is
        let escaped_title = html_escape::encode_text(&self.title);
        (
            offset,
            format!(
                "\
<navPoint id=\"navPoint-{id}\">
  <navLabel>
   <text>{title}</text>
  </navLabel>
  <content src=\"{url}\"/>{children}
</navPoint>",
                id = id,
                title = escaped_title.trim(),
                url = self.url,
                children = children
            ),
        )
    }

    /// Render element as a list element
    #[doc(hidden)]
    pub fn render(&self, numbered: bool) -> String {
        if self.title.is_empty() {
            return String::new();
        }
        if self.children.is_empty() {
            let escaped_title = html_escape::encode_text(&self.title);
            format!(
                "
{title}
",
                link = self.url,
                title = escaped_title,
            )
        } else {
            let mut output: Vec<String> = Vec::new();
            for child in &self.children {
                output.push(child.render(numbered));
            }
            let children = format!(
                "<{oul}>\n{children}\n</{oul}>",
                oul = if numbered { "ol" } else { "ul" },
                children = common::indent(output.join("\n"), 1)
            );
            format!(
                "\

  {title}
{children}

",
                link = self.url,
                // escape < > symbols by < > using 'encode_text()' in link's Title
                title = html_escape::encode_text(&self.title),
                children = common::indent(children, 1)
            )
        }
    }
}

/// A Table Of Contents
///
/// It basically contains a list of [`TocElement`](struct.TocElement.html)s.
///
/// # Example
///
/// Creates a Toc, fills it, and render it to HTML:
///
/// ```
/// use epub_builder::{Toc, TocElement};
/// Toc::new()
///    // add a level-1 element
///    .add(TocElement::new("intro.xhtml", "Introduction"))
///    // add a level-1 element with children
///    .add(TocElement::new("chapter_1.xhtml", "Chapter 1")
///            .child(TocElement::new("chapter_1.xhtml#section1", "1.1: Some section"))
///            .child(TocElement::new("chapter_1.xhtml#section2", "1.2: another section")))
///    // add a level-2 element, which will thus get "attached" to previous level-1 element
///    .add(TocElement::new("chapter_1.xhtml#section3", "1.3: yet another section")
///            .level(2))
///    // render the toc (non-numbered list) and returns a string
///    .render(false);
/// ```
#[derive(Debug, Default)]
pub struct Toc {
    /// The elements composing the TOC
    pub elements: Vec<TocElement>,
}

impl Toc {
    /// Creates a new, empty, Toc
    pub fn new() -> Toc {
        Toc { elements: vec![] }
    }

    /// Returns `true` if the toc is empty, `false` else.
    ///
    /// Note that `empty` here means that the the toc has zero *or one*
    /// element, since it's still not worth displaying it in this case.
    pub fn is_empty(&self) -> bool {
        self.elements.len() <= 1
    }

    /// Adds a [`TocElement`](struct.TocElement.html) to the Toc.
    ///
    /// This will look at the element's level and will insert it as a child of the last
    /// element of the Toc that has an inferior level.
    ///
    /// # Example
    ///
    /// ```
    /// # use epub_builder::{Toc, TocElement};
    /// let mut toc = Toc::new();
    /// // Insert an element at default level (1)
    /// toc.add(TocElement::new("chapter_1.xhtml", "Chapter 1"));
    ///
    /// // Insert an element at level 2
    /// toc.add(TocElement::new("section_1.xhtml", "Section 1")
    ///           .level(2));
    /// // "Section 1" is now a child of "Chapter 1"
    /// ```
    ///
    /// There are some cases where this behaviour might not be what you want; however,
    /// it makes sure that the TOC can still be renderer correctly for HTML and EPUB.
    pub fn add(&mut self, element: TocElement) -> &mut Self {
        let mut inserted = false;
        if let Some(ref mut last_elem) = self.elements.last_mut() {
            if element.level > last_elem.level {
                last_elem.add(element.clone());
                inserted = true;
            }
        }
        if !inserted {
            self.elements.push(element);
        }

        self
    }

    /// Render the Toc in a toc.ncx compatible way, for EPUB.
    pub fn render_epub(&mut self) -> String {
        let mut output: Vec<String> = Vec::new();
        let mut offset = 0;
        for elem in &self.elements {
            let (n, s) = elem.render_epub(offset);
            offset = n;
            output.push(s);
        }
        common::indent(output.join("\n"), 2)
    }

    /// Render the Toc in either
 or
 form (according to numbered)
    pub fn render(&mut self, numbered: bool) -> String {
        let mut output: Vec<String> = Vec::new();
        for elem in &self.elements {
            debug!("rendered elem: {:?}", &elem.render(numbered));
            output.push(elem.render(numbered));
        }
        common::indent(
            format!(
                "<{oul}>\n{output}\n</{oul}>",
                output = common::indent(output.join("\n"), 1),
                oul = if numbered { "ol" } else { "ul" }
            ),
            2,
        )
    }
}

/////////////////////////////////////////////////////////////////////////////////
///                                  TESTS                                     //
/////////////////////////////////////////////////////////////////////////////////

#[test]
fn toc_simple() {
    let mut toc = Toc::new();
    toc.add(TocElement::new("#1", "0.0.1").level(3));
    toc.add(TocElement::new("#2", "1").level(1));
    toc.add(TocElement::new("#3", "1.0.1").level(3));
    toc.add(TocElement::new("#4", "1.1").level(2));
    toc.add(TocElement::new("#5", "2"));
    let actual = toc.render(false);
    let expected = "

0.0.1

        1

1.0.1

1.1

2

";
    assert_eq!(&actual, expected);
}

#[test]
fn toc_epub_simple() {
    let mut toc = Toc::new();
    toc.add(TocElement::new("#1", "1"));
    toc.add(TocElement::new("#2", "2"));
    let actual = toc.render_epub();
    let expected = "    <navPoint id=\"navPoint-1\">
      <navLabel>
       <text>1</text>
      </navLabel>
      <content src=\"#1\"/>
    </navPoint>
    <navPoint id=\"navPoint-2\">
      <navLabel>
       <text>2</text>
      </navLabel>
      <content src=\"#2\"/>
    </navPoint>";
    assert_eq!(&actual, expected);
}

#[test]
fn toc_epub_simple_sublevels() {
    let mut toc = Toc::new();
    toc.add(TocElement::new("#1", "1"));
    toc.add(TocElement::new("#1.1", "1.1").level(2));
    toc.add(TocElement::new("#2", "2"));
    toc.add(TocElement::new("#2.1", "2.1").level(2));
    let actual = toc.render_epub();
    let expected = "    <navPoint id=\"navPoint-1\">
      <navLabel>
       <text>1</text>
      </navLabel>
      <content src=\"#1\"/>
      <navPoint id=\"navPoint-2\">
        <navLabel>
         <text>1.1</text>
        </navLabel>
        <content src=\"#1.1\"/>
      </navPoint>
    </navPoint>
    <navPoint id=\"navPoint-3\">
      <navLabel>
       <text>2</text>
      </navLabel>
      <content src=\"#2\"/>
      <navPoint id=\"navPoint-4\">
        <navLabel>
         <text>2.1</text>
        </navLabel>
        <content src=\"#2.1\"/>
      </navPoint>
    </navPoint>";
    assert_eq!(&actual, expected);
}

#[test]
fn toc_epub_broken_sublevels() {
    let mut toc = Toc::new();
    toc.add(TocElement::new("#1.1", "1.1").level(2));
    toc.add(TocElement::new("#2", "2"));
    toc.add(TocElement::new("#2.1", "2.1").level(2));
    let actual = toc.render_epub();
    let expected = "    <navPoint id=\"navPoint-1\">
      <navLabel>
       <text>1.1</text>
      </navLabel>
      <content src=\"#1.1\"/>
    </navPoint>
    <navPoint id=\"navPoint-2\">
      <navLabel>
       <text>2</text>
      </navLabel>
      <content src=\"#2\"/>
      <navPoint id=\"navPoint-3\">
        <navLabel>
         <text>2.1</text>
        </navLabel>
        <content src=\"#2.1\"/>
      </navPoint>
    </navPoint>";
    assert_eq!(&actual, expected);
}

#[test]
fn toc_epub_title_escaped() {
    let mut toc = Toc::new();
    toc.add(TocElement::new("#1", "D&D"));
    let actual = toc.render_epub();
    let expected = "    <navPoint id=\"navPoint-1\">
      <navLabel>
       <text>D&D</text>
      </navLabel>
      <content src=\"#1\"/>
    </navPoint>";
    assert_eq!(&actual, expected);
}
<|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"]

//! 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 following:
//!
//! ```no_run
//! extern crate sysfs_gpio;
//!
//! use sysfs_gpio::{Direction, Pin};
//! use std::thread::sleep_ms;
//!
//! fn main() {
//!     let my_led = Pin::new(127); // number depends on chip, etc.
//!     my_led.with_exported(|| {
//!         loop {
//!             my_led.set_value(0).unwrap();
//!             sleep_ms(200);
//!             my_led.set_value(1).unwrap();
//!             sleep_ms(200);
//!         }
//!     }).unwrap();
//! }
//! ```

extern crate nix;

use nix::sys::epoll::*;
use nix::unistd::close;

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

pub struct Pin {
    pin_num : u64,
}

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

#[derive(Clone,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) },
    });
}

fn from_nix_error(err: ::nix::Error) -> io::Error {
    io::Error::from_raw_os_error(err.errno() as i32)
}

/// Flush up to max bytes from the provided files input buffer
///
/// Typically, one would just use seek() for this sort of thing,
/// but for certain files (e.g. in sysfs), you need to actually
/// read it.
fn flush_input_from_file(dev_file: &mut File, max : usize) -> io::Result<usize> {
    let mut s = String::with_capacity(max);
    dev_file.read_to_string(&mut s)
}

/// Get the pin value from the provided file
fn get_value_from_file(dev_file: &mut File) -> io::Result<u8> {
    let mut s = String::with_capacity(10);
    try!(dev_file.seek(SeekFrom::Start(0)));
    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")),
    }
}

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(())
    }

    fn read_from_device_file(&self, dev_file_name: &str) -> io::Result<String> {
        let gpio_path = format!("/sys/class/gpio/gpio{}/{}", self.pin_num, dev_file_name);
        let mut dev_file = try!(File::create(&gpio_path));
        let mut s = String::new();
        if let Err(err) = dev_file.read_to_string(&mut s) {
            Err(err)
        } else {
            Ok(s)
        }
    }

    /// Create a new Pin with the provided `pin_num`
    ///
    /// This function does not export the provided pin_num.
    pub fn new(pin_num : u64) -> Pin {
        Pin {
            pin_num: pin_num,
        }
    }

    /// Run a closure with the GPIO exported
    ///
    /// Prior to the provided closure being executed, the GPIO
    /// will be exported.  After the closure execution is complete,
    /// the GPIO will be unexported.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use sysfs_gpio::{Pin, Direction};
    ///
    /// let gpio = Pin::new(24);
    /// let res = gpio.with_exported(|| {
    ///     println!("At this point, the Pin is exported");
    ///     try!(gpio.set_direction(Direction::Low));
    ///     try!(gpio.set_value(1));
    ///     // ...
    ///     Ok(())
    /// });
    /// ```
    #[inline]
    pub fn with_exported<F: FnOnce() -> io::Result<()>>(&self, closure : F) -> io::Result<()> {
        try!(self.export());
        match closure() {
            Ok(()) => { try!(self.unexport()); Ok(()) },
            Err(err) => { try!(self.unexport()); Err(err) },
        }
    }

    /// 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
    /// ```no_run
    /// use sysfs_gpio::Pin;
    ///
    /// let gpio = Pin::new(24);
    /// match gpio.export() {
    ///     Ok(()) => println!("Gpio {} exported!", gpio.get_pin()),
    ///     Err(err) => println!("Gpio {} could not be exported: {}", gpio.get_pin(), err),
    /// }
    /// ```
    pub fn export(&self) -> io::Result<()> {
        if let Err(_) = fs::metadata(&format!("/sys/class/gpio/gpio{}", self.pin_num)) {
            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<()> {
        if let Ok(_) = fs::metadata(&format!("/sys/class/gpio/gpio{}", self.pin_num)) {
            let mut unexport_file = try!(File::create("/sys/class/gpio/unexport"));
            try!(unexport_file.write_all(format!("{}", self.pin_num).as_bytes()));
        }
        Ok(())
    }

    /// Get the pin number for the Pin
    pub fn get_pin(&self) -> u64 {
        self.pin_num
    }

    /// Get the direction of the Pin
    pub fn get_direction(&self) -> io::Result<Direction> {
        match self.read_from_device_file("direction") {
            Ok(s) => {
                match s.trim() {
                    "in" => Ok(Direction::In),
                    "out" => Ok(Direction::Out),
                    "high" => Ok(Direction::High),
                    "low" => Ok(Direction::Low),
                    other => Err(Error::new(ErrorKind::Other,
                                            format!("Unexpected direction file contents {}", other))),
                }
            }
            Err(e) => Err(e)
        }
    }

    /// 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> {
        match self.read_from_device_file("value") {
            Ok(s) => {
                match s.trim() {
                    "1" => Ok(1),
                    "0" => Ok(0),
                    other => Err(Error::new(ErrorKind::Other,
                                            format!("Unexpected value file contents {}", other))),
                }
            }
            Err(e) => Err(e)
        }
    }

    /// 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 = match value {
            0 => "0",
            _ => "1",
        };
        self.write_to_device_file("value", val)
    }

    /// Get the currently configured edge for this pin
    ///
    /// This value will only be present if the Pin allows
    /// for interrupts.
    pub fn get_edge(&self) -> io::Result<Edge> {
        match self.read_from_device_file("edge") {
            Ok(s) => {
                match s.trim() {
                    "none" => Ok(Edge::NoInterrupt),
                    "rising" => Ok(Edge::RisingEdge),
                    "falling" => Ok(Edge::FallingEdge),
                    "both" => Ok(Edge::BothEdges),
                    other => Err(Error::new(ErrorKind::Other, format!("Unexpected edge file contents {}", other))),
                }
            }
            Err(e) => Err(e)
        }
    }

    /// Set the edge on which this GPIO will trigger when polled
    ///
    /// The configured edge determines what changes to the Pin will
    /// result in `poll()` returning.  This call will return an Error
    /// if the pin does not allow interrupts.
    pub fn set_edge(&self, edge: Edge) -> io::Result<()> {
        self.write_to_device_file("edge", match edge {
            Edge::NoInterrupt => "none",
            Edge::RisingEdge => "rising",
            Edge::FallingEdge => "falling",
            Edge::BothEdges => "both",
        })
    }

    /// Get a PinPoller object for this pin
    ///
    /// This pin poller object will register an interrupt with the
    /// kernel and allow you to poll() on it and receive notifications
    /// that an interrupt has occured with minimal delay.
    pub fn get_poller(&self) -> io::Result<PinPoller> {
        PinPoller::new(self.pin_num)
    }
}

pub struct PinPoller {
    pin_num : u64,
    epoll_fd : RawFd,
    devfile : File,
}

impl PinPoller {

    /// Get the pin associated with this PinPoller
    ///
    /// Note that this will be a new Pin object with the
    /// proper pin number.
    pub fn get_pin(&self) -> Pin {
        Pin::new(self.pin_num)
    }

    /// Create a new PinPoller for the provided pin number
    pub fn new(pin_num : u64) -> io::Result<PinPoller> {
        let devfile : File = try!(File::open(&format!("/sys/class/gpio/gpio{}/value", pin_num)));
        let devfile_fd = devfile.as_raw_fd();
        let epoll_fd = try!(epoll_create().map_err(from_nix_error));
        let events = EPOLLPRI | EPOLLET;
        let info = EpollEvent {
            events: events,
            data: 0u64,
        };

        match epoll_ctl(epoll_fd, EpollOp::EpollCtlAdd, devfile_fd, &info) {
            Ok(_) => {
                Ok(PinPoller {
                    pin_num: pin_num,
                    devfile: devfile,
                    epoll_fd: epoll_fd,
                })
            },
            Err(err) => {
                let _ = close(epoll_fd); // cleanup
                Err(from_nix_error(err))
            }
        }
    }

    /// Block until an interrupt occurs
    ///
    /// This call will block until an interrupt occurs.  The types
    /// of interrupts which may result in this call returning
    /// may be configured by calling `set_edge()` prior to
    /// making this call.  This call makes use of epoll under the
    /// covers.  If it is desirable to poll on multiple GPIOs or
    /// other event source, you will need to implement that logic
    /// yourself.
    ///
    /// This function will return Some(value) of the pin if a change is
    /// detected or None if a timeout occurs.  Note that the value provided
    /// is the value of the pin as soon as we get to handling the interrupt
    /// in userspace.  Each time this function returns with a value, a change
    /// has occurred, but you could end up reading the same value multiple
    /// times as the value has changed back between when the interrupt
    /// occurred and the current time.
    pub fn poll(&mut self, timeout_ms: isize) -> io::Result<Option<u8>> {
        try!(flush_input_from_file(&mut self.devfile, 255));
        let dummy_event = EpollEvent { events: EPOLLPRI | EPOLLET, data: 0u64};
        let mut events: [EpollEvent; 1] = [ dummy_event ];
        let cnt = try!(epoll_wait(self.epoll_fd, &mut events, timeout_ms).map_err(from_nix_error));
        Ok(match cnt {
            0 => None, // timeout
            _ => Some(try!(get_value_from_file(&mut self.devfile))),
        })
    }
}

impl Drop for PinPoller {
    fn drop(&mut self) {
        // we implement drop to close the underlying epoll fd as
        // it does not implement drop itself.  This is similar to
        // how mio works
        close(self.epoll_fd).unwrap();  // panic! if close files
    }
}
<commit_msg>Minor simplification to remove branching<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"]

//! 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 following:
//!
//! ```no_run
//! extern crate sysfs_gpio;
//!
//! use sysfs_gpio::{Direction, Pin};
//! use std::thread::sleep_ms;
//!
//! fn main() {
//!     let my_led = Pin::new(127); // number depends on chip, etc.
//!     my_led.with_exported(|| {
//!         loop {
//!             my_led.set_value(0).unwrap();
//!             sleep_ms(200);
//!             my_led.set_value(1).unwrap();
//!             sleep_ms(200);
//!         }
//!     }).unwrap();
//! }
//! ```

extern crate nix;

use nix::sys::epoll::*;
use nix::unistd::close;

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

pub struct Pin {
    pin_num : u64,
}

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

#[derive(Clone,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) },
    });
}

fn from_nix_error(err: ::nix::Error) -> io::Error {
    io::Error::from_raw_os_error(err.errno() as i32)
}

/// Flush up to max bytes from the provided files input buffer
///
/// Typically, one would just use seek() for this sort of thing,
/// but for certain files (e.g. in sysfs), you need to actually
/// read it.
fn flush_input_from_file(dev_file: &mut File, max : usize) -> io::Result<usize> {
    let mut s = String::with_capacity(max);
    dev_file.read_to_string(&mut s)
}

/// Get the pin value from the provided file
fn get_value_from_file(dev_file: &mut File) -> io::Result<u8> {
    let mut s = String::with_capacity(10);
    try!(dev_file.seek(SeekFrom::Start(0)));
    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")),
    }
}

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(())
    }

    fn read_from_device_file(&self, dev_file_name: &str) -> io::Result<String> {
        let gpio_path = format!("/sys/class/gpio/gpio{}/{}", self.pin_num, dev_file_name);
        let mut dev_file = try!(File::create(&gpio_path));
        let mut s = String::new();
        try!(dev_file.read_to_string(&mut s));
        Ok(s)
    }

    /// Create a new Pin with the provided `pin_num`
    ///
    /// This function does not export the provided pin_num.
    pub fn new(pin_num : u64) -> Pin {
        Pin {
            pin_num: pin_num,
        }
    }

    /// Run a closure with the GPIO exported
    ///
    /// Prior to the provided closure being executed, the GPIO
    /// will be exported.  After the closure execution is complete,
    /// the GPIO will be unexported.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use sysfs_gpio::{Pin, Direction};
    ///
    /// let gpio = Pin::new(24);
    /// let res = gpio.with_exported(|| {
    ///     println!("At this point, the Pin is exported");
    ///     try!(gpio.set_direction(Direction::Low));
    ///     try!(gpio.set_value(1));
    ///     // ...
    ///     Ok(())
    /// });
    /// ```
    #[inline]
    pub fn with_exported<F: FnOnce() -> io::Result<()>>(&self, closure : F) -> io::Result<()> {
        try!(self.export());
        match closure() {
            Ok(()) => { try!(self.unexport()); Ok(()) },
            Err(err) => { try!(self.unexport()); Err(err) },
        }
    }

    /// 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
    /// ```no_run
    /// use sysfs_gpio::Pin;
    ///
    /// let gpio = Pin::new(24);
    /// match gpio.export() {
    ///     Ok(()) => println!("Gpio {} exported!", gpio.get_pin()),
    ///     Err(err) => println!("Gpio {} could not be exported: {}", gpio.get_pin(), err),
    /// }
    /// ```
    pub fn export(&self) -> io::Result<()> {
        if let Err(_) = fs::metadata(&format!("/sys/class/gpio/gpio{}", self.pin_num)) {
            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<()> {
        if let Ok(_) = fs::metadata(&format!("/sys/class/gpio/gpio{}", self.pin_num)) {
            let mut unexport_file = try!(File::create("/sys/class/gpio/unexport"));
            try!(unexport_file.write_all(format!("{}", self.pin_num).as_bytes()));
        }
        Ok(())
    }

    /// Get the pin number for the Pin
    pub fn get_pin(&self) -> u64 {
        self.pin_num
    }

    /// Get the direction of the Pin
    pub fn get_direction(&self) -> io::Result<Direction> {
        match self.read_from_device_file("direction") {
            Ok(s) => {
                match s.trim() {
                    "in" => Ok(Direction::In),
                    "out" => Ok(Direction::Out),
                    "high" => Ok(Direction::High),
                    "low" => Ok(Direction::Low),
                    other => Err(Error::new(ErrorKind::Other,
                                            format!("Unexpected direction file contents {}", other))),
                }
            }
            Err(e) => Err(e)
        }
    }

    /// 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> {
        match self.read_from_device_file("value") {
            Ok(s) => {
                match s.trim() {
                    "1" => Ok(1),
                    "0" => Ok(0),
                    other => Err(Error::new(ErrorKind::Other,
                                            format!("Unexpected value file contents {}", other))),
                }
            }
            Err(e) => Err(e)
        }
    }

    /// 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 = match value {
            0 => "0",
            _ => "1",
        };
        self.write_to_device_file("value", val)
    }

    /// Get the currently configured edge for this pin
    ///
    /// This value will only be present if the Pin allows
    /// for interrupts.
    pub fn get_edge(&self) -> io::Result<Edge> {
        match self.read_from_device_file("edge") {
            Ok(s) => {
                match s.trim() {
                    "none" => Ok(Edge::NoInterrupt),
                    "rising" => Ok(Edge::RisingEdge),
                    "falling" => Ok(Edge::FallingEdge),
                    "both" => Ok(Edge::BothEdges),
                    other => Err(Error::new(ErrorKind::Other, format!("Unexpected edge file contents {}", other))),
                }
            }
            Err(e) => Err(e)
        }
    }

    /// Set the edge on which this GPIO will trigger when polled
    ///
    /// The configured edge determines what changes to the Pin will
    /// result in `poll()` returning.  This call will return an Error
    /// if the pin does not allow interrupts.
    pub fn set_edge(&self, edge: Edge) -> io::Result<()> {
        self.write_to_device_file("edge", match edge {
            Edge::NoInterrupt => "none",
            Edge::RisingEdge => "rising",
            Edge::FallingEdge => "falling",
            Edge::BothEdges => "both",
        })
    }

    /// Get a PinPoller object for this pin
    ///
    /// This pin poller object will register an interrupt with the
    /// kernel and allow you to poll() on it and receive notifications
    /// that an interrupt has occured with minimal delay.
    pub fn get_poller(&self) -> io::Result<PinPoller> {
        PinPoller::new(self.pin_num)
    }
}

pub struct PinPoller {
    pin_num : u64,
    epoll_fd : RawFd,
    devfile : File,
}

impl PinPoller {

    /// Get the pin associated with this PinPoller
    ///
    /// Note that this will be a new Pin object with the
    /// proper pin number.
    pub fn get_pin(&self) -> Pin {
        Pin::new(self.pin_num)
    }

    /// Create a new PinPoller for the provided pin number
    pub fn new(pin_num : u64) -> io::Result<PinPoller> {
        let devfile : File = try!(File::open(&format!("/sys/class/gpio/gpio{}/value", pin_num)));
        let devfile_fd = devfile.as_raw_fd();
        let epoll_fd = try!(epoll_create().map_err(from_nix_error));
        let events = EPOLLPRI | EPOLLET;
        let info = EpollEvent {
            events: events,
            data: 0u64,
        };

        match epoll_ctl(epoll_fd, EpollOp::EpollCtlAdd, devfile_fd, &info) {
            Ok(_) => {
                Ok(PinPoller {
                    pin_num: pin_num,
                    devfile: devfile,
                    epoll_fd: epoll_fd,
                })
            },
            Err(err) => {
                let _ = close(epoll_fd); // cleanup
                Err(from_nix_error(err))
            }
        }
    }

    /// Block until an interrupt occurs
    ///
    /// This call will block until an interrupt occurs.  The types
    /// of interrupts which may result in this call returning
    /// may be configured by calling `set_edge()` prior to
    /// making this call.  This call makes use of epoll under the
    /// covers.  If it is desirable to poll on multiple GPIOs or
    /// other event source, you will need to implement that logic
    /// yourself.
    ///
    /// This function will return Some(value) of the pin if a change is
    /// detected or None if a timeout occurs.  Note that the value provided
    /// is the value of the pin as soon as we get to handling the interrupt
    /// in userspace.  Each time this function returns with a value, a change
    /// has occurred, but you could end up reading the same value multiple
    /// times as the value has changed back between when the interrupt
    /// occurred and the current time.
    pub fn poll(&mut self, timeout_ms: isize) -> io::Result<Option<u8>> {
        try!(flush_input_from_file(&mut self.devfile, 255));
        let dummy_event = EpollEvent { events: EPOLLPRI | EPOLLET, data: 0u64};
        let mut events: [EpollEvent; 1] = [ dummy_event ];
        let cnt = try!(epoll_wait(self.epoll_fd, &mut events, timeout_ms).map_err(from_nix_error));
        Ok(match cnt {
            0 => None, // timeout
            _ => Some(try!(get_value_from_file(&mut self.devfile))),
        })
    }
}

impl Drop for PinPoller {
    fn drop(&mut self) {
        // we implement drop to close the underlying epoll fd as
        // it does not implement drop itself.  This is similar to
        // how mio works
        close(self.epoll_fd).unwrap();  // panic! if close files
    }
}
<|endoftext|>


<commit_before>#![crate_name = "rustless"]
#![comment = "REST-like API micro-framework for Rust"]
#![license = "MIT"]
#![crate_type = "rlib"]
#![deny(warnings)]
#![deny(bad_style)]
#![feature(macro_rules, phase, tuple_indexing)]
#[phase(plugin)]

extern crate regex_macros;
extern crate regex;
extern crate hyper;
extern crate serialize;
extern crate url;
extern crate anymap;
extern crate error;
extern crate cookie;

extern crate collections;
extern crate valico;
extern crate queryst;

pub use common::{Cookies, Static};
pub use valico::Builder as Valico;
pub use server::{Server, Request, SimpleRequest, Response};
pub use middleware::{Application, HandleResult, HandleSuccessResult};
pub use framework::{
    Endpoint, Client, Api, Namespace, Nesting, Media,
    PathVersioning, AcceptHeaderVersioning, ParamVersioning
};

#[macro_export]
macro_rules! edp_handler {
    ($edp:ident, |$client:ident, $params:ident| $blk:block) => ({
        #[allow(dead_code)]
        fn endpoint_handler<'a>($client: Client<'a>, $params: &JsonObject) -> HandleResult<Client<'a>> {
            $blk
        }

        $edp.handle(endpoint_handler)
    })
}

#[macro_export]
macro_rules! callback {
    (|$client:ident, $params:ident| $blk:block) => ({
        fn callback<'a>($client: &mut Client<'a>, $params: &JsonObject) -> HandleSuccessResult {
            $blk
        }

        callback
    })
}

#[macro_export]
macro_rules! format_error (
    ($api:ident, $t:ty, |$err:ident, $media:ident| $blk:block) => ({
        #[allow(dead_code)]
        fn error_formatter(err: &Box<Error>, $media: &Media) -> Option<Response> {
            match err.downcast::<$t>() {
                Some($err) => {
                    $blk
                },
                None => None
            }
        }

        $api.error_formatter(error_formatter);
    });
    ($api:ident, all, |$err:ident, $media:ident| $blk:block) => ({
        #[allow(dead_code)]
        fn error_formatter($err: &Box<Error>, $media: &Media) -> Option<Response> {
            $blk
        }

        $api.error_formatter(error_formatter);
    });
)

pub trait Extensible {
    fn ext(&self) -> &::anymap::AnyMap;
    fn ext_mut(&mut self) -> &mut ::anymap::AnyMap;
}

macro_rules! impl_extensible(
    ($t:ty) => (
        impl Extensible for $t {
            fn ext(&self) -> &::anymap::AnyMap { &self.ext }
            fn ext_mut(&mut self) -> &mut ::anymap::AnyMap { &mut self.ext }
        }
    )
)

pub mod errors;
pub mod server_backend;
mod middleware;
mod server;
pub mod framework;
pub mod common;<commit_msg>feat: make `Client` mutable in `endpoint_handler`<commit_after>#![crate_name = "rustless"]
#![comment = "REST-like API micro-framework for Rust"]
#![license = "MIT"]
#![crate_type = "rlib"]
#![deny(warnings)]
#![deny(bad_style)]
#![feature(macro_rules, phase, tuple_indexing)]
#[phase(plugin)]

extern crate regex_macros;
extern crate regex;
extern crate hyper;
extern crate serialize;
extern crate url;
extern crate anymap;
extern crate error;
extern crate cookie;

extern crate collections;
extern crate valico;
extern crate queryst;

pub use common::{Cookies, Static};
pub use valico::Builder as Valico;
pub use server::{Server, Request, SimpleRequest, Response};
pub use middleware::{Application, HandleResult, HandleSuccessResult};
pub use framework::{
    Endpoint, Client, Api, Namespace, Nesting, Media,
    PathVersioning, AcceptHeaderVersioning, ParamVersioning
};

#[macro_export]
macro_rules! edp_handler {
    ($edp:ident, |$client:ident, $params:ident| $blk:block) => ({
        #[allow(dead_code)]
        #[allow(unused_mut)]
        fn endpoint_handler<'a>(mut $client: Client<'a>, $params: &JsonObject) -> HandleResult<Client<'a>> {
            $blk
        }

        $edp.handle(endpoint_handler)
    })
}

#[macro_export]
macro_rules! callback {
    (|$client:ident, $params:ident| $blk:block) => ({
        fn callback<'a>($client: &mut Client<'a>, $params: &JsonObject) -> HandleSuccessResult {
            $blk
        }

        callback
    })
}

#[macro_export]
macro_rules! format_error (
    ($api:ident, $t:ty, |$err:ident, $media:ident| $blk:block) => ({
        #[allow(dead_code)]
        fn error_formatter(err: &Box<Error>, $media: &Media) -> Option<Response> {
            match err.downcast::<$t>() {
                Some($err) => {
                    $blk
                },
                None => None
            }
        }

        $api.error_formatter(error_formatter);
    });
    ($api:ident, all, |$err:ident, $media:ident| $blk:block) => ({
        #[allow(dead_code)]
        fn error_formatter($err: &Box<Error>, $media: &Media) -> Option<Response> {
            $blk
        }

        $api.error_formatter(error_formatter);
    });
)

pub trait Extensible {
    fn ext(&self) -> &::anymap::AnyMap;
    fn ext_mut(&mut self) -> &mut ::anymap::AnyMap;
}

macro_rules! impl_extensible(
    ($t:ty) => (
        impl Extensible for $t {
            fn ext(&self) -> &::anymap::AnyMap { &self.ext }
            fn ext_mut(&mut self) -> &mut ::anymap::AnyMap { &mut self.ext }
        }
    )
)

pub mod errors;
pub mod server_backend;
mod middleware;
mod server;
pub mod framework;
pub mod common;<|endoftext|>


<commit_before>extern crate num_cpus;
extern crate primal_sieve;

#[macro_use]
mod macros;
pub mod filter;
pub mod collection;
mod concurrent_help;

#[cfg(test)]
mod tests {
    use filter::{
        prime_filter,
        // prime_filter_section,
        old_prime_filter,
        prime_filter_section_sequentially,
    };
    extern crate time;
    extern crate num_cpus;
    use self::time::PreciseTime;
    #[test]
    fn test_prime_filter(){
        let n = 12345;
        let new_pf = prime_filter(n);
        let old_pf = old_prime_filter(n);
        for i in 0..n{
            assert_eq!(new_pf[i], old_pf[i], "Failed on number {}", i)
        }
    }
    use collection::{
        primes,
        primes_section,
        primes_concurrently,
        primes_section_sequentially,
    };
    #[test]
    fn test_prime_collection(){
        let some_primes = [ 2, 3, 5, 7, 11, 13,
                            17, 19, 23, 29, 31,
                            37, 41, 43, 47, 53,
                            59, 61, 67, 71, 73,
                            79, 83, 89, 97, 101,
                            103, 107, 109, 113, 127,
                            131, 137, 139, 149, 151,
                            157, 163, 167, 173, 179,
                            181, 191, 193, 197, 199];

        let test_primes: Vec<usize> = primes(200);
        for i in 0..test_primes.len(){
            assert_eq!(test_primes[i], some_primes[i], "Mismatch")
        };
    }
    #[test]
    fn test_prime_sec_collection(){
        let some_primes = [ 101,
                            103, 107, 109, 113, 127,
                            131, 137, 139, 149, 151,
                            157, 163, 167, 173, 179,
                            181, 191, 193, 197, 199];

        let test_primes: Vec<usize> = primes_section(100, 200);
        for i in 0..test_primes.len(){
            assert_eq!(test_primes[i], some_primes[i], "Mismatch")
        };
    }
    #[test]
    fn can_take_any_section_filter(){
        let some_primes = old_prime_filter(200);
        for min in 0..200{
            for max in (min+1)..200{
                for (i, is_prime) in prime_filter_section_sequentially(min, max).into_iter().enumerate(){
                    assert_eq!(some_primes[min+i], is_prime, "bad case from {} to {}", min, max);
                }
            }
        }
    }
    #[test]
    fn can_take_any_section(){
        let some_primes = old_prime_filter(200);
        for min in 0..200{
            for max in (min+1)..200{
                for prime in primes_section_sequentially(min, max).into_iter(){
                    assert!(some_primes[prime], "bad case from {} to {}: prime: {}", min, max, prime);
                }
            }
        }
    }
    #[test]
    fn count_primes(){
        let n = 100_000_000;
        let start = PreciseTime::now();
        let primes = primes(n);
        let end = PreciseTime::now();
        println!("{} seconds to find all primes less than {}!", start.to(end), n);
        println!("{} primes total!", primes.len());
        let total_primes = primes.len();
        assert_eq!(total_primes, 5761455);
    }
    #[test]
    fn count_primes_concurrently(){
        let threads = num_cpus::get();
        let n = 1_000_000_000;
        let start = PreciseTime::now();
        let primes = primes_concurrently(n, threads);
        let end = PreciseTime::now();
        println!("{} seconds to find all primes less than {}! (Threads: {})", start.to(end), n, threads);
        println!("{} primes total!", primes.len());
        let total_primes = primes.len();
        assert_eq!(total_primes, 50_847_534);
    }
    #[test]
    fn count_prime_section(){
        let min = 1_000_000;
        let max = 10_000_000;
        let primes = primes_section(min, max);
        let total_primes = primes.len();
        assert_eq!(total_primes, 586081);
    }
    #[test]
    fn count_primes_with_filter(){
        let n = 100_000_000;
        let start = PreciseTime::now();
        let primes = prime_filter(n);
        let end = PreciseTime::now();
        println!("{} seconds to generate a prime filter less than {}!", start.to(end), n);
        // println!("{} primes total!", primes.len());
        let total_primes = primes.iter().fold(0, |acc, &x| acc + (if x {1} else {0}));
        assert_eq!(total_primes, 5761455);
    }
    #[test]
    fn big_distant_section(){
        let min = 10000000000000000;
        let max = 10000000010000000;
        let start = PreciseTime::now();
        let primes = primes_section(min, max);
        let end = PreciseTime::now();
        println!("{} seconds to find big prime section!", start.to(end));
        let total_primes = primes.len();
        assert_eq!(total_primes, 271898);
    }
}
<commit_msg>Change the test back<commit_after>extern crate num_cpus;
extern crate primal_sieve;

#[macro_use]
mod macros;
pub mod filter;
pub mod collection;
mod concurrent_help;

#[cfg(test)]
mod tests {
    use filter::{
        prime_filter,
        // prime_filter_section,
        old_prime_filter,
        prime_filter_section_sequentially,
    };
    extern crate time;
    extern crate num_cpus;
    use self::time::PreciseTime;
    #[test]
    fn test_prime_filter(){
        let n = 12345;
        let new_pf = prime_filter(n);
        let old_pf = old_prime_filter(n);
        for i in 0..n{
            assert_eq!(new_pf[i], old_pf[i], "Failed on number {}", i)
        }
    }
    use collection::{
        primes,
        primes_section,
        primes_concurrently,
        primes_section_sequentially,
    };
    #[test]
    fn test_prime_collection(){
        let some_primes = [ 2, 3, 5, 7, 11, 13,
                            17, 19, 23, 29, 31,
                            37, 41, 43, 47, 53,
                            59, 61, 67, 71, 73,
                            79, 83, 89, 97, 101,
                            103, 107, 109, 113, 127,
                            131, 137, 139, 149, 151,
                            157, 163, 167, 173, 179,
                            181, 191, 193, 197, 199];

        let test_primes: Vec<usize> = primes(200);
        for i in 0..test_primes.len(){
            assert_eq!(test_primes[i], some_primes[i], "Mismatch")
        };
    }
    #[test]
    fn test_prime_sec_collection(){
        let some_primes = [ 101,
                            103, 107, 109, 113, 127,
                            131, 137, 139, 149, 151,
                            157, 163, 167, 173, 179,
                            181, 191, 193, 197, 199];

        let test_primes: Vec<usize> = primes_section(100, 200);
        for i in 0..test_primes.len(){
            assert_eq!(test_primes[i], some_primes[i], "Mismatch")
        };
    }
    #[test]
    fn can_take_any_section_filter(){
        let some_primes = old_prime_filter(200);
        for min in 0..200{
            for max in (min+1)..200{
                for (i, is_prime) in prime_filter_section_sequentially(min, max).into_iter().enumerate(){
                    assert_eq!(some_primes[min+i], is_prime, "bad case from {} to {}", min, max);
                }
            }
        }
    }
    #[test]
    fn can_take_any_section(){
        let some_primes = old_prime_filter(200);
        for min in 0..200{
            for max in (min+1)..200{
                for prime in primes_section_sequentially(min, max).into_iter(){
                    assert!(some_primes[prime], "bad case from {} to {}: prime: {}", min, max, prime);
                }
            }
        }
    }
    #[test]
    fn count_primes(){
        let n = 100_000_000;
        let start = PreciseTime::now();
        let primes = primes(n);
        let end = PreciseTime::now();
        println!("{} seconds to find all primes less than {}!", start.to(end), n);
        println!("{} primes total!", primes.len());
        let total_primes = primes.len();
        assert_eq!(total_primes, 5761455);
    }
    #[test]
    fn count_primes_concurrently(){
        let threads = num_cpus::get();
        let n = 1_000_000_000;
        let start = PreciseTime::now();
        let primes = primes_concurrently(n, threads);
        let end = PreciseTime::now();
        println!("{} seconds to find all primes less than {}! (Threads: {})", start.to(end), n, threads);
        println!("{} primes total!", primes.len());
        let total_primes = primes.len();
        assert_eq!(total_primes, 50_847_534);
    }
    #[test]
    fn count_prime_section(){
        let min = 1_000_000;
        let max = 10_000_000;
        let primes = primes_section(min, max);
        let total_primes = primes.len();
        assert_eq!(total_primes, 586081);
    }
    #[test]
    fn count_primes_with_filter(){
        let n = 100_000_000;
        let start = PreciseTime::now();
        let primes = prime_filter(n);
        let end = PreciseTime::now();
        println!("{} seconds to generate a prime filter less than {}!", start.to(end), n);
        // println!("{} primes total!", primes.len());
        let total_primes = primes.iter().fold(0, |acc, &x| acc + (if x {1} else {0}));
        assert_eq!(total_primes, 5761455);
    }
    #[test]
    fn big_distant_section(){
        let min = 10000000000000000;
        let max = 10000000100000000;
        let start = PreciseTime::now();
        let primes = primes_section(min, max);
        let end = PreciseTime::now();
        println!("{} seconds to find big prime section!", start.to(end));
        let total_primes = primes.len();
        assert_eq!(total_primes, 2714904);
    }
}
<|endoftext|>