<commit_before>extern crate md5;

pub fn puzzle(door_id: &str) -> String {
    let mut answer = String::new();
    let mut index = 0;

    for _ in 0..9 {
        let (new_index, next_char) = next_interesting_md5(door_id, index);
        index = new_index + 1;
        answer.push(next_char);
    }
    answer
}

pub fn next_interesting_md5(door_id: &str, mut index: u32) -> (u32, char) {
    loop {
        let candidate = format!("{}{}", door_id, index);
        let digest = md5::compute(candidate);
        if digest.starts_with("00000") {
            return (index, digest.char_at(5))
        } else {
            index += 1;
        }
    }

    (0, 'a')
}

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

}
<commit_msg>Compiles, but I left an unreachable return val in there<commit_after>extern crate md5;

pub fn puzzle(door_id: &str) -> String {
    let mut answer = String::new();
    let mut index = 0;

    for _ in 0..9 {
        let (new_index, next_char) = next_interesting_md5(door_id, index);
        index = new_index + 1;
        answer.push(next_char);
    }
    answer
}

pub fn next_interesting_md5(door_id: &str, mut index: u32) -> (u32, char) {
    loop {
        let candidate = format!("{}{}", door_id, index);

        let digest = String::from_utf8(
            md5::compute(candidate.as_bytes()).into_iter().cloned().collect()
        ).expect("creating string failed");

        if digest.starts_with("00000") {
            return (index, digest.chars().nth(5).expect("no 5th char"))
        } else {
            index += 1;
        }
    }

    (0, 'a')
}

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

}
<|endoftext|>


<commit_before>// Copyright 2015 Corey Farwell
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate xml;

use std::ascii::AsciiExt;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

trait ElementUtils {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str);
    fn tag_with_optional_text(&mut self, child_name: &'static str, child_body: &Option<String>);
}

impl ElementUtils for Element {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str) {
        self.tag(elem_with_text(child_name, child_body));
    }

    fn tag_with_optional_text(&mut self, child_name: &'static str, child_body: &Option<String>) {
        if let Some(ref c) = *child_body {
            self.tag_with_text(child_name, &c);
        }
    }
}

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name.to_string(), None, vec![]);
    elem.text(chars.to_string());
    elem
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss".to_string(), None, vec![("version".to_string(), None, "2.0".to_string())]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    pub fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    pub fn from_read(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        if let Err(..) = reader.read_to_string(&mut rss_string) {
            return Err("Error reading string from reader");
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            if let Some(Ok(element)) = builder.handle_event(event) {
                return ViaXml::from_xml(element);
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
/// use std::default::Default;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
///     ..Default::default()
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    pub language: Option<String>,
    pub copyright: Option<String>,
    pub managing_editor: Option<String>,
    pub web_master: Option<String>,
    pub pub_date: Option<String>,
    pub last_build_date: Option<String>,
    pub categories: Vec<Category>,
    pub generator: Option<String>,
    pub docs: Option<String>,
    // pub cloud:
    pub ttl: Option<String>,  // TODO: change this to Option<i32>?
    pub image: Option<String>,
    pub rating: Option<String>,
    // pub text_input:
    pub skip_hours: Option<String>,
    pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel".to_string(), None, vec![]);

        channel.tag_with_text("title", &self.title);
        channel.tag_with_text("link", &self.link);
        channel.tag_with_text("description", &self.description);

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel.tag_with_optional_text("language", &self.language);
        channel.tag_with_optional_text("copyright", &self.copyright);
        channel.tag_with_optional_text("managingEditor", &self.managing_editor);
        channel.tag_with_optional_text("webMaster", &self.web_master);
        channel.tag_with_optional_text("pubDate", &self.pub_date);
        channel.tag_with_optional_text("lastBuildDate", &self.last_build_date);
        channel.tag_with_optional_text("generator", &self.generator);
        channel.tag_with_optional_text("docs", &self.docs);
        channel.tag_with_optional_text("ttl", &self.ttl);
        channel.tag_with_optional_text("image", &self.image);
        channel.tag_with_optional_text("rating", &self.rating);
        channel.tag_with_optional_text("skipHours", &self.skip_hours);
        channel.tag_with_optional_text("skipDays", &self.skip_days);

        for category in &self.categories {
            channel.tag(category.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = match element.get_child("title", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        };

        let link = match element.get_child("link", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        };

        let description = match element.get_child("description", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        };

        let items = element.get_children("item", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        let language = element.get_child("language", None).map(Element::content_str);
        let copyright = element.get_child("copyright", None).map(Element::content_str);
        let managing_editor = element.get_child("managing_editor", None).map(Element::content_str);
        let web_master = element.get_child("managing_editor", None).map(Element::content_str);
        let pub_date = element.get_child("pub_date", None).map(Element::content_str);
        let last_build_date = element.get_child("last_build_date", None).map(Element::content_str);

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        let generator = element.get_child("generator", None).map(Element::content_str);
        let docs = element.get_child("docs", None).map(Element::content_str);
        let ttl = element.get_child("ttl", None).map(Element::content_str);
        let image = element.get_child("image", None).map(Element::content_str);
        let rating = element.get_child("rating", None).map(Element::content_str);
        let skip_hours = element.get_child("skip_hours", None).map(Element::content_str);
        let skip_days = element.get_child("skip_days", None).map(Element::content_str);

        Ok(Channel {
            title: title,
            link: link,
            description: description,
            items: items,
            language: language,
            copyright: copyright,
            managing_editor: managing_editor,
            web_master: web_master,
            pub_date: pub_date,
            last_build_date: last_build_date,
            categories: categories,
            generator: generator,
            docs: docs,
            ttl: ttl,
            image: image,
            rating: rating,
            skip_hours: skip_hours,
            skip_days: skip_days,
        })
    }
}

/// Item
///
/// [RSS 2.0 Specification § Item]
/// (http://cyber.law.harvard.edu/rss/rss.html#hrelementsOfLtitemgt)
#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    pub author: Option<String>,
    pub categories: Vec<Category>,
    pub comments: Option<String>,
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item".to_string(), None, vec![]);

        item.tag_with_optional_text("title", &self.title);
        item.tag_with_optional_text("link", &self.link);
        item.tag_with_optional_text("description", &self.description);
        item.tag_with_optional_text("author", &self.author);
        item.tag_with_optional_text("comments", &self.comments);

        for category in &self.categories {
            item.tag(category.to_xml());
        }

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = element.get_child("title", None).map(Element::content_str);
        let link = element.get_child("link", None).map(Element::content_str);
        let description = element.get_child("description", None).map(Element::content_str);
        let author = element.get_child("author", None).map(Element::content_str);
        let comments = element.get_child("comments", None).map(Element::content_str);

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Item {
            title: title,
            link: link,
            description: description,
            categories: categories,
            author: author,
            comments: comments,
        })
    }
}

/// Category
///
/// [RSS 2.0 Specification § Category]
/// (http://cyber.law.harvard.edu/rss/rss.html#ltcategorygtSubelementOfLtitemgt)
#[derive(Default)]
pub struct Category {
    pub domain: Option<String>,
    pub value: String,
}

impl ViaXml for Category {
    fn to_xml(&self) -> Element {
        let mut category = match self.domain {
            Some(ref d) => Element::new("category".to_string(), None, vec![("domain".to_string(), None, d.clone())]),
            None => Element::new("category".to_string(), None, vec![]),
        };
        category.text(self.value.clone());
        category
    }

    fn from_xml(elem: Element) -> Result<Self, &'static str> {
        let domain = elem.get_attribute("domain", None).map(|s| s.to_string());
        let value = elem.content_str();

        Ok(Category {
            domain: domain,
            value: value,
        })
    }
}

#[cfg(test)]
mod test {
    use std::default::Default;
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
            ..Default::default()
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
            ..Default::default()
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let rss = Rss::from_read(&mut file).unwrap();
        assert!(rss.to_string().len() > 0);
    }

    #[test]
    #[should_panic]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_from_read_one_channel_no_properties() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<commit_msg>Rename constructor<commit_after>// Copyright 2015 Corey Farwell
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate xml;

use std::ascii::AsciiExt;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

trait ElementUtils {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str);
    fn tag_with_optional_text(&mut self, child_name: &'static str, child_body: &Option<String>);
}

impl ElementUtils for Element {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str) {
        self.tag(elem_with_text(child_name, child_body));
    }

    fn tag_with_optional_text(&mut self, child_name: &'static str, child_body: &Option<String>) {
        if let Some(ref c) = *child_body {
            self.tag_with_text(child_name, &c);
        }
    }
}

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name.to_string(), None, vec![]);
    elem.text(chars.to_string());
    elem
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss".to_string(), None, vec![("version".to_string(), None, "2.0".to_string())]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    pub fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    pub fn from_reader(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        if let Err(..) = reader.read_to_string(&mut rss_string) {
            return Err("Error reading string from reader");
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            if let Some(Ok(element)) = builder.handle_event(event) {
                return ViaXml::from_xml(element);
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
/// use std::default::Default;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
///     ..Default::default()
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    pub language: Option<String>,
    pub copyright: Option<String>,
    pub managing_editor: Option<String>,
    pub web_master: Option<String>,
    pub pub_date: Option<String>,
    pub last_build_date: Option<String>,
    pub categories: Vec<Category>,
    pub generator: Option<String>,
    pub docs: Option<String>,
    // pub cloud:
    pub ttl: Option<String>,  // TODO: change this to Option<i32>?
    pub image: Option<String>,
    pub rating: Option<String>,
    // pub text_input:
    pub skip_hours: Option<String>,
    pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel".to_string(), None, vec![]);

        channel.tag_with_text("title", &self.title);
        channel.tag_with_text("link", &self.link);
        channel.tag_with_text("description", &self.description);

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel.tag_with_optional_text("language", &self.language);
        channel.tag_with_optional_text("copyright", &self.copyright);
        channel.tag_with_optional_text("managingEditor", &self.managing_editor);
        channel.tag_with_optional_text("webMaster", &self.web_master);
        channel.tag_with_optional_text("pubDate", &self.pub_date);
        channel.tag_with_optional_text("lastBuildDate", &self.last_build_date);
        channel.tag_with_optional_text("generator", &self.generator);
        channel.tag_with_optional_text("docs", &self.docs);
        channel.tag_with_optional_text("ttl", &self.ttl);
        channel.tag_with_optional_text("image", &self.image);
        channel.tag_with_optional_text("rating", &self.rating);
        channel.tag_with_optional_text("skipHours", &self.skip_hours);
        channel.tag_with_optional_text("skipDays", &self.skip_days);

        for category in &self.categories {
            channel.tag(category.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = match element.get_child("title", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        };

        let link = match element.get_child("link", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        };

        let description = match element.get_child("description", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        };

        let items = element.get_children("item", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        let language = element.get_child("language", None).map(Element::content_str);
        let copyright = element.get_child("copyright", None).map(Element::content_str);
        let managing_editor = element.get_child("managing_editor", None).map(Element::content_str);
        let web_master = element.get_child("managing_editor", None).map(Element::content_str);
        let pub_date = element.get_child("pub_date", None).map(Element::content_str);
        let last_build_date = element.get_child("last_build_date", None).map(Element::content_str);

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        let generator = element.get_child("generator", None).map(Element::content_str);
        let docs = element.get_child("docs", None).map(Element::content_str);
        let ttl = element.get_child("ttl", None).map(Element::content_str);
        let image = element.get_child("image", None).map(Element::content_str);
        let rating = element.get_child("rating", None).map(Element::content_str);
        let skip_hours = element.get_child("skip_hours", None).map(Element::content_str);
        let skip_days = element.get_child("skip_days", None).map(Element::content_str);

        Ok(Channel {
            title: title,
            link: link,
            description: description,
            items: items,
            language: language,
            copyright: copyright,
            managing_editor: managing_editor,
            web_master: web_master,
            pub_date: pub_date,
            last_build_date: last_build_date,
            categories: categories,
            generator: generator,
            docs: docs,
            ttl: ttl,
            image: image,
            rating: rating,
            skip_hours: skip_hours,
            skip_days: skip_days,
        })
    }
}

/// Item
///
/// [RSS 2.0 Specification § Item]
/// (http://cyber.law.harvard.edu/rss/rss.html#hrelementsOfLtitemgt)
#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    pub author: Option<String>,
    pub categories: Vec<Category>,
    pub comments: Option<String>,
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item".to_string(), None, vec![]);

        item.tag_with_optional_text("title", &self.title);
        item.tag_with_optional_text("link", &self.link);
        item.tag_with_optional_text("description", &self.description);
        item.tag_with_optional_text("author", &self.author);
        item.tag_with_optional_text("comments", &self.comments);

        for category in &self.categories {
            item.tag(category.to_xml());
        }

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = element.get_child("title", None).map(Element::content_str);
        let link = element.get_child("link", None).map(Element::content_str);
        let description = element.get_child("description", None).map(Element::content_str);
        let author = element.get_child("author", None).map(Element::content_str);
        let comments = element.get_child("comments", None).map(Element::content_str);

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Item {
            title: title,
            link: link,
            description: description,
            categories: categories,
            author: author,
            comments: comments,
        })
    }
}

/// Category
///
/// [RSS 2.0 Specification § Category]
/// (http://cyber.law.harvard.edu/rss/rss.html#ltcategorygtSubelementOfLtitemgt)
#[derive(Default)]
pub struct Category {
    pub domain: Option<String>,
    pub value: String,
}

impl ViaXml for Category {
    fn to_xml(&self) -> Element {
        let mut category = match self.domain {
            Some(ref d) => Element::new("category".to_string(), None, vec![("domain".to_string(), None, d.clone())]),
            None => Element::new("category".to_string(), None, vec![]),
        };
        category.text(self.value.clone());
        category
    }

    fn from_xml(elem: Element) -> Result<Self, &'static str> {
        let domain = elem.get_attribute("domain", None).map(|s| s.to_string());
        let value = elem.content_str();

        Ok(Category {
            domain: domain,
            value: value,
        })
    }
}

#[cfg(test)]
mod test {
    use std::default::Default;
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
            ..Default::default()
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
            ..Default::default()
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let rss = Rss::from_reader(&mut file).unwrap();
        assert!(rss.to_string().len() > 0);
    }

    #[test]
    #[should_panic]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_reader(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_from_read_one_channel_no_properties() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_reader(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_reader(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<|endoftext|>


<commit_before>#![crate_name = "spinlock"]
#![experimental]
#![crate_type = "lib"]
#![feature(unsafe_destructor)]
#![warn(missing_docs)]

#![no_std]

//! This crate provides a thread-safe data container.
//!
//! # Description
//!
//! This structure behaves a lot like a normal Mutex. There are some differences:
//!
//! - It may be used outside the runtime.
//!   - A normal mutex will fail when used without the runtime, this will just lock
//!   - When the runtime is present, it will call the deschedule function when appropriate
//! - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
//!
//! When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
//! helpfull. In other cases however, you are encouraged to use the locks from the standard
//! library.
//!
//! # Simple example
//!
//! ```
//! use spinlock::Spinlock;
//! let spinlock = Spinlock::new(0u);
//!
//! // Modify the data
//! {
//!     let mut data = spinlock.lock();
//!     *data = 2;
//! }
//!
//! // Read the data
//! let answer =
//! {
//!     let data = spinlock.lock();
//!     *data
//! };
//!
//! assert_eq!(answer, 2u);
//! ```
//!
//! # Thread-safety example
//!
//! ```
//! use spinlock::Spinlock;
//! use std::sync::{Arc, Barrier};
//!
//! let numthreads = 1000;
//! let spinlock = Arc::new(Spinlock::new(0u));
//!
//! // We use a barrier to ensure the readout happens after all writing
//! let barrier = Arc::new(Barrier::new(numthreads + 1));
//!
//! for _ in range(0, numthreads)
//! {
//!     let my_barrier = barrier.clone();
//!     let my_lock = spinlock.clone();
//!     spawn(move||
//!     {
//!         let mut guard = my_lock.lock();
//!         *guard += 1;
//!
//!         // Release the lock to prevent a deadlock
//!         drop(guard);
//!         my_barrier.wait();
//!     });
//! }
//!
//! barrier.wait();
//!
//! let answer = { *spinlock.lock() };
//! assert_eq!(answer, numthreads);
//! ```

extern crate core;

use core::kinds::Send;
use core::ops::{Drop, Deref, DerefMut};
use core::atomic::{AtomicBool, SeqCst};
use core::cell::UnsafeCell;

/// A wrapper for the data giving access in a thread-safe manner
pub struct Spinlock<T>
{
    lock: AtomicBool,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
#[experimental]
pub struct SpinlockGuard<'a, T:'a>
{
    lock: &'a AtomicBool,
    data: &'a mut T,
}

impl<T: Send> Spinlock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    #[unstable]
    pub fn new(user_data: T) -> Spinlock<T>
    {
        Spinlock
        {
            lock: AtomicBool::new(false),
            data: UnsafeCell::new(user_data),
        }
    }

    #[inline(always)]
    fn lock_check(&self) -> bool
    {
        self.lock.compare_and_swap(false, true, SeqCst) != false
    }

    fn obtain_lock(&self)
    {
        while self.lock_check()
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spinlock::Spinlock::new(0u);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    /// }
    /// // The lock is dropped
    /// ```
    pub fn lock(&self) -> SpinlockGuard<T>
    {
        self.obtain_lock();
        SpinlockGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }
}

impl<'a, T: Send> Deref<T> for SpinlockGuard<'a, T>
{
    fn deref<'a>(&'a self) -> &'a T { &*self.data }
}

impl<'a, T: Send> DerefMut<T> for SpinlockGuard<'a, T>
{
    fn deref_mut<'a>(&'a mut self) -> &'a mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T: Send> Drop for SpinlockGuard<'a, T>
{
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(false, SeqCst);
    }
}
<commit_msg>Rename lifetimes of deref and deref_mut to avoid lifetime shadowing (deprecated and will be removed). See Deref Implementation of core::cell::Ref for a similar case<commit_after>#![crate_name = "spinlock"]
#![experimental]
#![crate_type = "lib"]
#![feature(unsafe_destructor)]
#![warn(missing_docs)]

#![no_std]

//! This crate provides a thread-safe data container.
//!
//! # Description
//!
//! This structure behaves a lot like a normal Mutex. There are some differences:
//!
//! - It may be used outside the runtime.
//!   - A normal mutex will fail when used without the runtime, this will just lock
//!   - When the runtime is present, it will call the deschedule function when appropriate
//! - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
//!
//! When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
//! helpfull. In other cases however, you are encouraged to use the locks from the standard
//! library.
//!
//! # Simple example
//!
//! ```
//! use spinlock::Spinlock;
//! let spinlock = Spinlock::new(0u);
//!
//! // Modify the data
//! {
//!     let mut data = spinlock.lock();
//!     *data = 2;
//! }
//!
//! // Read the data
//! let answer =
//! {
//!     let data = spinlock.lock();
//!     *data
//! };
//!
//! assert_eq!(answer, 2u);
//! ```
//!
//! # Thread-safety example
//!
//! ```
//! use spinlock::Spinlock;
//! use std::sync::{Arc, Barrier};
//!
//! let numthreads = 1000;
//! let spinlock = Arc::new(Spinlock::new(0u));
//!
//! // We use a barrier to ensure the readout happens after all writing
//! let barrier = Arc::new(Barrier::new(numthreads + 1));
//!
//! for _ in range(0, numthreads)
//! {
//!     let my_barrier = barrier.clone();
//!     let my_lock = spinlock.clone();
//!     spawn(move||
//!     {
//!         let mut guard = my_lock.lock();
//!         *guard += 1;
//!
//!         // Release the lock to prevent a deadlock
//!         drop(guard);
//!         my_barrier.wait();
//!     });
//! }
//!
//! barrier.wait();
//!
//! let answer = { *spinlock.lock() };
//! assert_eq!(answer, numthreads);
//! ```

extern crate core;

use core::kinds::Send;
use core::ops::{Drop, Deref, DerefMut};
use core::atomic::{AtomicBool, SeqCst};
use core::cell::UnsafeCell;

/// A wrapper for the data giving access in a thread-safe manner
pub struct Spinlock<T>
{
    lock: AtomicBool,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
#[experimental]
pub struct SpinlockGuard<'a, T:'a>
{
    lock: &'a AtomicBool,
    data: &'a mut T,
}

impl<T: Send> Spinlock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    #[unstable]
    pub fn new(user_data: T) -> Spinlock<T>
    {
        Spinlock
        {
            lock: AtomicBool::new(false),
            data: UnsafeCell::new(user_data),
        }
    }

    #[inline(always)]
    fn lock_check(&self) -> bool
    {
        self.lock.compare_and_swap(false, true, SeqCst) != false
    }

    fn obtain_lock(&self)
    {
        while self.lock_check()
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spinlock::Spinlock::new(0u);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    /// }
    /// // The lock is dropped
    /// ```
    pub fn lock(&self) -> SpinlockGuard<T>
    {
        self.obtain_lock();
        SpinlockGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }
}

impl<'a, T: Send> Deref<T> for SpinlockGuard<'a, T>
{
    fn deref<'b>(&'b self) -> &'b T { &*self.data }
}

impl<'a, T: Send> DerefMut<T> for SpinlockGuard<'a, T>
{
    fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T: Send> Drop for SpinlockGuard<'a, T>
{
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(false, SeqCst);
    }
}
<|endoftext|>


<commit_before>#![feature(no_std)]
#![feature(core)]
#![feature(raw)]
#![no_std]

#![crate_name = "multiboot"]
#![crate_type = "lib"]

extern crate core;

#[cfg(test)]
extern crate std;

use core::mem::{transmute};
use core::ops::FnMut;
use core::raw;
use core::str;

/// Value that is in rax after multiboot jumps to our entry point
pub const SIGNATURE_RAX: u64 = 0x2BADB002;

#[derive(Debug, PartialEq, Eq)]
pub enum MemType {
    RAM = 1,
    Unusable = 2,
}

pub type PAddr = u64;
pub type VAddr = usize;

/// Multiboot struct clients mainly interact with
/// To create this use Multiboot::new()
pub struct Multiboot<'a> {
    header: &'a MultibootHeader,
    paddr_to_vaddr: fn(PAddr) -> VAddr,
}

/// Representation of Multiboot header according to specification.
#[derive(Debug)]
#[repr(packed)]
struct MultibootHeader {
    flags: u32,

    mem_lower: u32,
    mem_upper: u32,

    boot_device: u32,
    cmdline: u32,

    mods_count: u32,
    mods_addr: u32,

    elf_symbols: ElfSymbols,

    mmap_length: u32,
    mmap_addr: u32,
}

/// Multiboot format of the MMAP buffer.
/// Note that size is defined to be at -4 bytes.
#[derive(Debug)]
#[repr(packed)]
struct MemEntry {
    size: u32,
    base_addr: u64,
    length: u64,
    mtype: u32
}

#[derive(Debug)]
#[repr(packed)]
struct ElfSymbols {
    num: u32,
    size: u32,
    addr: u32,
    shndx: u32,
}

/// Multiboot module structure
#[derive(Debug)]
#[repr(packed)]
struct Module {
    /// Start address of module in memory.
    start: u32,
    /// End address of module in memory.
    end: u32,
    /// Name of module.
    string: u32,
    /// Must be zero.
    reserved: u32
}

/// Convert a C string into a [u8 slice and from there into a &'static str.
/// This unsafe block builds on assumption that multiboot strings are sane.
fn convert_safe_c_string(cstring: *const u8) -> &'static str {
    unsafe {
        let mut iter = cstring;
        while *iter != 0 {
            iter = iter.offset(1);
        }

        let slice = raw::Slice { data: cstring, len: iter as usize - cstring as usize };
        let byte_array: &'static [u8] = transmute(slice);
        str::from_utf8_unchecked(byte_array)
    }
}

impl<'a> Multiboot<'a> {

    /// Initializes the multiboot structure.
    ///
    /// # Arguments
    ///
    ///  * `mboot_ptr` - The physical address of the multiboot header. On qemu for example
    ///                  this is typically at 0x9500.
    ///  * `paddr_to_vaddr` - Translation of the physical addresses into kernel addresses.
    ///
    ///  `paddr_to_vaddr` translates physical it into a kernel accessible address.
    ///  The simplest paddr_to_vaddr function would for example be just the identity
    ///  function. But this may vary depending on how your page table layout looks like.
    ///
    pub fn new(mboot_ptr: u64, paddr_to_vaddr: fn(paddr: PAddr) -> VAddr) -> Multiboot<'a> {
        let header = paddr_to_vaddr(mboot_ptr);
        let mb: &MultibootHeader = unsafe { transmute::<VAddr, &MultibootHeader>(header) };

        Multiboot { header: mb, paddr_to_vaddr: paddr_to_vaddr }
    }

    pub fn has_mmap(&'a self) -> bool {
        self.header.flags & 0x1 > 0
    }

    /// Discover all memory regions in the multiboot memory map.
    ///
    /// # Arguments
    ///
    ///  * `discovery_callback` - Function to notify your memory system about regions.
    ///
    pub fn find_memory<F: FnMut(u64, u64, MemType)>(&'a self, mut discovery_callback: F) {
        if !self.has_mmap() {
            return
        }

        let paddr_to_vaddr = self.paddr_to_vaddr;

        let mut current = self.header.mmap_addr;
        let end = self.header.mmap_addr + self.header.mmap_length;
        while current < end
        {
            let memory_region: &MemEntry = unsafe { transmute::<VAddr, &MemEntry>(paddr_to_vaddr(current as u64)) };

            let mtype = match memory_region.mtype {
                1 => MemType::RAM,
                2 => MemType::Unusable,
                _ => MemType::Unusable
            };

            discovery_callback(memory_region.base_addr, memory_region.length, mtype);
            current += memory_region.size + 4;
        }
    }

    pub fn has_modules(&'a self) -> bool {
        self.header.flags & (1<<3) > 0
    }

    /// Discover all additional modules in multiboot.
    ///
    /// # Arguments
    ///
    ///  * `discovery_callback` - Function to notify your system about modules.
    ///
    pub fn find_modules<F: FnMut(&'static str, VAddr, VAddr)>(&'a self, mut discovery_callback: F) {
        if !self.has_modules() {
            return
        }

        let paddr_to_vaddr = self.paddr_to_vaddr;

        let module_start = paddr_to_vaddr(self.header.mods_addr as u64);
        let count: usize = self.header.mods_count as usize;
        for _ in 0..count {
            let current: &Module = unsafe { transmute::<VAddr, &Module>(module_start) };
            let path = unsafe { convert_safe_c_string(transmute::<VAddr, *const u8>(paddr_to_vaddr(current.string as u64))) };

            discovery_callback(path, paddr_to_vaddr(current.start as PAddr), paddr_to_vaddr(current.end as PAddr));
        }
    }
}
<commit_msg>Update comments, rename MultibootHeader -> MultibootInfo.<commit_after>//! Multiboot v1 library
//!
//! # Additional documentation
//!   * https://www.gnu.org/software/grub/manual/multiboot/multiboot.html
//!   * http://git.savannah.gnu.org/cgit/grub.git/tree/doc/multiboot.texi?h=multiboot
//!

#![feature(no_std)]
#![feature(core)]
#![feature(raw)]
#![no_std]

#![crate_name = "multiboot"]
#![crate_type = "lib"]

extern crate core;

#[cfg(test)]
extern crate std;

use core::mem::{transmute};
use core::ops::FnMut;
use core::raw;
use core::str;

/// Value found in %rax after multiboot jumps to our entry point.
pub const SIGNATURE_RAX: u64 = 0x2BADB002;

/// Types that define if the memory is usable or not.
#[derive(Debug, PartialEq, Eq)]
pub enum MemType {
    RAM = 1,
    Unusable = 2,
}

pub type PAddr = u64;
pub type VAddr = usize;

/// Multiboot struct clients mainly interact with
/// To create this use Multiboot::new()
pub struct Multiboot<'a> {
    header: &'a MultibootInfo,
    paddr_to_vaddr: fn(PAddr) -> VAddr,
}

/// Representation of Multiboot header according to specification.
////
///<rawtext>
///         +-------------------+
/// 0       | flags             |    (required)
///         +-------------------+
/// 4       | mem_lower         |    (present if flags[0] is set)
/// 8       | mem_upper         |    (present if flags[0] is set)
///         +-------------------+
/// 12      | boot_device       |    (present if flags[1] is set)
///         +-------------------+
/// 16      | cmdline           |    (present if flags[2] is set)
///         +-------------------+
/// 20      | mods_count        |    (present if flags[3] is set)
/// 24      | mods_addr         |    (present if flags[3] is set)
///         +-------------------+
/// 28 - 40 | syms              |    (present if flags[4] or
///         |                   |                flags[5] is set)
///         +-------------------+
/// 44      | mmap_length       |    (present if flags[6] is set)
/// 48      | mmap_addr         |    (present if flags[6] is set)
///         +-------------------+
/// 52      | drives_length     |    (present if flags[7] is set)
/// 56      | drives_addr       |    (present if flags[7] is set)
///         +-------------------+
/// 60      | config_table      |    (present if flags[8] is set)
///         +-------------------+
/// 64      | boot_loader_name  |    (present if flags[9] is set)
///         +-------------------+
/// 68      | apm_table         |    (present if flags[10] is set)
///         +-------------------+
/// 72      | vbe_control_info  |    (present if flags[11] is set)
/// 76      | vbe_mode_info     |
/// 80      | vbe_mode          |
/// 82      | vbe_interface_seg |
/// 84      | vbe_interface_off |
/// 86      | vbe_interface_len |
///         +-------------------+
///</rawtext>
///
#[derive(Debug)]
#[repr(packed)]
struct MultibootInfo {
    flags: u32,

    mem_lower: u32,
    mem_upper: u32,

    boot_device: u32,
    cmdline: u32,

    mods_count: u32,
    mods_addr: u32,

    elf_symbols: ElfSymbols,

    mmap_length: u32,
    mmap_addr: u32,

    drives_length: u32,
    drives_addr: u32,

    config_table: u32,

    boot_loader_name: u32,

    apm_table: u32,

    vbe_control_info: u32,
    vbe_mode_info: u32,
    vbe_mode: u16,
    vbe_interface_off: u16,
    vbe_interface_len: u16
}

/// Multiboot format of the MMAP buffer.
///
/// Note that size is defined to be at -4 bytes in multiboot.
#[derive(Debug)]
#[repr(packed)]
struct MemEntry {
    size: u32,
    base_addr: u64,
    length: u64,
    mtype: u32
}

/// ELF Symbols
#[derive(Debug)]
#[repr(packed)]
struct ElfSymbols {
    num: u32,
    size: u32,
    addr: u32,
    shndx: u32,
}

/// Multiboot module representation
#[derive(Debug)]
#[repr(packed)]
struct Module {
    /// Start address of module in memory.
    start: u32,
    /// End address of module in memory.
    end: u32,
    /// Name of module.
    string: u32,
    /// Must be zero.
    reserved: u32
}

/// Convert a C string into a [u8 slice and from there into a &'static str.
/// This unsafe block builds on assumption that multiboot strings are sane.
fn convert_safe_c_string(cstring: *const u8) -> &'static str {
    unsafe {
        let mut iter = cstring;
        while *iter != 0 {
            iter = iter.offset(1);
        }

        let slice = raw::Slice { data: cstring, len: iter as usize - cstring as usize };
        let byte_array: &'static [u8] = transmute(slice);
        str::from_utf8_unchecked(byte_array)
    }
}

impl<'a> Multiboot<'a> {

    /// Initializes the multiboot structure.
    ///
    /// # Arguments
    ///
    ///  * `mboot_ptr` - The physical address of the multiboot header. On qemu for example
    ///                  this is typically at 0x9500.
    ///  * `paddr_to_vaddr` - Translation of the physical addresses into kernel addresses.
    ///
    ///  `paddr_to_vaddr` translates physical it into a kernel accessible address.
    ///  The simplest paddr_to_vaddr function would for example be just the identity
    ///  function. But this may vary depending on how your page table layout looks like.
    ///
    pub fn new(mboot_ptr: u64, paddr_to_vaddr: fn(paddr: PAddr) -> VAddr) -> Multiboot<'a> {
        let header = paddr_to_vaddr(mboot_ptr);
        let mb: &MultibootInfo = unsafe { transmute::<VAddr, &MultibootInfo>(header) };

        Multiboot { header: mb, paddr_to_vaddr: paddr_to_vaddr }
    }

    pub fn has_mmap(&'a self) -> bool {
        self.header.flags & 0x1 > 0
    }

    /// Discover all memory regions in the multiboot memory map.
    ///
    /// # Arguments
    ///
    ///  * `discovery_callback` - Function to notify your memory system about regions.
    ///
    pub fn find_memory<F: FnMut(u64, u64, MemType)>(&'a self, mut discovery_callback: F) {
        if !self.has_mmap() {
            return
        }

        let paddr_to_vaddr = self.paddr_to_vaddr;

        let mut current = self.header.mmap_addr;
        let end = self.header.mmap_addr + self.header.mmap_length;
        while current < end
        {
            let memory_region: &MemEntry = unsafe { transmute::<VAddr, &MemEntry>(paddr_to_vaddr(current as u64)) };

            let mtype = match memory_region.mtype {
                1 => MemType::RAM,
                2 => MemType::Unusable,
                _ => MemType::Unusable
            };

            discovery_callback(memory_region.base_addr, memory_region.length, mtype);
            current += memory_region.size + 4;
        }
    }

    pub fn has_modules(&'a self) -> bool {
        self.header.flags & (1<<3) > 0
    }

    /// Discover all additional modules in multiboot.
    ///
    /// # Arguments
    ///
    ///  * `discovery_callback` - Function to notify your system about modules.
    ///
    pub fn find_modules<F: FnMut(&'static str, VAddr, VAddr)>(&'a self, mut discovery_callback: F) {
        if !self.has_modules() {
            return
        }

        let paddr_to_vaddr = self.paddr_to_vaddr;

        let module_start = paddr_to_vaddr(self.header.mods_addr as u64);
        let count: usize = self.header.mods_count as usize;
        for _ in 0..count {
            let current: &Module = unsafe { transmute::<VAddr, &Module>(module_start) };
            let path = unsafe { convert_safe_c_string(transmute::<VAddr, *const u8>(paddr_to_vaddr(current.string as u64))) };

            discovery_callback(path, paddr_to_vaddr(current.start as PAddr), paddr_to_vaddr(current.end as PAddr));
        }
    }
}
<|endoftext|>


<commit_before>//! Checked arithmetic.
//!
//! The Checked struct allows you to perform checked arithmetic without an overabundance of
//! .checked_* calls.
//! # Examples
//! ```
//! use checked::Checked;
//!
//! let x = Checked::from(1_000_u32);
//! let y = Checked::from(1_000_000_u32);
//!
//! assert_eq!(x * 1_000, y);
//! assert_eq!(1_000_000 * y, Checked::from(None));
//! assert_eq!(x << 3, Checked::<u32>::from(8_000));
//! ```
//!
//! All the basic arithmetic operations are implemented.
//!
//! ```
//! use checked::Checked;
//!
//! assert_eq!(Checked::<u8>::from(5) + Checked::<u8>::from(6), Checked::<u8>::from(11));
//! assert_eq!(Checked::<u8>::from(5) - Checked::<u8>::from(6), Checked::<u8>::from(None));
//! assert_eq!(Checked::<u8>::from(5) * Checked::<u8>::from(6), Checked::<u8>::from(30));
//! assert_eq!(Checked::<u8>::from(5) / Checked::<u8>::from(6), Checked::<u8>::from(0));
//! assert_eq!(- Checked::<u8>::from(6), Checked::<u8>::from(None));
//! assert_eq!(Checked::<u8>::from(5) % Checked::<u8>::from(6), Checked::<u8>::from(5));
//! ```
//!
//! Including bitwise operations.
//!
//! ```
//! use checked::Checked;
//!
//! assert_eq!(Checked::<u8>::from(5) & Checked::<u8>::from(6), Checked::<u8>::from(4));
//! assert_eq!(Checked::<u8>::from(5) | Checked::<u8>::from(6), Checked::<u8>::from(7));
//! assert_eq!(Checked::<u8>::from(5) ^ Checked::<u8>::from(6), Checked::<u8>::from(3));
//! assert_eq!(! Checked::<u8>::from(6), Checked::<u8>::from(249));
//! assert_eq!(Checked::<u8>::from(5) << Checked::<u32>::from(5), Checked::<u8>::from(160));
//! assert_eq!(Checked::<u8>::from(160) >> Checked::<u32>::from(5), Checked::<u8>::from(5));
//! ```
//!
//! Ord is implemented, and the overflow state is considered less than everything
//! (may change this in the future)
//!
//! ```
//! use checked::Checked;
//!
//! assert!(Checked::from(1_000_u32) <= Checked::from(10_000_u32));
//! assert!(!(Checked::from(1_000_u32) <= Checked::from(None)));
//! assert!((Checked::from(None) <= Checked::from(1_000_u32)));
//! ```

mod num;
pub use num::Checked;

#[cfg(test)]
mod tests;
<commit_msg>added option_like module<commit_after>//! Checked arithmetic.
//!
//! The Checked struct allows you to perform checked arithmetic without an overabundance of
//! .checked_* calls.
//! # Examples
//! ```
//! use checked::Checked;
//!
//! let x = Checked::from(1_000_u32);
//! let y = Checked::from(1_000_000_u32);
//!
//! assert_eq!(x * 1_000, y);
//! assert_eq!(1_000_000 * y, Checked::from(None));
//! assert_eq!(x << 3, Checked::<u32>::from(8_000));
//! ```
//!
//! All the basic arithmetic operations are implemented.
//!
//! ```
//! use checked::Checked;
//!
//! assert_eq!(Checked::<u8>::from(5) + Checked::<u8>::from(6), Checked::<u8>::from(11));
//! assert_eq!(Checked::<u8>::from(5) - Checked::<u8>::from(6), Checked::<u8>::from(None));
//! assert_eq!(Checked::<u8>::from(5) * Checked::<u8>::from(6), Checked::<u8>::from(30));
//! assert_eq!(Checked::<u8>::from(5) / Checked::<u8>::from(6), Checked::<u8>::from(0));
//! assert_eq!(- Checked::<u8>::from(6), Checked::<u8>::from(None));
//! assert_eq!(Checked::<u8>::from(5) % Checked::<u8>::from(6), Checked::<u8>::from(5));
//! ```
//!
//! Including bitwise operations.
//!
//! ```
//! use checked::Checked;
//!
//! assert_eq!(Checked::<u8>::from(5) & Checked::<u8>::from(6), Checked::<u8>::from(4));
//! assert_eq!(Checked::<u8>::from(5) | Checked::<u8>::from(6), Checked::<u8>::from(7));
//! assert_eq!(Checked::<u8>::from(5) ^ Checked::<u8>::from(6), Checked::<u8>::from(3));
//! assert_eq!(! Checked::<u8>::from(6), Checked::<u8>::from(249));
//! assert_eq!(Checked::<u8>::from(5) << Checked::<u32>::from(5), Checked::<u8>::from(160));
//! assert_eq!(Checked::<u8>::from(160) >> Checked::<u32>::from(5), Checked::<u8>::from(5));
//! ```
//!
//! Ord is implemented, and the overflow state is considered less than everything
//! (may change this in the future)
//!
//! ```
//! use checked::Checked;
//!
//! assert!(Checked::from(1_000_u32) <= Checked::from(10_000_u32));
//! assert!(!(Checked::from(1_000_u32) <= Checked::from(None)));
//! assert!((Checked::from(None) <= Checked::from(1_000_u32)));
//! ```

mod num;
pub use num::Checked;

mod option_like;
pub use option_like::{IntoOption, AsRefOption, AsMutOption};

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>extern crate heatmap;
extern crate hsl;
extern crate lodepng;
extern crate rusttype;

use std::path::Path;

use heatmap::Heatmap;
use hsl::HSL;
use lodepng::encode_file;
use rusttype::{FontCollection, PixelsXY, point, PositionedGlyph};

pub struct Waterfall {
	pub heatmap: Heatmap,
}

pub struct WaterfallConfig {
	num_slices: usize,
	precision: u32,
	slice_duration: u64,
}

impl WaterfallConfig {
	pub fn new() -> WaterfallConfig {
		WaterfallConfig {
			precision: 2,
			num_slices: 300,
			slice_duration: 1,
		}
	}

	pub fn num_slices(&mut self, count: usize) -> &mut Self {
		self.num_slices = count;
		self
	}

	pub fn slice_duration(&mut self, value: u64) -> &mut Self {
		self.slice_duration = value;
		self
	}
}

struct Label {
	value: u64,
	text: String,
}

impl Waterfall {
	pub fn new() -> Waterfall {
		Waterfall::configured(WaterfallConfig::new())
	}

	pub fn configured(config: WaterfallConfig) -> Waterfall {
		let heatmap = Heatmap::configure()
			.precision(config.precision)
			.num_slices(config.num_slices)
			.slice_duration(config.slice_duration)
			.build()
			.unwrap();
		Waterfall {
			heatmap: heatmap,
		}
	}

	pub fn load_file(&mut self, file: String) {
		let mut d = Heatmap::load(file.clone());
		self.heatmap.merge(&mut d);
	}

	pub fn merge_heatmap(&mut self, mut heatmap: Heatmap) {
		self.heatmap.merge(&mut heatmap);
	}

	pub fn find_max(&mut self) -> u64 {
		let mut max = 0_u64;
		for slice in &self.heatmap {
			for bucket in &slice.histogram {
				if bucket.count() > max {
					max = bucket.count();
				}
			}
		}
		max
	}

	pub fn render_png(&mut self, file: String) {
		let height = self.heatmap.num_slices() as usize;
		let width = self.heatmap.histogram_buckets() as usize;

		// build buffer from data
		let mut buffer = ImageBuffer::<ColorRgb>::new(width, height);
		let max = self.find_max();
		let mut x;
		let mut y = 0;

		// loop to color the pixels
		for slice in &self.heatmap {
			x = 0;
			for bucket in &slice.histogram {
				let pixel = color_from_value(bucket.count(), max);
				buffer.set_pixel(x, y, pixel);
				x += 1;
			}
		}

		// latency annotations
		let labels: Vec<Label> = vec!(
			Label{ value: 200, text: "200nS".to_string() },
			Label{ value: 500, text: "500nS".to_string() },
			Label{ value: 1000, text: "1uS".to_string() },
			Label{ value: 2000, text: "2uS".to_string() },
			Label{ value: 5000, text: "5uS".to_string() },
			Label{ value: 10000, text: "10uS".to_string() },
			Label{ value: 20000, text: "20uS".to_string() },
			Label{ value: 50000, text: "50uS".to_string() },
			Label{ value: 100000, text: "100uS".to_string() },
			Label{ value: 200000, text: "200uS".to_string() },
			Label{ value: 500000, text: "500uS".to_string() },
			Label{ value: 1000000, text: "1mS".to_string() },
			Label{ value: 2000000, text: "2mS".to_string() },
			Label{ value: 5000000, text: "5mS".to_string() },
			Label{ value: 10000000, text: "10mS".to_string() },
			Label{ value: 20000000, text: "20mS".to_string() },
			Label{ value: 50000000, text: "50mS".to_string() },
			Label{ value: 100000000, text: "100mS".to_string() },
			Label{ value: 200000000, text: "200mS".to_string() },
			Label{ value: 500000000, text: "500mS".to_string() },
			);

		let mut l = 0;
		y = 0;
		for slice in &self.heatmap {
			x = 0;
			for bucket in &slice.histogram {
				if (y % 60) == 0 {
					if x == 0 {
						let hour = y / 3600;
						let minute = y / 60;
						let time = format!("{:02}:{:02}", hour, minute);
						let overlay = string_buffer(time.to_string(), 25.0);
						buffer.overlay(&overlay, x, y);
						buffer.horizontal_line(y, ColorRgb { r: 0, g: 0, b: 0 });
					}
					let v = bucket.value();
					if l < labels.len() {
						if v >= labels[l].value {
							let overlay = string_buffer(labels[l].text.clone(), 25.0);
							buffer.overlay(&overlay, x, y);
							buffer.vertical_line(x, ColorRgb { r: 0, g: 0, b: 0 });
							l += 1;
						}
					}

				}
				x += 1;
			}
		}

		let _ = buffer.write_png(file.clone());
	}

}

fn string_buffer(string: String, size: f32) -> ImageBuffer<ColorRgb> {
	// load font
	let font_data = include_bytes!("../assets/ubuntumono/UbuntuMono-Regular.ttf");
	let collection = FontCollection::from_bytes(font_data as &[u8]);
	let font = collection.into_font().unwrap();

	// size and scaling
	let height: f32 = size;
	let pixel_height = height.ceil() as usize;
	let scale = PixelsXY(height*1.0, height);

	let v_metrics = font.v_metrics(scale);
	let offset = point(0.0, v_metrics.ascent);

	let glyphs: Vec<PositionedGlyph> = font.layout(&string, scale, offset).collect();

	let width = glyphs.iter().map(|g| g.h_metrics().advance_width)
    .fold(0.0, |x, y| x + y).ceil() as usize;

    let mut overlay = ImageBuffer::<ColorRgb>::new(width, pixel_height);

    for g in glyphs {
        if let Some(bb) = g.pixel_bounding_box() {
            g.draw(|x, y, v| {
                let x = (x as i32 + bb.min.x) as usize;
                let y = (y as i32 + bb.min.y) as usize;
                if v > 0.25 {
                	overlay.set_pixel(x, y, ColorRgb { r: 255, g: 255, b: 255 });
                }
            })
        }
    }

    overlay
}

fn color_from_value(value: u64, max: u64) -> ColorRgb {
	let value = (value as f64) / (max as f64);

	let knee = 0.20_f64;

	let hsl: HSL;

	if value < knee {
		let l = 0.25_f64 + 0.25_f64 * value / knee;
		hsl = HSL {
			h: 236_f64,
			s: 1_f64,
			l: l,
		};
	} else {
		let h_per_deg: f64 = 236_f64 / (1.0_f64 - knee);
		let deg = (value - knee) * h_per_deg;

		hsl = HSL {
			h: (236_f64 - deg),
			s: 1_f64,
			l: 0.50_f64,
		};
	}

	let (r, g, b) = hsl.to_rgb();
	ColorRgb {
	   r: r,
	   g: g,
	   b: b,
	}
}

#[derive(Clone, Copy, Debug, PartialEq)]
struct ColorRgb {
	r: u8,
	g: u8,
	b: u8,
}

struct ImageBuffer<T> {
	buffer: Vec<Vec<T>>,
	height: usize,
	width: usize,
}

impl ImageBuffer<ColorRgb> {
	pub fn new(width: usize, height: usize) -> ImageBuffer<ColorRgb> {
		let background = ColorRgb {
			r: 0,
			g: 0,
			b: 0,
		};
		let mut row = Vec::<ColorRgb>::with_capacity(width);
		for _ in 0..width {
			row.push(background);
		}
		let mut buffer = Vec::<Vec<ColorRgb>>::with_capacity(height);
		for _ in 0..height {
			buffer.push(row.clone());
		}
		ImageBuffer {
			buffer: buffer,
			height: height,
			width: width,
		}
	}

	pub fn write_png(self, file: String) -> Result<(), lodepng::ffi::Error> {
		let mut buffer = Vec::<u8>::with_capacity((self.height * self.width ));
		for row in 0..self.height {
			for col in 0..self.width {
				let pixel = self.buffer[row][col];
				buffer.push(pixel.r);
				buffer.push(pixel.g);
				buffer.push(pixel.b);
			}
		}
		let path = &Path::new(&file);
		encode_file(path, &buffer, self.width, self.height, lodepng::LCT_RGB, 8)
	}

	pub fn set_pixel(&mut self, x: usize, y: usize, value: ColorRgb) {
		if x < self.width && y < self.height {
			self.buffer[y][x] = value;
		}
	}

	pub fn overlay(&mut self, other: &ImageBuffer<ColorRgb>, x: usize, y: usize) {
		let ignore = ColorRgb { r: 0, g: 0, b: 0 };
		for sx in 0..other.width {
			for sy in 0..other.height {
				if other.buffer[sy][sx] != ignore {
					if ((sy + y) < self.height) && ((sx + x) < self.width){
						self.buffer[(sy + y)][(sx + x)] = other.buffer[sy][sx];
					}
				}
			}
		}
	}

	pub fn horizontal_line(&mut self, y: usize, color: ColorRgb) {
		for x in 0..self.width {
			self.buffer[y][x] = color;
		}
	}

	pub fn vertical_line(&mut self, x: usize, color: ColorRgb) {
		for y in 0..self.height {
			self.buffer[y][x] = color;
		}
	}
}
<commit_msg>improved builder pattern<commit_after>extern crate heatmap;
extern crate hsl;
extern crate lodepng;
extern crate rusttype;

use std::path::Path;

use heatmap::Heatmap;
use hsl::HSL;
use lodepng::encode_file;
use rusttype::{FontCollection, PixelsXY, point, PositionedGlyph};

pub struct Waterfall {
	pub heatmap: Heatmap,
}

pub struct Config {
	num_slices: usize,
	precision: u32,
	slice_duration: u64,
}

impl Default for Config {
	fn default() -> Config {
		Config {
			precision: 2,
			num_slices: 300,
			slice_duration: 1,
		}
	}
}

impl Config {
	pub fn new() -> Config {
		Default::default()
	}

	pub fn num_slices(&mut self, count: usize) -> &mut Self {
		self.num_slices = count;
		self
	}

	pub fn slice_duration(&mut self, value: u64) -> &mut Self {
		self.slice_duration = value;
		self
	}

	pub fn build(self) -> Waterfall {
		Waterfall::configured(self)
	}
}

struct Label {
	value: u64,
	text: String,
}

impl Default for Waterfall {
	fn default() -> Waterfall {
		Waterfall::configured(Config::default())
	}
}

impl Waterfall {
	pub fn new() -> Waterfall {
		Default::default()
	}

	pub fn configure() -> Config {
		Config::default()
	}

	fn configured(config: Config) -> Waterfall {
		let heatmap = Heatmap::configure()
			.precision(config.precision)
			.num_slices(config.num_slices)
			.slice_duration(config.slice_duration)
			.build()
			.unwrap();
		Waterfall {
			heatmap: heatmap,
		}
	}

	pub fn load_file(&mut self, file: String) {
		let mut d = Heatmap::load(file.clone());
		self.heatmap.merge(&mut d);
	}

	pub fn merge_heatmap(&mut self, mut heatmap: Heatmap) {
		self.heatmap.merge(&mut heatmap);
	}

	pub fn find_max(&mut self) -> u64 {
		let mut max = 0_u64;
		for slice in &self.heatmap {
			for bucket in &slice.histogram {
				if bucket.count() > max {
					max = bucket.count();
				}
			}
		}
		max
	}

	pub fn render_png(&mut self, file: String) {
		let height = self.heatmap.num_slices() as usize;
		let width = self.heatmap.histogram_buckets() as usize;

		// build buffer from data
		let mut buffer = ImageBuffer::<ColorRgb>::new(width, height);
		let max = self.find_max();
		let mut x;
		let mut y = 0;

		// loop to color the pixels
		for slice in &self.heatmap {
			x = 0;
			for bucket in &slice.histogram {
				let pixel = color_from_value(bucket.count(), max);
				buffer.set_pixel(x, y, pixel);
				x += 1;
			}
		}

		// latency annotations
		let labels: Vec<Label> = vec!(
			Label{ value: 200, text: "200nS".to_string() },
			Label{ value: 500, text: "500nS".to_string() },
			Label{ value: 1000, text: "1uS".to_string() },
			Label{ value: 2000, text: "2uS".to_string() },
			Label{ value: 5000, text: "5uS".to_string() },
			Label{ value: 10000, text: "10uS".to_string() },
			Label{ value: 20000, text: "20uS".to_string() },
			Label{ value: 50000, text: "50uS".to_string() },
			Label{ value: 100000, text: "100uS".to_string() },
			Label{ value: 200000, text: "200uS".to_string() },
			Label{ value: 500000, text: "500uS".to_string() },
			Label{ value: 1000000, text: "1mS".to_string() },
			Label{ value: 2000000, text: "2mS".to_string() },
			Label{ value: 5000000, text: "5mS".to_string() },
			Label{ value: 10000000, text: "10mS".to_string() },
			Label{ value: 20000000, text: "20mS".to_string() },
			Label{ value: 50000000, text: "50mS".to_string() },
			Label{ value: 100000000, text: "100mS".to_string() },
			Label{ value: 200000000, text: "200mS".to_string() },
			Label{ value: 500000000, text: "500mS".to_string() },
			);

		let mut l = 0;
		y = 0;
		for slice in &self.heatmap {
			x = 0;
			for bucket in &slice.histogram {
				if (y % 60) == 0 {
					if x == 0 {
						let hour = y / 3600;
						let minute = y / 60;
						let time = format!("{:02}:{:02}", hour, minute);
						let overlay = string_buffer(time.to_string(), 25.0);
						buffer.overlay(&overlay, x, y);
						buffer.horizontal_line(y, ColorRgb { r: 0, g: 0, b: 0 });
					}
					let v = bucket.value();
					if l < labels.len() {
						if v >= labels[l].value {
							let overlay = string_buffer(labels[l].text.clone(), 25.0);
							buffer.overlay(&overlay, x, y);
							buffer.vertical_line(x, ColorRgb { r: 0, g: 0, b: 0 });
							l += 1;
						}
					}

				}
				x += 1;
			}
		}

		let _ = buffer.write_png(file.clone());
	}

}

fn string_buffer(string: String, size: f32) -> ImageBuffer<ColorRgb> {
	// load font
	let font_data = include_bytes!("../assets/ubuntumono/UbuntuMono-Regular.ttf");
	let collection = FontCollection::from_bytes(font_data as &[u8]);
	let font = collection.into_font().unwrap();

	// size and scaling
	let height: f32 = size;
	let pixel_height = height.ceil() as usize;
	let scale = PixelsXY(height*1.0, height);

	let v_metrics = font.v_metrics(scale);
	let offset = point(0.0, v_metrics.ascent);

	let glyphs: Vec<PositionedGlyph> = font.layout(&string, scale, offset).collect();

	let width = glyphs.iter().map(|g| g.h_metrics().advance_width)
    .fold(0.0, |x, y| x + y).ceil() as usize;

    let mut overlay = ImageBuffer::<ColorRgb>::new(width, pixel_height);

    for g in glyphs {
        if let Some(bb) = g.pixel_bounding_box() {
            g.draw(|x, y, v| {
                let x = (x as i32 + bb.min.x) as usize;
                let y = (y as i32 + bb.min.y) as usize;
                if v > 0.25 {
                	overlay.set_pixel(x, y, ColorRgb { r: 255, g: 255, b: 255 });
                }
            })
        }
    }

    overlay
}

fn color_from_value(value: u64, max: u64) -> ColorRgb {
	let value = (value as f64) / (max as f64);

	let knee = 0.20_f64;

	let hsl: HSL;

	if value < knee {
		let l = 0.25_f64 + 0.25_f64 * value / knee;
		hsl = HSL {
			h: 236_f64,
			s: 1_f64,
			l: l,
		};
	} else {
		let h_per_deg: f64 = 236_f64 / (1.0_f64 - knee);
		let deg = (value - knee) * h_per_deg;

		hsl = HSL {
			h: (236_f64 - deg),
			s: 1_f64,
			l: 0.50_f64,
		};
	}

	let (r, g, b) = hsl.to_rgb();
	ColorRgb {
	   r: r,
	   g: g,
	   b: b,
	}
}

#[derive(Clone, Copy, Debug, PartialEq)]
struct ColorRgb {
	r: u8,
	g: u8,
	b: u8,
}

struct ImageBuffer<T> {
	buffer: Vec<Vec<T>>,
	height: usize,
	width: usize,
}

impl ImageBuffer<ColorRgb> {
	pub fn new(width: usize, height: usize) -> ImageBuffer<ColorRgb> {
		let background = ColorRgb {
			r: 0,
			g: 0,
			b: 0,
		};
		let mut row = Vec::<ColorRgb>::with_capacity(width);
		for _ in 0..width {
			row.push(background);
		}
		let mut buffer = Vec::<Vec<ColorRgb>>::with_capacity(height);
		for _ in 0..height {
			buffer.push(row.clone());
		}
		ImageBuffer {
			buffer: buffer,
			height: height,
			width: width,
		}
	}

	pub fn write_png(self, file: String) -> Result<(), lodepng::ffi::Error> {
		let mut buffer = Vec::<u8>::with_capacity((self.height * self.width ));
		for row in 0..self.height {
			for col in 0..self.width {
				let pixel = self.buffer[row][col];
				buffer.push(pixel.r);
				buffer.push(pixel.g);
				buffer.push(pixel.b);
			}
		}
		let path = &Path::new(&file);
		encode_file(path, &buffer, self.width, self.height, lodepng::LCT_RGB, 8)
	}

	pub fn set_pixel(&mut self, x: usize, y: usize, value: ColorRgb) {
		if x < self.width && y < self.height {
			self.buffer[y][x] = value;
		}
	}

	pub fn overlay(&mut self, other: &ImageBuffer<ColorRgb>, x: usize, y: usize) {
		let ignore = ColorRgb { r: 0, g: 0, b: 0 };
		for sx in 0..other.width {
			for sy in 0..other.height {
				if other.buffer[sy][sx] != ignore {
					if ((sy + y) < self.height) && ((sx + x) < self.width){
						self.buffer[(sy + y)][(sx + x)] = other.buffer[sy][sx];
					}
				}
			}
		}
	}

	pub fn horizontal_line(&mut self, y: usize, color: ColorRgb) {
		for x in 0..self.width {
			self.buffer[y][x] = color;
		}
	}

	pub fn vertical_line(&mut self, x: usize, color: ColorRgb) {
		for y in 0..self.height {
			self.buffer[y][x] = color;
		}
	}
}
<|endoftext|>


<commit_before>#![feature(plugin, unboxed_closures, core, iter_arith, custom_attribute, slice_patterns)]
#![plugin(clippy)]
#![deny(missing_docs)]

//! # inverted_index
//! This library provides an in-memory (subject to change) `InvertedIndex` that indexes documents
//! to make them searchable.  Below are a few details about its features. For more examples, see
//! the tests.
//!
//! ## Indexing
//! ```
//! let mut index = InvertedIndex::new();
//! index.index(Document::new("1", "learn to program in rust today"));
//! ```
//!
//! Indexing is the process of inserting a document into the `InvertedIndex` to make it searchable.
//! The general process is:
//!
//! 1. Tokenize the document's text, typically by splitting the text on word boundaries.
//! 2. Insert each token into the index with the original document as its payload.
//! 3. Optionally store additional metadata along with each document, such as positional
//!    information.
//!
//! ## Searching
//! ```
//! let results = index.search("prog");
//! ```
//!
//! Searches returns a set of search results. Each search result consists of a matching document,
//! the positions within the document that matched the query, and the document's search score.
//!
//! Searches can be performed via the `query` method using the composable `Query` enum, which
//! currently has four variants:
//!
//! * `Match` - The simplest query. Takes a string argument and returns any documents that match
//!             the string. `index.search(str)` is shorthand for `index.query(Match(str))`.
//! * `Phrase` - An exact-match query. Takes a string argument and returns any documents that
//!              contain the exact string. n.b. the `InvertedIndex` may return false positives in
//!              some cases.
//! * `And` - Composes a number of queries into a single query that restricts the results to the
//!           documents that are returned for each of the sub-queries.
//! * `Or` - Composes a number of queries into a single query that returns all the documents that
//!          are returned for any of the sub-queries.
//!
//! ## Scoring
//! The returned search results are ordered based on document relevance to the search query, sorted
//! descending. Currently, relevance for each document is computed based on the length of matching
//! content divided by the square root of the document length. This helps to ensure that longer
//! documents don't receive too unfair of an advantage over shorter documents.
//!
//! ## Highlighting
//! Search results include the positions in the document that matched the query. There is a helper
//! method defined on the `SearchResult` struct to highlight the matching content. It accepts
//! `before` and `after` string arguments to wrap the matching sections of the document in
//! highlights.
//! ```
//! for search_result in &results {
//!     println!("{:?}", search_result.highlight("<b>", "</b>"));
//! }
//! ```

extern crate itertools;
extern crate rustc_serialize;
extern crate core;

/// Contains utility methods used in the rest of the crate.
pub mod util;

mod document;
mod index;
mod postings;
mod query;
mod search_result;

pub use index::InvertedIndex;
pub use document::Document;
pub use search_result::SearchResult;
pub use postings::{PostingsMap, PostingsMerge, PostingsIntersect, PositionalIntersect, Position};
pub use query::Query;
<commit_msg>Fix doc tests<commit_after>#![feature(plugin, unboxed_closures, core, iter_arith, custom_attribute, slice_patterns)]
#![plugin(clippy)]
#![deny(missing_docs)]

//! # inverted_index
//! This library provides an in-memory (subject to change) `InvertedIndex` that indexes documents
//! to make them searchable.  Below are a few details about its features. For more examples, see
//! the tests.
//!
//! ## Indexing
//! ```
//! use inverted_index::{Document, InvertedIndex};
//! let mut index = InvertedIndex::new();
//! index.index(Document::new("1", "learn to program in rust today"));
//! ```
//!
//! Indexing is the process of inserting a document into the `InvertedIndex` to make it searchable.
//! The general process is:
//!
//! 1. Tokenize the document's text, typically by splitting the text on word boundaries.
//! 2. Insert each token into the index with the original document as its payload.
//! 3. Optionally store additional metadata along with each document, such as positional
//!    information.
//!
//! ## Searching
//! ```
//! use inverted_index::{Document, InvertedIndex};
//! let mut index = InvertedIndex::new();
//! index.index(Document::new("1", "learn to program in rust today"));
//! let results = index.search("prog");
//! ```
//!
//! Searches returns a set of search results. Each search result consists of a matching document,
//! the positions within the document that matched the query, and the document's search score.
//!
//! Searches can be performed via the `query` method using the composable `Query` enum, which
//! currently has four variants:
//!
//! * `Match` - The simplest query. Takes a string argument and returns any documents that match
//!             the string. `index.search(str)` is shorthand for `index.query(Match(str))`.
//! * `Phrase` - An exact-match query. Takes a string argument and returns any documents that
//!              contain the exact string. n.b. the `InvertedIndex` may return false positives in
//!              some cases.
//! * `And` - Composes a number of queries into a single query that restricts the results to the
//!           documents that are returned for each of the sub-queries.
//! * `Or` - Composes a number of queries into a single query that returns all the documents that
//!          are returned for any of the sub-queries.
//!
//! ## Scoring
//! The returned search results are ordered based on document relevance to the search query, sorted
//! descending. Currently, relevance for each document is computed based on the length of matching
//! content divided by the square root of the document length. This helps to ensure that longer
//! documents don't receive too unfair of an advantage over shorter documents.
//!
//! ## Highlighting
//! Search results include the positions in the document that matched the query. There is a helper
//! method defined on the `SearchResult` struct to highlight the matching content. It accepts
//! `before` and `after` string arguments to wrap the matching sections of the document in
//! highlights.
//!
//! ```
//! use inverted_index::{Document, InvertedIndex};
//! let mut index = InvertedIndex::new();
//! index.index(Document::new("1", "learn to program in rust today"));
//! let results = index.search("prog");
//! for search_result in &results {
//!     println!("{:?}", search_result.highlight("<b>", "</b>"));
//! }
//! ```

extern crate itertools;
extern crate rustc_serialize;
extern crate core;

/// Contains utility methods used in the rest of the crate.
pub mod util;

mod document;
mod index;
mod postings;
mod query;
mod search_result;

pub use index::InvertedIndex;
pub use document::Document;
pub use search_result::SearchResult;
pub use postings::{PostingsMap, PostingsMerge, PostingsIntersect, PositionalIntersect, Position};
pub use query::Query;
<|endoftext|>


<commit_before>#![no_std]

pub mod prelude;

// TODO documentation
// TODO attributes
// TODO MACROS
#[macro_export] macro_rules! lisp {
    // empty
    () => (());
    (()) => (());

    // special forms
    ((ns $($ns_form:tt)*) $($body:tt)*) => {
        $(lisp!($ns_form);)*
        $(lisp!($body);)*
    };
    ((extern [$($krate:tt)*])) => {
        $(lisp!(@krate $krate);)*
    };
    ((use [$($uze:tt)*])) => {
        $(lisp!(@uze $uze);)*
    };
    ((lambda ($($argn:ident)*) $($body:tt)*)) => {
        // regular lambda
        |$($argn),*| { $(lisp!($body));* }
    };
    ((lambda (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {
        // regular lambda
        |$($argn:$argt),*| -> $ret { $(lisp!($body));* }
    };
    ((lambda $s:ident (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {{
        // recursive lambda
        // $s MUST NOT be "self"
        // recurse by calling ($s ...)
        // FIXME recursive lambdas can't capture variables

        lisp!((rust { fn $s($($argn: $argt),*) -> $ret { $(lisp!($body));* } $s }))
    }};
    ((defn $name:ident () $($body:tt)*)) => {
        fn $name() {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([($selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([(&$selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name(&$selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([(&mut $selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name(&mut $selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([($selph:ident: Box<Self>) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($selph: Box<Self> $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([$(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($($argn:$argt),*) -> $ret {
            $(lisp!($body));*
        }
    };

    ((defstruct $name:ident $(($typ:ty))*)) => {
        struct $name($($typ),*);
    };
    ((defstruct $name:ident $(($field:ident $typ:ty))*)) => {
        struct $name { $($field: $typ),* }
    };
    ((defstruct $name:ident <$($gen:ident)*>)) => {
        struct $name<$($gen),*>;
    };
    ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($typ:ty))*)) => {
        struct $name<$($gen),*>($($typ),*) where $($wty: $($wtr)*),*;
    };
    ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($field:ident $typ:ty))*)) => {
        struct $name<$($gen),*> where $($wty: $($wtr)*),* { $($field: $typ),* }
    };

    ((deftype $name:ident $typ:ty)) => { type $name = $typ; };
    ((deftype $name:ident <$($gen:ident)*> $typ:ty)) => { type $name<$($gen),*> = $typ; };

    ((defimpl ($trate:ty) (for $typ:ty) $($body:tt)*)) => {
        impl $trate for $typ {
            $(lisp!($body);)*
        }
    };
    ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) (where $(($wty:ident $($wtr:tt)*))*) $($body:tt)*)) => {
        impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* {
            $(lisp!($body);)*
        }
    };
    ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) $($body:tt)*)) => {
        impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* {
            $(lisp!($body);)*
        }
    };

    ((if $cond:tt $yes:tt $no:tt)) => {
        if lisp!($cond) { lisp!($yes) } else { lisp!($no) }
    };
    ((while $cond:tt $($body:tt)*)) => {
        while lisp!($cond) { $(lisp!($body));* }
    };
    // TODO for loops
    ((match $var:tt $(($cond:pat) $arm:tt)*)) => {
        match lisp!($var) {
            $($cond => lisp!($arm)),*
        }
    };
    ((do $($stmts:tt)*)) => {{
        $(lisp!($stmts));*
    }};

    // variables
    ((let ((mut $var:ident $val:tt) $($bindings:tt)+) $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        lisp!((let ($($bindings)+) $($body)*))
    }};
    ((let (($var:ident $val:tt) $($bindings:tt)+) $($body:tt)*)) => {{
        let $var = lisp!($val);
        lisp!((let ($($bindings)+) $($body)*))
    }};
    ((let ((mut $var:ident $val:tt)) $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        $(lisp!($body));*
    }};
    ((let ((mut $var:ident $val:tt)) $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        $(lisp!($body));*
    }};
    ((let (($var:ident $val:tt)) $($body:tt)*)) => {{
        let $var = lisp!($val);
        $(lisp!($body));*
    }};
    ((:= $var:ident $val:tt)) => {
        $var = lisp!($val);
    };

    // escape hatch
    ((rust $body:block)) => {
        { $body }
    };

    // list parsing
    (($($elem:tt)*)) => {
        lisp!(@list $($elem),*)
    };

    // parsers for unary and binary operators
    (@list -,    $arg:tt   ) => { lisp!(@unary  _neg,   $arg   ) };
    (@list !,    $arg:tt   ) => { lisp!(@unary  _not,   $arg   ) };
    (@list +,  $($arg:tt),*) => { lisp!(@binary _add, $($arg),*) };
    (@list &,  $($arg:tt),*) => { lisp!(@binary _and, $($arg),*) };
    (@list |,  $($arg:tt),*) => { lisp!(@binary _or,  $($arg),*) };
    (@list ^,  $($arg:tt),*) => { lisp!(@binary _xor, $($arg),*) };
    (@list /,  $($arg:tt),*) => { lisp!(@binary _div, $($arg),*) };
    (@list *,  $($arg:tt),*) => { lisp!(@binary _mul, $($arg),*) };
    (@list %,  $($arg:tt),*) => { lisp!(@binary _rem, $($arg),*) };
    (@list <<, $($arg:tt),*) => { lisp!(@binary _shl, $($arg),*) };
    (@list >>, $($arg:tt),*) => { lisp!(@binary _shr, $($arg),*) };
    (@list -,  $($arg:tt),*) => { lisp!(@binary _sub, $($arg),*) };
    (@list ==, $($arg:tt),*) => { lisp!(@binary _eq,  $($arg),*) };
    (@list !=, $($arg:tt),*) => { lisp!(@binary _ne,  $($arg),*) };
    (@list >,  $($arg:tt),*) => { lisp!(@binary _gt,  $($arg),*) };
    (@list <,  $($arg:tt),*) => { lisp!(@binary _lt,  $($arg),*) };
    (@list >=, $($arg:tt),*) => { lisp!(@binary _ge,  $($arg),*) };
    (@list <=, $($arg:tt),*) => { lisp!(@binary _le,  $($arg),*) };

    // generically turn unary/binary operators into function calls
    // binary operators can be used as n-ary operators through @reduce
    (@unary  $op:ident, $a:tt)        => { lisp!(@list $op, $a)     };
    (@binary $op:ident, $a:tt, $b:tt) => { lisp!(@list $op, $a, $b) };
    (@binary $op:ident, $a:tt, $b:tt, $($rest:tt),+) =>
                                               { lisp!(@reduce $op,
                                                       ($op $a $b),
                                                       $($rest),+) };

    // reduce implementation
    // TODO external entry point for @reduce
    (@reduce $op:ident, $acc:tt)                       => { lisp!($acc)          };
    (@reduce $op:ident, $acc:tt, $a:tt)                => { lisp!(@reduce $op,
                                                                  ($op $acc $a)) };
    (@reduce $op:ident, $acc:tt, $a:tt, $($rest:tt),+) => { lisp!(@reduce $op,
                                                                  ($op $acc $a),
                                                                  $($rest),+)    };
    // ns form helpers
    (@krate $(^$attr:meta)* $krate:ident) => {
        $(#[$attr:meta])*
        extern crate $krate;
    };
    (@krate $(^$attr:meta)* ($krate:ident $alias:ident)) => {
        $(#[$attr:meta])*
        extern crate $krate as $alias;
    };
    (@uze ($($head:ident)*)) => { use $($head)::*; };
    (@uze ($($head:ident)* { $($multiple:ident)* })) => {
        lisp!(@uze mult ($($head)*) { $($multiple)* });
    };
    (@uze mult $head:tt { $($multiple:ident)* }) => {
        $(lisp!(@uze mult out $head $multiple);)*
    };
    (@uze mult out ($($head:ident)*) $multiple:ident) => {
        use $($head)::*::$multiple;
    };

    // macro calls
    (@list $mac:ident, !) => {
        $mac!()
    };
    (@list $mac:ident, !, $($arg:tt),*) => {
        $mac!($(lisp!($arg)),*)
    };

    // struct constructors
    (@list $name:ident, ., $(($member:ident $val:tt)),*) => {
        $name { $($member: lisp!($val))* }
    };

    // function calls
    (@list $name:expr) => {
        lisp!($name)()
    };
    (@list $name:expr, $($arg:tt),*) => {
        lisp!($name)($(lisp!($arg)),*)
    };

    // one expression
    ($e:expr) => ($e);
}
<commit_msg>use square brackets for<commit_after>#![no_std]

pub mod prelude;

// TODO documentation
// TODO attributes
// TODO MACROS
#[macro_export] macro_rules! lisp {
    // empty
    () => (());
    (()) => (());

    // special forms
    ((ns $($ns_form:tt)*) $($body:tt)*) => {
        $(lisp!($ns_form);)*
        $(lisp!($body);)*
    };
    ((extern [$($krate:tt)*])) => {
        $(lisp!(@krate $krate);)*
    };
    ((use [$($uze:tt)*])) => {
        $(lisp!(@uze $uze);)*
    };
    ((lambda ($($argn:ident)*) $($body:tt)*)) => {
        // regular lambda
        |$($argn),*| { $(lisp!($body));* }
    };
    ((lambda (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {
        // regular lambda
        |$($argn:$argt),*| -> $ret { $(lisp!($body));* }
    };
    ((lambda $s:ident (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {{
        // recursive lambda
        // $s MUST NOT be "self"
        // recurse by calling ($s ...)
        // FIXME recursive lambdas can't capture variables

        lisp!((rust { fn $s($($argn: $argt),*) -> $ret { $(lisp!($body));* } $s }))
    }};
    ((defn $name:ident () $($body:tt)*)) => {
        fn $name() {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([($selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([(&$selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name(&$selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([(&mut $selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name(&mut $selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([($selph:ident: Box<Self>) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($selph: Box<Self> $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([$(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($($argn:$argt),*) -> $ret {
            $(lisp!($body));*
        }
    };

    ((defstruct $name:ident $(($typ:ty))*)) => {
        struct $name($($typ),*);
    };
    ((defstruct $name:ident $(($field:ident $typ:ty))*)) => {
        struct $name { $($field: $typ),* }
    };
    ((defstruct $name:ident <$($gen:ident)*>)) => {
        struct $name<$($gen),*>;
    };
    ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($typ:ty))*)) => {
        struct $name<$($gen),*>($($typ),*) where $($wty: $($wtr)*),*;
    };
    ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($field:ident $typ:ty))*)) => {
        struct $name<$($gen),*> where $($wty: $($wtr)*),* { $($field: $typ),* }
    };

    ((deftype $name:ident $typ:ty)) => { type $name = $typ; };
    ((deftype $name:ident <$($gen:ident)*> $typ:ty)) => { type $name<$($gen),*> = $typ; };

    ((defimpl ($trate:ty) (for $typ:ty) $($body:tt)*)) => {
        impl $trate for $typ {
            $(lisp!($body);)*
        }
    };
    ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) (where $(($wty:ident $($wtr:tt)*))*) $($body:tt)*)) => {
        impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* {
            $(lisp!($body);)*
        }
    };
    ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) $($body:tt)*)) => {
        impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* {
            $(lisp!($body);)*
        }
    };

    ((if $cond:tt $yes:tt $no:tt)) => {
        if lisp!($cond) { lisp!($yes) } else { lisp!($no) }
    };
    ((while $cond:tt $($body:tt)*)) => {
        while lisp!($cond) { $(lisp!($body));* }
    };
    // TODO for loops
    ((match $var:tt $(($cond:pat) $arm:tt)*)) => {
        match lisp!($var) {
            $($cond => lisp!($arm)),*
        }
    };
    ((do $($stmts:tt)*)) => {{
        $(lisp!($stmts));*
    }};

    // variables
    ((let [] $($body:tt)*)) => {{
        $(lisp!($body));*
    }};
    ((let [mut $var:ident $val:tt $($bindings:tt)*] $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        lisp!((let [$($bindings)*] $($body)*))
    }};
    ((let [$var:ident $val:tt $($bindings:tt)*] $($body:tt)*)) => {{
        let $var = lisp!($val);
        lisp!((let [$($bindings)*] $($body)*))
    }};
    ((:= $var:ident $val:tt)) => {
        $var = lisp!($val);
    };

    // escape hatch
    ((rust $body:block)) => {
        { $body }
    };

    // list parsing
    (($($elem:tt)*)) => {
        lisp!(@list $($elem),*)
    };

    // parsers for unary and binary operators
    (@list -,    $arg:tt   ) => { lisp!(@unary  _neg,   $arg   ) };
    (@list !,    $arg:tt   ) => { lisp!(@unary  _not,   $arg   ) };
    (@list +,  $($arg:tt),*) => { lisp!(@binary _add, $($arg),*) };
    (@list &,  $($arg:tt),*) => { lisp!(@binary _and, $($arg),*) };
    (@list |,  $($arg:tt),*) => { lisp!(@binary _or,  $($arg),*) };
    (@list ^,  $($arg:tt),*) => { lisp!(@binary _xor, $($arg),*) };
    (@list /,  $($arg:tt),*) => { lisp!(@binary _div, $($arg),*) };
    (@list *,  $($arg:tt),*) => { lisp!(@binary _mul, $($arg),*) };
    (@list %,  $($arg:tt),*) => { lisp!(@binary _rem, $($arg),*) };
    (@list <<, $($arg:tt),*) => { lisp!(@binary _shl, $($arg),*) };
    (@list >>, $($arg:tt),*) => { lisp!(@binary _shr, $($arg),*) };
    (@list -,  $($arg:tt),*) => { lisp!(@binary _sub, $($arg),*) };
    (@list ==, $($arg:tt),*) => { lisp!(@binary _eq,  $($arg),*) };
    (@list !=, $($arg:tt),*) => { lisp!(@binary _ne,  $($arg),*) };
    (@list >,  $($arg:tt),*) => { lisp!(@binary _gt,  $($arg),*) };
    (@list <,  $($arg:tt),*) => { lisp!(@binary _lt,  $($arg),*) };
    (@list >=, $($arg:tt),*) => { lisp!(@binary _ge,  $($arg),*) };
    (@list <=, $($arg:tt),*) => { lisp!(@binary _le,  $($arg),*) };

    // generically turn unary/binary operators into function calls
    // binary operators can be used as n-ary operators through @reduce
    (@unary  $op:ident, $a:tt)        => { lisp!(@list $op, $a)     };
    (@binary $op:ident, $a:tt, $b:tt) => { lisp!(@list $op, $a, $b) };
    (@binary $op:ident, $a:tt, $b:tt, $($rest:tt),+) =>
                                               { lisp!(@reduce $op,
                                                       ($op $a $b),
                                                       $($rest),+) };

    // reduce implementation
    // TODO external entry point for @reduce
    (@reduce $op:ident, $acc:tt)                       => { lisp!($acc)          };
    (@reduce $op:ident, $acc:tt, $a:tt)                => { lisp!(@reduce $op,
                                                                  ($op $acc $a)) };
    (@reduce $op:ident, $acc:tt, $a:tt, $($rest:tt),+) => { lisp!(@reduce $op,
                                                                  ($op $acc $a),
                                                                  $($rest),+)    };
    // ns form helpers
    (@krate $(^$attr:meta)* $krate:ident) => {
        $(#[$attr:meta])*
        extern crate $krate;
    };
    (@krate $(^$attr:meta)* ($krate:ident $alias:ident)) => {
        $(#[$attr:meta])*
        extern crate $krate as $alias;
    };
    (@uze ($($head:ident)*)) => { use $($head)::*; };
    (@uze ($($head:ident)* { $($multiple:ident)* })) => {
        lisp!(@uze mult ($($head)*) { $($multiple)* });
    };
    (@uze mult $head:tt { $($multiple:ident)* }) => {
        $(lisp!(@uze mult out $head $multiple);)*
    };
    (@uze mult out ($($head:ident)*) $multiple:ident) => {
        use $($head)::*::$multiple;
    };

    // macro calls
    (@list $mac:ident, !) => {
        $mac!()
    };
    (@list $mac:ident, !, $($arg:tt),*) => {
        $mac!($(lisp!($arg)),*)
    };

    // struct constructors
    (@list $name:ident, ., $(($member:ident $val:tt)),*) => {
        $name { $($member: lisp!($val))* }
    };

    // function calls
    (@list $name:expr) => {
        lisp!($name)()
    };
    (@list $name:expr, $($arg:tt),*) => {
        lisp!($name)($(lisp!($arg)),*)
    };

    // one expression
    ($e:expr) => ($e);
}
<|endoftext|>