<commit_before>//! [![github]](https://github.com/dtolnay/ryu) [![crates-io]](https://crates.io/crates/ryu) [![docs-rs]](https://docs.rs/ryu)
//!
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K
//!
//!

//!
//! Pure Rust implementation of Ryū, an algorithm to quickly convert floating
//! point numbers to decimal strings.
//!
//! The PLDI'18 paper [*Ryū: fast float-to-string conversion*][paper] by Ulf
//! Adams includes a complete correctness proof of the algorithm. The paper is
//! available under the creative commons CC-BY-SA license.
//!
//! This Rust implementation is a line-by-line port of Ulf Adams' implementation
//! in C, [https://github.com/ulfjack/ryu][upstream].
//!
//! [paper]: https://dl.acm.org/citation.cfm?id=3192369
//! [upstream]: https://github.com/ulfjack/ryu
//!
//! # Example
//!
//! ```
//! fn main() {
//!     let mut buffer = ryu::Buffer::new();
//!     let printed = buffer.format(1.234);
//!     assert_eq!(printed, "1.234");
//! }
//! ```
//!
//! ## Performance
//!
//! You can run upstream's benchmarks with:
//!
//! ```console
//! $ git clone https://github.com/ulfjack/ryu c-ryu
//! $ cd c-ryu
//! $ bazel run -c opt //ryu/benchmark
//! ```
//!
//! And the same benchmark against our implementation with:
//!
//! ```console
//! $ git clone https://github.com/dtolnay/ryu rust-ryu
//! $ cd rust-ryu
//! $ cargo run --example upstream_benchmark --release
//! ```
//!
//! These benchmarks measure the average time to print a 32-bit float and average
//! time to print a 64-bit float, where the inputs are distributed as uniform random
//! bit patterns 32 and 64 bits wide.
//!
//! The upstream C code, the unsafe direct Rust port, and the safe pretty Rust API
//! all perform the same, taking around 21 nanoseconds to format a 32-bit float and
//! 31 nanoseconds to format a 64-bit float.
//!
//! There is also a Rust-specific benchmark comparing this implementation to the
//! standard library which you can run with:
//!
//! ```console
//! $ cargo bench
//! ```
//!
//! The benchmark shows Ryū approximately 4-10x faster than the standard library
//! across a range of f32 and f64 inputs. Measurements are in nanoseconds per
//! iteration; smaller is better.
//!
//! | type=f32 | 0.0  | 0.1234 | 2.718281828459045 | f32::MAX |
//! |:--------:|:----:|:------:|:-----------------:|:--------:|
//! | RYU      | 3ns  | 28ns   | 23ns              | 22ns     |
//! | STD      | 40ns | 106ns  | 128ns             | 110ns    |
//!
//! | type=f64 | 0.0  | 0.1234 | 2.718281828459045 | f64::MAX |
//! |:--------:|:----:|:------:|:-----------------:|:--------:|
//! | RYU      | 3ns  | 50ns   | 35ns              | 32ns     |
//! | STD      | 39ns | 105ns  | 128ns             | 202ns    |
//!
//! ## Formatting
//!
//! This library tends to produce more human-readable output than the standard
//! library's to\_string, which never uses scientific notation. Here are two
//! examples:
//!
//! - *ryu:* 1.23e40, *std:* 12300000000000000000000000000000000000000
//! - *ryu:* 1.23e-40, *std:* 0.000000000000000000000000000000000000000123
//!
//! Both libraries print short decimals such as 0.0000123 without scientific
//! notation.

#![no_std]
#![doc(html_root_url = "https://docs.rs/ryu/1.0.5")]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(
    feature = "cargo-clippy",
    allow(cast_lossless, many_single_char_names, unreadable_literal,)
)]

mod buffer;
mod common;
mod d2s;
#[cfg(not(feature = "small"))]
mod d2s_full_table;
mod d2s_intrinsics;
#[cfg(feature = "small")]
mod d2s_small_table;
mod digit_table;
mod f2s;
mod f2s_intrinsics;
mod pretty;

pub use crate::buffer::{Buffer, Float};

/// Unsafe functions that mirror the API of the C implementation of Ryū.
pub mod raw {
    pub use crate::pretty::{format32, format64};
}
<commit_msg>Update to tool attrs<commit_after>//! [![github]](https://github.com/dtolnay/ryu) [![crates-io]](https://crates.io/crates/ryu) [![docs-rs]](https://docs.rs/ryu)
//!
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K
//!
//!

//!
//! Pure Rust implementation of Ryū, an algorithm to quickly convert floating
//! point numbers to decimal strings.
//!
//! The PLDI'18 paper [*Ryū: fast float-to-string conversion*][paper] by Ulf
//! Adams includes a complete correctness proof of the algorithm. The paper is
//! available under the creative commons CC-BY-SA license.
//!
//! This Rust implementation is a line-by-line port of Ulf Adams' implementation
//! in C, [https://github.com/ulfjack/ryu][upstream].
//!
//! [paper]: https://dl.acm.org/citation.cfm?id=3192369
//! [upstream]: https://github.com/ulfjack/ryu
//!
//! # Example
//!
//! ```
//! fn main() {
//!     let mut buffer = ryu::Buffer::new();
//!     let printed = buffer.format(1.234);
//!     assert_eq!(printed, "1.234");
//! }
//! ```
//!
//! ## Performance
//!
//! You can run upstream's benchmarks with:
//!
//! ```console
//! $ git clone https://github.com/ulfjack/ryu c-ryu
//! $ cd c-ryu
//! $ bazel run -c opt //ryu/benchmark
//! ```
//!
//! And the same benchmark against our implementation with:
//!
//! ```console
//! $ git clone https://github.com/dtolnay/ryu rust-ryu
//! $ cd rust-ryu
//! $ cargo run --example upstream_benchmark --release
//! ```
//!
//! These benchmarks measure the average time to print a 32-bit float and average
//! time to print a 64-bit float, where the inputs are distributed as uniform random
//! bit patterns 32 and 64 bits wide.
//!
//! The upstream C code, the unsafe direct Rust port, and the safe pretty Rust API
//! all perform the same, taking around 21 nanoseconds to format a 32-bit float and
//! 31 nanoseconds to format a 64-bit float.
//!
//! There is also a Rust-specific benchmark comparing this implementation to the
//! standard library which you can run with:
//!
//! ```console
//! $ cargo bench
//! ```
//!
//! The benchmark shows Ryū approximately 4-10x faster than the standard library
//! across a range of f32 and f64 inputs. Measurements are in nanoseconds per
//! iteration; smaller is better.
//!
//! | type=f32 | 0.0  | 0.1234 | 2.718281828459045 | f32::MAX |
//! |:--------:|:----:|:------:|:-----------------:|:--------:|
//! | RYU      | 3ns  | 28ns   | 23ns              | 22ns     |
//! | STD      | 40ns | 106ns  | 128ns             | 110ns    |
//!
//! | type=f64 | 0.0  | 0.1234 | 2.718281828459045 | f64::MAX |
//! |:--------:|:----:|:------:|:-----------------:|:--------:|
//! | RYU      | 3ns  | 50ns   | 35ns              | 32ns     |
//! | STD      | 39ns | 105ns  | 128ns             | 202ns    |
//!
//! ## Formatting
//!
//! This library tends to produce more human-readable output than the standard
//! library's to\_string, which never uses scientific notation. Here are two
//! examples:
//!
//! - *ryu:* 1.23e40, *std:* 12300000000000000000000000000000000000000
//! - *ryu:* 1.23e-40, *std:* 0.000000000000000000000000000000000000000123
//!
//! Both libraries print short decimals such as 0.0000123 without scientific
//! notation.

#![no_std]
#![doc(html_root_url = "https://docs.rs/ryu/1.0.5")]
#![allow(
    clippy::cast_lossless,
    clippy::many_single_char_names,
    clippy::unreadable_literal
)]

mod buffer;
mod common;
mod d2s;
#[cfg(not(feature = "small"))]
mod d2s_full_table;
mod d2s_intrinsics;
#[cfg(feature = "small")]
mod d2s_small_table;
mod digit_table;
mod f2s;
mod f2s_intrinsics;
mod pretty;

pub use crate::buffer::{Buffer, Float};

/// Unsafe functions that mirror the API of the C implementation of Ryū.
pub mod raw {
    pub use crate::pretty::{format32, format64};
}
<|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.

//! Library for serializing the RSS web content syndication format
//!
//! # Examples
//!
//! ## Writing
//!
//! ```
//! use rss::{Channel, Item, Rss};
//!
//! let item = Item {
//!     title: Some(String::from("Ford hires Elon Musk as CEO")),
//!     pub_date: Some(String::from("01 Apr 2019 07:30:00 GMT")),
//!     description: Some(String::from("In an unprecedented move, Ford hires Elon Musk.")),
//!     ..Default::default()
//! };
//!
//! let channel = Channel {
//!     title: String::from("TechCrunch"),
//!     link: String::from("http://techcrunch.com"),
//!     description: String::from("The latest technology news and information on startups"),
//!     items: vec![item],
//!     ..Default::default()
//! };
//!
//! let rss = Rss(channel);
//!
//! let rss_string = rss.to_string();
//! ```
//!
//! ## Reading
//!
//! ```
//! use rss::Rss;
//!
//! let rss_str = r#"
//! <?xml version="1.0" encoding="UTF-8"?>
//! <rss version="2.0">
//!   <channel>
//!     <title>TechCrunch</title>
//!     <link>http://techcrunch.com</link>
//!     <description>The latest technology news and information on startups</description>
//!     <item>
//!       <title>Ford hires Elon Musk as CEO</title>
//!       <pubDate>01 Apr 2019 07:30:00 GMT</pubDate>
//!       <description>In an unprecedented move, Ford hires Elon Musk.</description>
//!     </item>
//!   </channel>
//! </rss>
//! "#;
//!
//! let rss = rss_str.parse::<Rss>().unwrap();
//! ```

mod category;
mod channel;
mod item;
mod text_input;

extern crate xml;

use std::ascii::AsciiExt;
use std::str::FromStr;

use xml::{Element, ElementBuilder, Parser, Xml};

pub use ::category::Category;
pub use ::channel::Channel;
pub use ::item::Item;
pub use ::text_input::TextInput;

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(elem: Element) -> Result<Self, &'static str>;
}

/// [RSS 2.0 Specification § What is RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default, Debug, Clone)]
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 FromStr for Rss {
    type Err = &'static str;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut parser = Parser::new();
        parser.feed_str(&s);

        let mut builder = ElementBuilder::new();

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

        Err("RSS read error")
    }
}

impl ToString for Rss {
    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
    }
}

#[cfg(test)]
mod test {
    use std::default::Default;
    use std::fs::File;
    use std::io::Read;
    use std::str::FromStr;
    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 mut rss_string = String::new();
        file.read_to_string(&mut rss_string).unwrap();
        let rss = Rss::from_str(&rss_string).unwrap();
        assert!(rss.to_string().len() > 0);
    }

    #[test]
    fn test_read_no_channels() {
        let rss_str = "<rss></rss>";
        assert!(Rss::from_str(rss_str).is_err());
    }

    #[test]
    fn test_read_one_channel_no_properties() {
        let rss_str = "\
            <rss>\
                <channel>\
                </channel>\
            </rss>";
        assert!(Rss::from_str(rss_str).is_err());
    }

    #[test]
    fn test_read_one_channel() {
        let rss_str = "\
            <rss>\
                <channel>\
                    <title>Hello world!</title>\
                    <description></description>\
                    <link></link>\
                </channel>\
            </rss>";
        let Rss(channel) = Rss::from_str(rss_str).unwrap();
        assert_eq!("Hello world!", channel.title);
    }

    #[test]
    fn test_read_text_input() {
        let rss_str = "\
            <rss>\
                <channel>\
                    <title></title>\
                    <description></description>\
                    <link></link>\
                    <textInput>\
                        <title>Foobar</title>\
                        <description></description>\
                        <name></name>\
                        <link></link>\
                    </textInput>\
                </channel>\
            </rss>";
        let Rss(channel) = Rss::from_str(rss_str).unwrap();
        assert_eq!("Foobar", channel.text_input.unwrap().title);
    }

    // Ensure reader ignores the PI XML node and continues to parse the RSS
    #[test]
    fn test_read_with_pinode() {
        let rss_str = "\
            <?xml version=\'1.0\' encoding=\'UTF-8\'?>\
            <rss>\
                <channel>\
                    <title>Title</title>\
                    <link></link>\
                    <description></description>\
                </channel>\
            </rss>";
        let Rss(channel) = Rss::from_str(rss_str).unwrap();
        assert_eq!("Title", channel.title);
    }
}
<commit_msg>Return Error instead of panicking<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.

//! Library for serializing the RSS web content syndication format
//!
//! # Examples
//!
//! ## Writing
//!
//! ```
//! use rss::{Channel, Item, Rss};
//!
//! let item = Item {
//!     title: Some(String::from("Ford hires Elon Musk as CEO")),
//!     pub_date: Some(String::from("01 Apr 2019 07:30:00 GMT")),
//!     description: Some(String::from("In an unprecedented move, Ford hires Elon Musk.")),
//!     ..Default::default()
//! };
//!
//! let channel = Channel {
//!     title: String::from("TechCrunch"),
//!     link: String::from("http://techcrunch.com"),
//!     description: String::from("The latest technology news and information on startups"),
//!     items: vec![item],
//!     ..Default::default()
//! };
//!
//! let rss = Rss(channel);
//!
//! let rss_string = rss.to_string();
//! ```
//!
//! ## Reading
//!
//! ```
//! use rss::Rss;
//!
//! let rss_str = r#"
//! <?xml version="1.0" encoding="UTF-8"?>
//! <rss version="2.0">
//!   <channel>
//!     <title>TechCrunch</title>
//!     <link>http://techcrunch.com</link>
//!     <description>The latest technology news and information on startups</description>
//!     <item>
//!       <title>Ford hires Elon Musk as CEO</title>
//!       <pubDate>01 Apr 2019 07:30:00 GMT</pubDate>
//!       <description>In an unprecedented move, Ford hires Elon Musk.</description>
//!     </item>
//!   </channel>
//! </rss>
//! "#;
//!
//! let rss = rss_str.parse::<Rss>().unwrap();
//! ```

mod category;
mod channel;
mod item;
mod text_input;

extern crate xml;

use std::ascii::AsciiExt;
use std::str::FromStr;

use xml::{Element, ElementBuilder, Parser, Xml};

pub use ::category::Category;
pub use ::channel::Channel;
pub use ::item::Item;
pub use ::text_input::TextInput;

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(elem: Element) -> Result<Self, &'static str>;
}

/// [RSS 2.0 Specification § What is RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default, Debug, Clone)]
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" {
            return Err("Top element is not <rss>, most likely not an RSS feed");
        }

        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 FromStr for Rss {
    type Err = &'static str;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut parser = Parser::new();
        parser.feed_str(&s);

        let mut builder = ElementBuilder::new();

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

        Err("RSS read error")
    }
}

impl ToString for Rss {
    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
    }
}

#[cfg(test)]
mod test {
    use std::default::Default;
    use std::fs::File;
    use std::io::Read;
    use std::str::FromStr;
    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 mut rss_string = String::new();
        file.read_to_string(&mut rss_string).unwrap();
        let rss = Rss::from_str(&rss_string).unwrap();
        assert!(rss.to_string().len() > 0);
    }

    #[test]
    fn test_read_no_channels() {
        let rss_str = "<rss></rss>";
        assert!(Rss::from_str(rss_str).is_err());
    }

    #[test]
    fn test_read_one_channel_no_properties() {
        let rss_str = "\
            <rss>\
                <channel>\
                </channel>\
            </rss>";
        assert!(Rss::from_str(rss_str).is_err());
    }

    #[test]
    fn test_read_one_channel() {
        let rss_str = "\
            <rss>\
                <channel>\
                    <title>Hello world!</title>\
                    <description></description>\
                    <link></link>\
                </channel>\
            </rss>";
        let Rss(channel) = Rss::from_str(rss_str).unwrap();
        assert_eq!("Hello world!", channel.title);
    }

    #[test]
    fn test_read_text_input() {
        let rss_str = "\
            <rss>\
                <channel>\
                    <title></title>\
                    <description></description>\
                    <link></link>\
                    <textInput>\
                        <title>Foobar</title>\
                        <description></description>\
                        <name></name>\
                        <link></link>\
                    </textInput>\
                </channel>\
            </rss>";
        let Rss(channel) = Rss::from_str(rss_str).unwrap();
        assert_eq!("Foobar", channel.text_input.unwrap().title);
    }

    // Ensure reader ignores the PI XML node and continues to parse the RSS
    #[test]
    fn test_read_with_pinode() {
        let rss_str = "\
            <?xml version=\'1.0\' encoding=\'UTF-8\'?>\
            <rss>\
                <channel>\
                    <title>Title</title>\
                    <link></link>\
                    <description></description>\
                </channel>\
            </rss>";
        let Rss(channel) = Rss::from_str(rss_str).unwrap();
        assert_eq!("Title", channel.title);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

pub use self::object::PyObject;
pub use self::typeobject::PyType;
pub use self::module::PyModule;

pub use self::string::{PyBytes, PyUnicode};
// Directly exporting self::string::PyString causes a compiler error?
#[cfg(feature="python27-sys")]
pub use self::string::PyBytes as PyString;
#[cfg(feature="python3-sys")]
pub use self::string::PyUnicode as PyString;

#[cfg(feature="python27-sys")]
pub use self::iterator::PyIterator;
pub use self::boolobject::PyBool;
pub use self::tuple::{PyTuple, NoArgs};
pub use self::dict::PyDict;
pub use self::list::PyList;
#[cfg(feature="python27-sys")]
pub use self::num::PyInt;
#[cfg(feature="python3-sys")]
pub use self::num::PyLong as PyInt;
pub use self::num::{PyLong, PyFloat};

/// Identity conversion: allows using existing `PyObject` instances where
/// `T: ToPyObject` is expected.
macro_rules! pyobject_to_pyobject(
    ($name: ident) => (
        impl <'p, 's> ::conversion::ToPyObject<'p> for $name<'s> {
            type ObjectType = $name<'p>;

            #[inline]
            fn to_py_object(&self, py: Python<'p>) -> $name<'p> {
                self.clone().into_py_object(py)
            }

            #[inline]
            fn into_py_object(self, _py: Python<'p>) -> $name<'p> {
                // Transmute the lifetime.
                // This is safe, because both lifetime variables represent the same lifetime:
                // that of the python GIL acquisition.
                unsafe { ::std::mem::transmute(self) }
            }

            #[inline]
            fn with_borrowed_ptr<F, R>(&self, _py: Python<'p>, f: F) -> R
              where F: FnOnce(*mut ffi::PyObject) -> R {
                f(self.as_ptr())
            }
        }
    )
);

macro_rules! pyobject_newtype(
    ($name: ident) => (
        /// Clone returns another reference to the Python object,
        /// thus incrementing the reference count by 1.
        impl <'p> Clone for $name<'p> {
            #[inline]
            fn clone(&self) -> Self {
                $name(self.0.clone())
            }
        }

        pyobject_to_pyobject!($name);

        impl <'p> ::python::PythonObject<'p> for $name<'p> {
            #[inline]
            fn as_object(&self) -> &::objects::object::PyObject<'p> {
                &self.0
            }

            #[inline]
            fn into_object(self) -> ::objects::object::PyObject<'p> {
                self.0
            }

            /// Unchecked downcast from PyObject to Self.
            /// Undefined behavior if the input object does not have the expected type.
            #[inline]
            unsafe fn unchecked_downcast_from(obj: ::objects::object::PyObject<'p>) -> Self {
                $name(obj)
            }

            /// Unchecked downcast from PyObject to Self.
            /// Undefined behavior if the input object does not have the expected type.
            #[inline]
            unsafe fn unchecked_downcast_borrow_from<'a>(obj: &'a ::objects::object::PyObject<'p>) -> &'a Self {
                ::std::mem::transmute(obj)
            }

            #[inline]
            fn python(&self) -> Python<'p> {
                self.0.python()
            }
        }
    );
    ($name: ident, $checkfunction: ident) => (
        pyobject_newtype!($name);

        impl <'p> ::python::PythonObjectWithCheckedDowncast<'p> for $name<'p> {
            #[inline]
            fn downcast_from(obj : ::objects::object::PyObject<'p>) -> Result<$name<'p>, ::python::PythonObjectDowncastError<'p>> {
                unsafe {
                    if ::ffi::$checkfunction(::python::ToPythonPointer::as_ptr(&obj)) != 0 {
                        Ok($name(obj))
                    } else {
                        Err(::python::PythonObjectDowncastError(::python::PythonObject::python(&obj)))
                    }
                }
            }

            #[inline]
            fn downcast_borrow_from<'a>(obj : &'a ::objects::object::PyObject<'p>) -> Result<&'a $name<'p>, ::python::PythonObjectDowncastError<'p>> {
                unsafe {
                    if ::ffi::$checkfunction(::python::ToPythonPointer::as_ptr(obj)) != 0 {
                        Ok(::std::mem::transmute(obj))
                    } else {
                        Err(::python::PythonObjectDowncastError(::python::PythonObject::python(obj)))
                    }
                }
            }
        }
    );
    ($name: ident, $checkfunction: ident, $typeobject: ident) => (
        pyobject_newtype!($name, $checkfunction);

        impl <'p> ::python::PythonObjectWithTypeObject<'p> for $name<'p> {
            #[inline]
            fn type_object(py: ::python::Python<'p>) -> ::objects::typeobject::PyType<'p> {
                unsafe { ::objects::typeobject::PyType::from_type_ptr(py, &mut ::ffi::$typeobject) }
            }
        }
    );
);

mod object;
mod typeobject;
mod module;
mod string;
mod dict;
#[cfg(feature="python27-sys")]
mod iterator;
mod boolobject;
mod tuple;
mod list;
mod num;
pub mod exc;

#[cfg(feature="python27-sys")]
pub mod oldstyle;

<commit_msg>Fix python 2.7 build<commit_after>// Copyright (c) 2015 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

pub use self::object::PyObject;
pub use self::typeobject::PyType;
pub use self::module::PyModule;

pub use self::string::{PyBytes, PyUnicode};
// Directly exporting self::string::PyString causes a compiler error?
#[cfg(feature="python27-sys")]
pub use self::string::PyBytes as PyString;
#[cfg(feature="python3-sys")]
pub use self::string::PyUnicode as PyString;

#[cfg(feature="python27-sys")]
pub use self::iterator::PyIterator;
pub use self::boolobject::PyBool;
pub use self::tuple::{PyTuple, NoArgs};
pub use self::dict::PyDict;
pub use self::list::PyList;
#[cfg(feature="python27-sys")]
pub use self::num::PyInt;
#[cfg(feature="python3-sys")]
pub use self::num::PyLong as PyInt;
pub use self::num::{PyLong, PyFloat};

/// Identity conversion: allows using existing `PyObject` instances where
/// `T: ToPyObject` is expected.
macro_rules! pyobject_to_pyobject(
    ($name: ident) => (
        impl <'p, 's> ::conversion::ToPyObject<'p> for $name<'s> {
            type ObjectType = $name<'p>;

            #[inline]
            fn to_py_object(&self, py: ::python::Python<'p>) -> $name<'p> {
                self.clone().into_py_object(py)
            }

            #[inline]
            fn into_py_object(self, _py: ::python::Python<'p>) -> $name<'p> {
                // Transmute the lifetime.
                // This is safe, because both lifetime variables represent the same lifetime:
                // that of the python GIL acquisition.
                unsafe { ::std::mem::transmute(self) }
            }

            #[inline]
            fn with_borrowed_ptr<F, R>(&self, _py: ::python::Python<'p>, f: F) -> R
              where F: FnOnce(*mut ffi::PyObject) -> R {
                f(self.as_ptr())
            }
        }
    )
);

macro_rules! pyobject_newtype(
    ($name: ident) => (
        /// Clone returns another reference to the Python object,
        /// thus incrementing the reference count by 1.
        impl <'p> Clone for $name<'p> {
            #[inline]
            fn clone(&self) -> Self {
                $name(self.0.clone())
            }
        }

        pyobject_to_pyobject!($name);

        impl <'p> ::python::PythonObject<'p> for $name<'p> {
            #[inline]
            fn as_object(&self) -> &::objects::object::PyObject<'p> {
                &self.0
            }

            #[inline]
            fn into_object(self) -> ::objects::object::PyObject<'p> {
                self.0
            }

            /// Unchecked downcast from PyObject to Self.
            /// Undefined behavior if the input object does not have the expected type.
            #[inline]
            unsafe fn unchecked_downcast_from(obj: ::objects::object::PyObject<'p>) -> Self {
                $name(obj)
            }

            /// Unchecked downcast from PyObject to Self.
            /// Undefined behavior if the input object does not have the expected type.
            #[inline]
            unsafe fn unchecked_downcast_borrow_from<'a>(obj: &'a ::objects::object::PyObject<'p>) -> &'a Self {
                ::std::mem::transmute(obj)
            }

            #[inline]
            fn python(&self) -> ::python::Python<'p> {
                self.0.python()
            }
        }
    );
    ($name: ident, $checkfunction: ident) => (
        pyobject_newtype!($name);

        impl <'p> ::python::PythonObjectWithCheckedDowncast<'p> for $name<'p> {
            #[inline]
            fn downcast_from(obj : ::objects::object::PyObject<'p>) -> Result<$name<'p>, ::python::PythonObjectDowncastError<'p>> {
                unsafe {
                    if ::ffi::$checkfunction(::python::ToPythonPointer::as_ptr(&obj)) != 0 {
                        Ok($name(obj))
                    } else {
                        Err(::python::PythonObjectDowncastError(::python::PythonObject::python(&obj)))
                    }
                }
            }

            #[inline]
            fn downcast_borrow_from<'a>(obj : &'a ::objects::object::PyObject<'p>) -> Result<&'a $name<'p>, ::python::PythonObjectDowncastError<'p>> {
                unsafe {
                    if ::ffi::$checkfunction(::python::ToPythonPointer::as_ptr(obj)) != 0 {
                        Ok(::std::mem::transmute(obj))
                    } else {
                        Err(::python::PythonObjectDowncastError(::python::PythonObject::python(obj)))
                    }
                }
            }
        }
    );
    ($name: ident, $checkfunction: ident, $typeobject: ident) => (
        pyobject_newtype!($name, $checkfunction);

        impl <'p> ::python::PythonObjectWithTypeObject<'p> for $name<'p> {
            #[inline]
            fn type_object(py: ::python::Python<'p>) -> ::objects::typeobject::PyType<'p> {
                unsafe { ::objects::typeobject::PyType::from_type_ptr(py, &mut ::ffi::$typeobject) }
            }
        }
    );
);

mod object;
mod typeobject;
mod module;
mod string;
mod dict;
#[cfg(feature="python27-sys")]
mod iterator;
mod boolobject;
mod tuple;
mod list;
mod num;
pub mod exc;

#[cfg(feature="python27-sys")]
pub mod oldstyle;

<|endoftext|>


<commit_before>extern crate nix;
extern crate rand;
extern crate time;
extern crate timely;
extern crate getopts;
extern crate graph_map;

use rand::{Rng, SeedableRng, StdRng};

#[cfg(linux)]
fn pin_to_core(core: usize) {
    let mut cpu_set = ::nix::sched::CpuSet::new();
    let tgt_cpu = index * cpu_stride;
    cpu_set.set(tgt_cpu);
    let result = ::nix::sched::sched_setaffinity(0, &cpu_set);
}

#[cfg(not(linux))]
fn pin_to_core(_core: usize) {

}

// pins the core in the process, which is a bit silly.
pub fn fetch_edges(index: usize, peers: usize) -> (Vec<(u32, u32)>, usize) {

    let mut opts = getopts::Options::new();
    opts.optopt("", "graph", "prefix of graph file", "FILE");
    opts.optopt("", "nodes", "number of nodes in a random graph", "NUM");
    opts.optopt("", "edges", "number of edges in a random graph", "NUM");
    opts.optopt("", "stride", "stride for CPU pinning, or zero for none", "NUM");

    let mut args = ::std::env::args().skip_while(|x| x != "--").collect::<Vec<_>>();
    args.remove(0);

    // this will assert if parsing fails. could be friendlier.
    let matches = opts.parse(args.into_iter()).ok().unwrap();

    // core pinning
    if let Some(stride) = matches.opt_str("stride") {
        if let Ok(cpu_stride) = stride.parse::<usize>() {
            if cpu_stride > 0 {
                pin_to_core(cpu_stride);
            }
        }
        else {
            println!("could not parse <{}> as a stride", stride);
        }
    }

    let mut nodes = 0;
    let mut edges = Vec::new();
    if let Some(filename) = matches.opt_str("graph") {

        let graph = graph_map::GraphMMap::new(&filename);
        nodes = graph.nodes();
        for node in 0..graph.nodes() {
            if node % peers == index {
                for &dest in graph.edges(node) {
                    edges.push((node as u32, dest));
                }
            }
        }

    }
    else {
        if let Some(node_cnt) = matches.opt_str("nodes").and_then(|x| x.parse::<usize>().ok()) {
            nodes = node_cnt;
            if let Some(edge_cnt) = matches.opt_str("edges").and_then(|x| x.parse::<usize>().ok()) {

                // rng is seeded with worker index.
                let seed: &[_] = &[1, 2, 3, index];
                let mut rng: StdRng = SeedableRng::from_seed(seed);

                for _index in 0..(edge_cnt / peers) {
                    edges.push((rng.gen_range(0, node_cnt as u32), rng.gen_range(0, node_cnt as u32)));
                }

            }
            else {
                println!("must specify --edges if not --graph")
            }
        }
        else {
            println!("must specify --nodes if not --graph")
        }
    }

    (edges, nodes)
}<commit_msg>fixed the pinning of cores<commit_after>extern crate nix;
extern crate rand;
extern crate time;
extern crate timely;
extern crate getopts;
extern crate graph_map;

use rand::{Rng, SeedableRng, StdRng};

#[cfg(target_os = "linux")]
fn pin_to_core(index:usize, core: usize) {
    let mut cpu_set = ::nix::sched::CpuSet::new();
    let tgt_cpu = index * core;
    cpu_set.set(tgt_cpu);
    let result = ::nix::sched::sched_setaffinity(0, &cpu_set);
}

#[cfg(not(target_os = "linux"))]
fn pin_to_core(_core: usize) {
   println!("not linux!");
}

// pins the core in the process, which is a bit silly.
pub fn fetch_edges(index: usize, peers: usize) -> (Vec<(u32, u32)>, usize) {

    let mut opts = getopts::Options::new();
    opts.optopt("", "graph", "prefix of graph file", "FILE");
    opts.optopt("", "nodes", "number of nodes in a random graph", "NUM");
    opts.optopt("", "edges", "number of edges in a random graph", "NUM");
    opts.optopt("", "stride", "stride for CPU pinning, or zero for none", "NUM");

    let mut args = ::std::env::args().skip_while(|x| x != "--").collect::<Vec<_>>();
    args.remove(0);

    // this will assert if parsing fails. could be friendlier.
    let matches = opts.parse(args.into_iter()).ok().unwrap();

    // core pinning
    if let Some(stride) = matches.opt_str("stride") {
        if let Ok(cpu_stride) = stride.parse::<usize>() {
            if cpu_stride > 0 {
                pin_to_core(index, cpu_stride);
            }
        }
        else {
            println!("could not parse <{}> as a stride", stride);
        }
    }

    let mut nodes = 0;
    let mut edges = Vec::new();
    if let Some(filename) = matches.opt_str("graph") {

        let graph = graph_map::GraphMMap::new(&filename);
        nodes = graph.nodes();
        for node in 0..graph.nodes() {
            if node % peers == index {
                for &dest in graph.edges(node) {
                    edges.push((node as u32, dest));
                }
            }
        }

    }
    else {
        if let Some(node_cnt) = matches.opt_str("nodes").and_then(|x| x.parse::<usize>().ok()) {
            nodes = node_cnt;
            if let Some(edge_cnt) = matches.opt_str("edges").and_then(|x| x.parse::<usize>().ok()) {

                // rng is seeded with worker index.
                let seed: &[_] = &[1, 2, 3, index];
                let mut rng: StdRng = SeedableRng::from_seed(seed);

                for _index in 0..(edge_cnt / peers) {
                    edges.push((rng.gen_range(0, node_cnt as u32), rng.gen_range(0, node_cnt as u32)));
                }

            }
            else {
                println!("must specify --edges if not --graph")
            }
        }
        else {
            println!("must specify --nodes if not --graph")
        }
    }

    (edges, nodes)
}
<|endoftext|>


<commit_before>#![cfg_attr(not(feature="use_std"), no_std)]

#[inline]
pub fn sign_extend(data: u32, size: u32) -> i32 {
    assert!(size > 0 && size <= 32);
    ((data << (32 - size)) as i32) >> (32 - size)
}

#[macro_export]
macro_rules! bits {
    ($val:expr, $low:expr => $hi:expr) => {{
        #[cfg(feature="use_std")]
        use ::std::mem::size_of_val;
        #[cfg(not(feature="use_std"))]
        use ::core::mem::size_of_val;

        let max_bit = size_of_val(&$val) * 8 - 1;
        $val << (max_bit - $hi) >> (max_bit - $hi + $low)
    }};
}

#[macro_export]
macro_rules! bit {
    ($val:expr, $bit:expr) => { bits!($val, $bit => $bit) };
}

#[macro_export]
macro_rules! bf {
    {$var:tt.$item:ident} => ($var.get($var.$item()));
    {$var:tt.$item:ident=$val:expr} => (
        let item = $var.$item();
        $var.set(item, $val)
    );
}

#[macro_export]
macro_rules! bitfield {
    ($name:ident: $ty:ty, { $($var_name:ident: $var_low:expr => $var_hi:expr),* }) => {
        #[derive(Clone, Copy, Default)]
        pub struct $name {
            val: $ty
        }

        impl $name {
            pub fn new(val: $ty) -> $name {
                $name {
                    val: val
                }
            }

            #[inline(always)]
            #[allow(dead_code)]
            pub fn raw(&self) -> $ty {
                self.val
            }

            #[inline(always)]
            #[allow(dead_code)]
            pub fn set_raw(&mut self, val: $ty) {
                self.val = val;
            }

            #[inline(always)]
            #[allow(dead_code)]
            pub fn get(&self, pos: (usize, usize)) -> $ty {
                bits!(self.val, pos.0 => pos.1)
            }

            #[inline(always)]
            #[allow(dead_code)]
            pub fn set(&mut self, pos: (usize, usize), val: $ty) {
                self.val ^= bits!(self.val, pos.0 => pos.1) << pos.0;
                self.val |= bits!(val, 0 => pos.1 - pos.0) << pos.0;
            }

            $(
                #[inline(always)]
                pub fn $var_name(&self) -> (usize, usize) {
                    ($var_low, $var_hi)
                }
            )*
        }

        #[cfg(feature="use_std")]
        impl ::std::fmt::Debug for $name {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                f.debug_struct(stringify!($name))
                    $(.field(stringify!($var_name), &bf!(self.$var_name)))*
                    .finish()
            }
        }
    };
}

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

    bitfield!(TestField: u8, {
        bottom: 0 => 5,
        top: 6 => 7
    });

    #[test]
    fn bitfield_get() {
        let mut test_field = TestField::new(0b10100000);
        assert_eq!(bf!(test_field.top), 0b10);
    }

    #[test]
    fn bitfield_set() {
        let mut test_field = TestField::new(0);
        bf!(test_field.top = 0b11);
        assert_eq!(test_field.raw(), 0b11000000);
    }

    #[test]
    fn bitfield_mod_recursive() {
        struct TFParent {
            tf: TestField
        }

        let mut tf_parent = TFParent { tf: TestField::new(0) };
        // Complex bitfield accesses must be surrounded by parentheses
        bf!((tf_parent.tf).top = 0b11);
        assert_eq!(tf_parent.tf.raw(), 0b11000000);
    }
}
<commit_msg>Correct conditional use of std/core<commit_after>#![cfg_attr(not(feature="use_std"), no_std)]

#[inline]
pub fn sign_extend(data: u32, size: u32) -> i32 {
    assert!(size > 0 && size <= 32);
    ((data << (32 - size)) as i32) >> (32 - size)
}

#[macro_export]
#[cfg(feature="use_std")]
macro_rules! bits {
    ($val:expr, $low:expr => $hi:expr) => {{
        let max_bit = ::std::mem::size_of_val(&$val) * 8 - 1;
        $val << (max_bit - $hi) >> (max_bit - $hi + $low)
    }};
}
#[macro_export]
#[cfg(not(feature="use_std"))]
macro_rules! bits {
    ($val:expr, $low:expr => $hi:expr) => {{
        let max_bit = ::core::mem::size_of_val(&$val) * 8 - 1;
        $val << (max_bit - $hi) >> (max_bit - $hi + $low)
    }};
}

#[macro_export]
macro_rules! bit {
    ($val:expr, $bit:expr) => { bits!($val, $bit => $bit) };
}

#[macro_export]
macro_rules! bf {
    {$var:tt.$item:ident} => ($var.get($var.$item()));
    {$var:tt.$item:ident=$val:expr} => (
        let item = $var.$item();
        $var.set(item, $val)
    );
}

#[macro_export]
#[cfg(feature="use_std")]
macro_rules! __bitfield_impl_debug__ {
    ($name:ident, { $($var_name:ident),* }) => {
        impl ::std::fmt::Debug for $name {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                f.debug_struct(stringify!($name))
                    $(.field(stringify!($var_name), &bf!(self.$var_name)))*
                    .finish()
            }
        }
    }
}

#[macro_export]
macro_rules! bitfield {
    ($name:ident: $ty:ty, { $($var_name:ident: $var_low:expr => $var_hi:expr),* }) => {
        #[derive(Clone, Copy, Default)]
        pub struct $name {
            val: $ty
        }

        impl $name {
            pub fn new(val: $ty) -> $name {
                $name {
                    val: val
                }
            }

            #[inline(always)]
            #[allow(dead_code)]
            pub fn raw(&self) -> $ty {
                self.val
            }

            #[inline(always)]
            #[allow(dead_code)]
            pub fn set_raw(&mut self, val: $ty) {
                self.val = val;
            }

            #[inline(always)]
            #[allow(dead_code)]
            pub fn get(&self, pos: (usize, usize)) -> $ty {
                bits!(self.val, pos.0 => pos.1)
            }

            #[inline(always)]
            #[allow(dead_code)]
            pub fn set(&mut self, pos: (usize, usize), val: $ty) {
                self.val ^= bits!(self.val, pos.0 => pos.1) << pos.0;
                self.val |= bits!(val, 0 => pos.1 - pos.0) << pos.0;
            }

            $(
                #[inline(always)]
                pub fn $var_name(&self) -> (usize, usize) {
                    ($var_low, $var_hi)
                }
            )*
        }

        __bitfield_impl_debug__!($name, { $($var_name),* });
    };
}

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

    bitfield!(TestField: u8, {
        bottom: 0 => 5,
        top: 6 => 7
    });

    #[test]
    fn bitfield_get() {
        let mut test_field = TestField::new(0b10100000);
        assert_eq!(bf!(test_field.top), 0b10);
    }

    #[test]
    fn bitfield_set() {
        let mut test_field = TestField::new(0);
        bf!(test_field.top = 0b11);
        assert_eq!(test_field.raw(), 0b11000000);
    }

    #[test]
    fn bitfield_mod_recursive() {
        struct TFParent {
            tf: TestField
        }

        let mut tf_parent = TFParent { tf: TestField::new(0) };
        // Complex bitfield accesses must be surrounded by parentheses
        bf!((tf_parent.tf).top = 0b11);
        assert_eq!(tf_parent.tf.raw(), 0b11000000);
    }
}
<|endoftext|>


<commit_before>use std::cmp::Eq;
use std::collections::HashMap;
use std::hash::Hash;

pub struct Graph<N, ND, ED> {
    nodes: HashMap<N, ND>,
    edges: HashMap<N, HashMap<N, ED>>,
}

impl<N, ND, ED> Graph<N, ND, ED>
    where N: Copy + Eq + Hash,
          ED: Copy
{
    fn new() -> Graph<N, ND, ED> {
        Graph {
            nodes: HashMap::new(),
            edges: HashMap::new(),
        }
    }

    fn add_node(&mut self, node: N, data: ND) {
        if self.nodes.contains_key(&node) {
            self.nodes.insert(node, data); // If the key already exists, data will be updated.
        } else {
            self.nodes.insert(node, data);
            self.edges.insert(node, HashMap::new());
        }
    }

    fn add_edge(&mut self, u: N, v: N, data: ED) {
        // Add nodes.
        // if !self.nodes.contains_key(&u) {
        //     let u_clone = u.clone();
        //     self.nodes.insert(u, None);
        //     self.edges.insert(u_clone, HashMap::new());
        // }
        // if !self.nodes.contains_key(&v) {
        //     let v_clone = v.clone();
        //     self.nodes.insert(v, None);
        //     self.edges.insert(v_clone, HashMap::new());
        // }

        // Add edges.
        self.edges
            .entry(u)
            .or_insert(HashMap::new())
            .insert(v, data);
        self.edges
            .entry(v)
            .or_insert(HashMap::new())
            .insert(u, data);
    }
}

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

    #[test]
    fn test_add_node() {
        let mut graph: Graph<&str, u32, u32> = Graph::new();

        graph.add_node("node1", 1);
        graph.add_node("node2", 2);
        graph.add_node("node1", 3);

        assert!(graph.nodes["node1"] == 3);
        assert!(graph.nodes["node2"] == 2);
    }

    #[test]
    fn test_add_edge() {
        let mut graph: Graph<&str, u32, u32> = Graph::new();

        graph.add_node("node1", 1);
        graph.add_node("node2", 2);
        graph.add_node("node3", 3);

        graph.add_edge("node1", "node2", 10);
        graph.add_edge("node2", "node3", 20);

        assert!(graph.edges["node1"]["node2"] == 10);
        assert!(graph.edges["node2"]["node3"] == 20);
    }
}
<commit_msg>Make data optional.<commit_after>use std::cmp::Eq;
use std::collections::HashMap;
use std::hash::Hash;

pub struct Graph<N, ND, ED> {
    nodes: HashMap<N, Option<ND>>,
    edges: HashMap<N, HashMap<N, Option<ED>>>,
}

impl<N, ND, ED> Graph<N, ND, ED>
    where N: Copy + Eq + Hash,
          ED: Copy
{
    fn new() -> Graph<N, ND, ED> {
        Graph {
            nodes: HashMap::new(),
            edges: HashMap::new(),
        }
    }

    fn add_node(&mut self, node: N, data: Option<ND>) {
        if self.nodes.contains_key(&node) {
            self.nodes.insert(node, data); // If the key already exists, data will be updated.
        } else {
            self.nodes.insert(node, data);
            self.edges.insert(node, HashMap::new());
        }
    }

    fn add_edge(&mut self, u: N, v: N, data: Option<ED>) {
        // Add nodes.
        if !self.nodes.contains_key(&u) {
            self.nodes.insert(u, None);
            self.edges.insert(u, HashMap::new());
        }
        if !self.nodes.contains_key(&v) {
            self.nodes.insert(v, None);
            self.edges.insert(v, HashMap::new());
        }

        // Add edges.
        self.edges
            .entry(u)
            .or_insert(HashMap::new())
            .insert(v, data);
        self.edges
            .entry(v)
            .or_insert(HashMap::new())
            .insert(u, data);
    }
}

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

    #[test]
    fn test_add_node() {
        let mut graph: Graph<&str, u32, u32> = Graph::new();

        graph.add_node("node1", Some(1));
        graph.add_node("node1", Some(2));
        graph.add_node("node2", None);

        assert!(graph.nodes["node1"] == Some(2));
        assert!(graph.nodes["node2"] == None);
    }

    #[test]
    fn test_add_edge() {
        let mut graph: Graph<&str, u32, u32> = Graph::new();

        graph.add_edge("node1", "node2", Some(10));
        graph.add_edge("node1", "node2", Some(20));
        graph.add_edge("node2", "node3", None);

        assert!(graph.edges["node1"]["node2"] == Some(20));
        assert!(graph.edges["node2"]["node3"] == None);
    }
}
<|endoftext|>


<commit_before>//! DNS resolvers built on [`c-ares`](https://c-ares.org), for asynchronous DNS requests.
//!
//! This crate provides three resolver types - the `Resolver`, the `FutureResolver`, and the
//! `BlockingResolver`:
//!
//! * The `Resolver` is the thinnest wrapper around the underlying `c-ares` library.  It returns
//! answers via callbacks.  The other resolvers are built on top of this.
//!
//! * The `FutureResolver` returns answers as `std::future::Future`s.
//!
//! * The `BlockingResolver` isn't asynchronous at all - as the name suggests, it blocks until the
//! lookup completes.
//!
//! On all resolvers:
//!
//! -  methods like `query_xxx` correspond to the `c-ares` function `ares_query`, which "initiates
//! a single-question DNS query".
//!
//! -  methods like `search_xxx` correspond to the `c-ares` function `ares_search`, which
//! "initiates a series of single-question DNS queries ... using the channel's search domains as
//! well as a host alias file given by the HOSTALIAS environment variable".
//!
//! See [`c-ares` documentation](https://c-ares.org/docs.html) for more details.
//!
//! # Example
//!
//! ```rust
//! extern crate c_ares_resolver;
//! extern crate futures_executor;
//! use futures_executor::block_on;
//!
//! fn main() {
//!     let resolver = c_ares_resolver::FutureResolver::new().unwrap();
//!     let query = resolver.query_a("google.com");
//!     let response = block_on(query);
//!     match response {
//!         Ok(result) => println!("{}", result),
//!         Err(e) => println!("Lookup failed with error '{}'", e)
//!     }
//! }
//! ```
//!
//! Further examples showing how to use the library can be found
//! [here](https://github.com/dimbleby/c-ares-resolver/tree/master/examples).
#![deny(missing_docs)]
extern crate c_ares;
extern crate crossbeam_channel;
extern crate futures_channel;
extern crate polling;

mod blockingresolver;
mod error;
mod eventloop;
mod futureresolver;
mod host;
mod nameinfo;
mod resolver;

#[cfg(test)]
mod tests;

pub use crate::blockingresolver::BlockingResolver;
pub use crate::error::Error;
pub use crate::futureresolver::{CAresFuture, FutureResolver};
pub use crate::host::HostResults;
pub use crate::nameinfo::NameInfoResult;
pub use crate::resolver::{Options, Resolver};
<commit_msg>modernize extern crate<commit_after>//! DNS resolvers built on [`c-ares`](https://c-ares.org), for asynchronous DNS requests.
//!
//! This crate provides three resolver types - the `Resolver`, the `FutureResolver`, and the
//! `BlockingResolver`:
//!
//! * The `Resolver` is the thinnest wrapper around the underlying `c-ares` library.  It returns
//! answers via callbacks.  The other resolvers are built on top of this.
//!
//! * The `FutureResolver` returns answers as `std::future::Future`s.
//!
//! * The `BlockingResolver` isn't asynchronous at all - as the name suggests, it blocks until the
//! lookup completes.
//!
//! On all resolvers:
//!
//! -  methods like `query_xxx` correspond to the `c-ares` function `ares_query`, which "initiates
//! a single-question DNS query".
//!
//! -  methods like `search_xxx` correspond to the `c-ares` function `ares_search`, which
//! "initiates a series of single-question DNS queries ... using the channel's search domains as
//! well as a host alias file given by the HOSTALIAS environment variable".
//!
//! See [`c-ares` documentation](https://c-ares.org/docs.html) for more details.
//!
//! # Example
//!
//! ```rust
//! extern crate c_ares_resolver;
//! extern crate futures_executor;
//! use futures_executor::block_on;
//!
//! fn main() {
//!     let resolver = c_ares_resolver::FutureResolver::new().unwrap();
//!     let query = resolver.query_a("google.com");
//!     let response = block_on(query);
//!     match response {
//!         Ok(result) => println!("{}", result),
//!         Err(e) => println!("Lookup failed with error '{}'", e)
//!     }
//! }
//! ```
//!
//! Further examples showing how to use the library can be found
//! [here](https://github.com/dimbleby/c-ares-resolver/tree/master/examples).
#![deny(missing_docs)]

mod blockingresolver;
mod error;
mod eventloop;
mod futureresolver;
mod host;
mod nameinfo;
mod resolver;

#[cfg(test)]
mod tests;

pub use crate::blockingresolver::BlockingResolver;
pub use crate::error::Error;
pub use crate::futureresolver::{CAresFuture, FutureResolver};
pub use crate::host::HostResults;
pub use crate::nameinfo::NameInfoResult;
pub use crate::resolver::{Options, Resolver};
<|endoftext|>


<commit_before>#![feature(no_std, core, core_prelude, core_slice_ext, custom_derive)]
#![no_std]

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

#[macro_use]
extern crate core;
#[macro_use]
extern crate klogger;

#[cfg(test)]
#[macro_use]
extern crate std;

pub mod elf;
use core::prelude::*;
use core::fmt;
use core::mem::{transmute, size_of};

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

/// Abstract representation of a loadable ELF binary.
pub struct ElfBinary {
    name: &'static str,
    region: &'static [u8],
    header: &'static elf::FileHeader,
}

impl fmt::Debug for ElfBinary {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} {}", self.name, self.header)
    }
}

/// Verify that memory region starts with a correct ELF magic.
fn valid_elf_magic(region: &'static [u8]) -> bool {
    region[0] == elf::ELFMAG0 &&
    region[1] == elf::ELFMAG1 &&
    region[2] == elf::ELFMAG2 &&
    region[3] == elf::ELFMAG3
}

/// Implement this for ELF loading.
pub trait ElfLoader {
    /// Allocates a virtual region of size amount of bytes.
    fn allocate(&mut self, base: VAddr, size: usize, flags: elf::ProgFlag);

    /// Copies the region into the base.
    fn load(&mut self, base: VAddr, region: &'static [u8]);
}

impl ElfBinary {

    /// Create a new ElfBinary.
    /// Makes sure that the provided region has valid ELF magic byte sequence
    /// and is big enough to contain at least the ELF file header
    /// otherwise it will return None.
    pub fn new(name: &'static str, region: &'static [u8]) -> Option<ElfBinary> {
        if region.len() >= size_of::<elf::FileHeader>() && valid_elf_magic(region) {
            let header: &elf::FileHeader = unsafe { transmute(&region[0]) };
            return Some(ElfBinary { name: name, region: region, header: header });
        }

        None
    }

    /// Print the program headers.
    pub fn print_program_headers(&self) {
        for p in self.program_headers() {
            //log!("pheader = {}", p);
        }
    }

    /// Create a slice of the program headers.
    fn program_headers(&self) -> &[elf::ProgramHeader] {
        let correct_header_size = self.header.phentsize as usize == size_of::<elf::ProgramHeader>();
        let pheader_region_size = self.header.phoff as usize + self.header.phnum as usize * self.header.phentsize as usize;
        let big_enough_region = self.region.len() >= pheader_region_size;

        if !correct_header_size || !big_enough_region {
            return &[];
        }

        let pheaders: &[elf::ProgramHeader] = unsafe {
            core::slice::from_raw_parts(
                transmute(&self.region[self.header.phoff as usize]),
                self.header.phnum as usize)
        };
        return pheaders;
    }

    /// Can we load the binary on our platform?
    fn can_load(&self) -> bool {
        let correct_class = self.header.ident.class == elf::ELFCLASS64;
        let correct_elfversion = self.header.ident.version == elf::EV_CURRENT;
        let correct_data = self.header.ident.data == elf::ELFDATA2LSB;
        let correct_osabi = self.header.ident.osabi == elf::ELFOSABI_SYSV || self.header.ident.osabi == elf::ELFOSABI_LINUX;
        let correct_type = self.header.elftype == elf::ET_EXEC || self.header.elftype == elf::ET_DYN;
        let correct_machine = self.header.machine == elf::EM_X86_64;

        correct_class && correct_data && correct_elfversion && correct_machine && correct_osabi && correct_type
    }

    fn load_header(&self, p: &elf::ProgramHeader, loader: &mut ElfLoader) {
        let big_enough_region = self.region.len() >= (p.offset + p.filesz) as usize;
        if !big_enough_region {
            //log!("Unable to load {}", p);
            return;
        }

        loader.allocate(p.vaddr, p.memsz as usize, p.flags);
        let segment: &'static [u8] = unsafe {
            core::slice::from_raw_parts(
                transmute(&self.region[p.offset as usize]), p.filesz as usize)
        };
        loader.load(p.vaddr, segment);
    }

    pub fn load(&self, loader: &mut ElfLoader) {
        for p in self.program_headers() {
            let x = match p.progtype {
                elf::PT_LOAD => self.load_header(p, loader),
                _ => ()
            };
        }
    }

}
<commit_msg>Remove klogger crate.<commit_after>#![feature(no_std, core, core_prelude, core_slice_ext, custom_derive)]
#![no_std]

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

#[macro_use]
extern crate core;

#[cfg(test)]
#[macro_use]
extern crate std;

pub mod elf;
use core::prelude::*;
use core::fmt;
use core::mem::{transmute, size_of};

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

/// Abstract representation of a loadable ELF binary.
pub struct ElfBinary {
    name: &'static str,
    region: &'static [u8],
    header: &'static elf::FileHeader,
}

impl fmt::Debug for ElfBinary {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} {}", self.name, self.header)
    }
}

/// Verify that memory region starts with a correct ELF magic.
fn valid_elf_magic(region: &'static [u8]) -> bool {
    region[0] == elf::ELFMAG0 &&
    region[1] == elf::ELFMAG1 &&
    region[2] == elf::ELFMAG2 &&
    region[3] == elf::ELFMAG3
}

/// Implement this for ELF loading.
pub trait ElfLoader {
    /// Allocates a virtual region of size amount of bytes.
    fn allocate(&mut self, base: VAddr, size: usize, flags: elf::ProgFlag);

    /// Copies the region into the base.
    fn load(&mut self, base: VAddr, region: &'static [u8]);
}

impl ElfBinary {

    /// Create a new ElfBinary.
    /// Makes sure that the provided region has valid ELF magic byte sequence
    /// and is big enough to contain at least the ELF file header
    /// otherwise it will return None.
    pub fn new(name: &'static str, region: &'static [u8]) -> Option<ElfBinary> {
        if region.len() >= size_of::<elf::FileHeader>() && valid_elf_magic(region) {
            let header: &elf::FileHeader = unsafe { transmute(&region[0]) };
            return Some(ElfBinary { name: name, region: region, header: header });
        }

        None
    }

    /// Print the program headers.
    pub fn print_program_headers(&self) {
        for p in self.program_headers() {
            //log!("pheader = {}", p);
        }
    }

    /// Create a slice of the program headers.
    fn program_headers(&self) -> &[elf::ProgramHeader] {
        let correct_header_size = self.header.phentsize as usize == size_of::<elf::ProgramHeader>();
        let pheader_region_size = self.header.phoff as usize + self.header.phnum as usize * self.header.phentsize as usize;
        let big_enough_region = self.region.len() >= pheader_region_size;

        if !correct_header_size || !big_enough_region {
            return &[];
        }

        let pheaders: &[elf::ProgramHeader] = unsafe {
            core::slice::from_raw_parts(
                transmute(&self.region[self.header.phoff as usize]),
                self.header.phnum as usize)
        };
        return pheaders;
    }

    /// Can we load the binary on our platform?
    fn can_load(&self) -> bool {
        let correct_class = self.header.ident.class == elf::ELFCLASS64;
        let correct_elfversion = self.header.ident.version == elf::EV_CURRENT;
        let correct_data = self.header.ident.data == elf::ELFDATA2LSB;
        let correct_osabi = self.header.ident.osabi == elf::ELFOSABI_SYSV || self.header.ident.osabi == elf::ELFOSABI_LINUX;
        let correct_type = self.header.elftype == elf::ET_EXEC || self.header.elftype == elf::ET_DYN;
        let correct_machine = self.header.machine == elf::EM_X86_64;

        correct_class && correct_data && correct_elfversion && correct_machine && correct_osabi && correct_type
    }

    fn load_header(&self, p: &elf::ProgramHeader, loader: &mut ElfLoader) {
        let big_enough_region = self.region.len() >= (p.offset + p.filesz) as usize;
        if !big_enough_region {
            //log!("Unable to load {}", p);
            return;
        }

        loader.allocate(p.vaddr, p.memsz as usize, p.flags);
        let segment: &'static [u8] = unsafe {
            core::slice::from_raw_parts(
                transmute(&self.region[p.offset as usize]), p.filesz as usize)
        };
        loader.load(p.vaddr, segment);
    }

    pub fn load(&self, loader: &mut ElfLoader) {
        for p in self.program_headers() {
            let x = match p.progtype {
                elf::PT_LOAD => self.load_header(p, loader),
                _ => ()
            };
        }
    }

}
<|endoftext|>


<commit_before>//! A wrapper around the uchardet library.  Detects character encodings.
//!
//! Note that the underlying implemention is written in C and C++, and I'm
//! not aware of any security audits which have been performed against it.
//!
//! For more information, see [this project on
//! GitHub](https://github.com/emk/rust-uchardet).

#![license = "Public domain (Unlicense)"]
#![unstable]
#![deny(missing_docs)]

extern crate libc;

use std::error::Error;
use std::result::Result;
use std::c_str::CString;
use libc::{c_char, c_int, c_void, size_t};

#[allow(non_camel_case_types)]
type uchardet_t = *mut c_void;

#[link(name = "uchardet")]
extern {
    fn uchardet_new() -> uchardet_t;
    fn uchardet_delete(ud: uchardet_t);
    fn uchardet_handle_data(ud: uchardet_t, data: *const c_char, len: size_t) ->
        c_int;
    fn uchardet_data_end(ud: uchardet_t);
    fn uchardet_reset(ud: uchardet_t);
    fn uchardet_get_charset(ud: uchardet_t) -> *const c_char;
}

/// An error occurred while trying to detect the character encoding.
#[stable]
#[deriving(Show)]
pub struct EncodingDetectionError {
    message: String
}

#[stable]
impl Error for EncodingDetectionError {
    fn description(&self) -> &str { "encoding detection error" }
    fn detail(&self) -> Option<String> { Some(self.message.clone()) }
    fn cause(&self) -> Option<&Error> { None }
}

/// Either a return value, or an encoding detection error.
#[stable]
pub type EncodingDetectionResult<T> = Result<T, EncodingDetectionError>;

/// Detects the encoding of text using the uchardet library.
#[stable]
pub struct EncodingDetector {
    ptr: uchardet_t
}

impl EncodingDetector {
    /// Return the name of the charset used in `data`, or `None` if the
    /// charset is ASCII or if the encoding can't be detected. (Yes, this
    /// API is weird, and we may offer a better alternative in the future.)
    ///
    /// ```
    /// use uchardet::EncodingDetector;
    ///
    /// assert_eq!(None, EncodingDetector::detect("ascii".as_bytes()).unwrap());
    /// assert_eq!(Some("UTF-8".to_string()),
    ///            EncodingDetector::detect("français".as_bytes()).unwrap());
    /// assert_eq!(Some("windows-1252".to_string()),
    ///            EncodingDetector::detect(&[0x66u8, 0x72, 0x61, 0x6e, 0xe7,
    ///                                       0x61, 0x69, 0x73]).unwrap());
    /// ```
    #[stable]
    pub fn detect(data: &[u8]) -> EncodingDetectionResult<Option<String>> {
        let mut detector = EncodingDetector::new();
        try!(detector.handle_data(data));
        detector.data_end();
        Ok(detector.charset())
    }

    /// Create a new EncodingDetector.
    #[stable]
    pub fn new() -> EncodingDetector {
        let ptr = unsafe { uchardet_new() };
        assert!(ptr.is_not_null());
        EncodingDetector{ptr: ptr}
    }

    /// Pass a chunk of raw bytes to the detector.  This is a no-op if a
    /// charset has been detected.
    #[unstable = "The underlying API is poorly documented."]
    pub fn handle_data(&mut self, data: &[u8]) -> EncodingDetectionResult<()> {
        let result = unsafe {
            uchardet_handle_data(self.ptr, data.as_ptr() as *const i8,
                                 data.len() as size_t)
        };
        match result {
            0 => Ok(()),
            _ => {
                let msg =  "Error handling data".to_string();
                Err(EncodingDetectionError{message: msg})
            }
        }
    }

    /// Notify the detector that we're done calling `handle_data`, and that
    /// we want it to make a guess as to our encoding.  This is a no-op if
    /// no data has been passed yet, or if an encoding has been detected
    /// for certain.  From reading the code, it appears that you can safely
    /// call `handle_data` after calling this, but I'm not certain.
    #[unstable = "The underlying API is poorly documented."]
    pub fn data_end(&mut self) {
        unsafe { uchardet_data_end(self.ptr); }
    }

    /// Reset the detector's internal state.
    #[unstable = "The underlying API is poorly documented."]
    pub fn reset(&mut self) {
        unsafe { uchardet_reset(self.ptr); }
    }

    /// Get the decoder's current best guess as to the encoding.  Returns
    /// `None` on error, or if the data appears to be ASCII.
    #[unstable = "The underlying API is poorly documented."]
    pub fn charset(&self) -> Option<String> {
        unsafe {
            let internal_str = uchardet_get_charset(self.ptr);
            assert!(internal_str.is_not_null());
            let c_str = CString::new(internal_str, false);
            match c_str.as_str() {
                None =>
                    panic!("uchardet_get_charset returned invalid value"),
                Some("") => None,
                Some(encoding) => Some(encoding.to_string())
            }
        }
    }
}

#[stable]
impl Drop for EncodingDetector {
    fn drop(&mut self) {
        unsafe { uchardet_delete(self.ptr) };
    }
}
<commit_msg>Don't officially stabilize anything until after it has been reviewed<commit_after>//! A wrapper around the uchardet library.  Detects character encodings.
//!
//! Note that the underlying implemention is written in C and C++, and I'm
//! not aware of any security audits which have been performed against it.
//!
//! For more information, see [this project on
//! GitHub](https://github.com/emk/rust-uchardet).

#![license = "Public domain (Unlicense)"]
#![unstable]
#![deny(missing_docs)]

extern crate libc;

use std::error::Error;
use std::result::Result;
use std::c_str::CString;
use libc::{c_char, c_int, c_void, size_t};

#[allow(non_camel_case_types)]
type uchardet_t = *mut c_void;

#[link(name = "uchardet")]
extern {
    fn uchardet_new() -> uchardet_t;
    fn uchardet_delete(ud: uchardet_t);
    fn uchardet_handle_data(ud: uchardet_t, data: *const c_char, len: size_t) ->
        c_int;
    fn uchardet_data_end(ud: uchardet_t);
    fn uchardet_reset(ud: uchardet_t);
    fn uchardet_get_charset(ud: uchardet_t) -> *const c_char;
}

/// An error occurred while trying to detect the character encoding.
#[unstable = "Needs review"]
#[deriving(Show)]
pub struct EncodingDetectionError {
    message: String
}

#[unstable = "Needs review"]
impl Error for EncodingDetectionError {
    fn description(&self) -> &str { "encoding detection error" }
    fn detail(&self) -> Option<String> { Some(self.message.clone()) }
    fn cause(&self) -> Option<&Error> { None }
}

/// Either a return value, or an encoding detection error.
#[unstable = "Needs review"]
pub type EncodingDetectionResult<T> = Result<T, EncodingDetectionError>;

/// Detects the encoding of text using the uchardet library.
#[unstable = "Needs review"]
pub struct EncodingDetector {
    ptr: uchardet_t
}

impl EncodingDetector {
    /// Return the name of the charset used in `data`, or `None` if the
    /// charset is ASCII or if the encoding can't be detected. (Yes, this
    /// API is weird, and we may offer a better alternative in the future.)
    ///
    /// ```
    /// use uchardet::EncodingDetector;
    ///
    /// assert_eq!(None, EncodingDetector::detect("ascii".as_bytes()).unwrap());
    /// assert_eq!(Some("UTF-8".to_string()),
    ///            EncodingDetector::detect("français".as_bytes()).unwrap());
    /// assert_eq!(Some("windows-1252".to_string()),
    ///            EncodingDetector::detect(&[0x66u8, 0x72, 0x61, 0x6e, 0xe7,
    ///                                       0x61, 0x69, 0x73]).unwrap());
    /// ```
    #[unstable = "Needs review"]
    pub fn detect(data: &[u8]) -> EncodingDetectionResult<Option<String>> {
        let mut detector = EncodingDetector::new();
        try!(detector.handle_data(data));
        detector.data_end();
        Ok(detector.charset())
    }

    /// Create a new EncodingDetector.
    #[unstable = "Needs review"]
    pub fn new() -> EncodingDetector {
        let ptr = unsafe { uchardet_new() };
        assert!(ptr.is_not_null());
        EncodingDetector{ptr: ptr}
    }

    /// Pass a chunk of raw bytes to the detector.  This is a no-op if a
    /// charset has been detected.
    #[unstable = "The underlying API is poorly documented."]
    pub fn handle_data(&mut self, data: &[u8]) -> EncodingDetectionResult<()> {
        let result = unsafe {
            uchardet_handle_data(self.ptr, data.as_ptr() as *const i8,
                                 data.len() as size_t)
        };
        match result {
            0 => Ok(()),
            _ => {
                let msg =  "Error handling data".to_string();
                Err(EncodingDetectionError{message: msg})
            }
        }
    }

    /// Notify the detector that we're done calling `handle_data`, and that
    /// we want it to make a guess as to our encoding.  This is a no-op if
    /// no data has been passed yet, or if an encoding has been detected
    /// for certain.  From reading the code, it appears that you can safely
    /// call `handle_data` after calling this, but I'm not certain.
    #[unstable = "The underlying API is poorly documented."]
    pub fn data_end(&mut self) {
        unsafe { uchardet_data_end(self.ptr); }
    }

    /// Reset the detector's internal state.
    #[unstable = "The underlying API is poorly documented."]
    pub fn reset(&mut self) {
        unsafe { uchardet_reset(self.ptr); }
    }

    /// Get the decoder's current best guess as to the encoding.  Returns
    /// `None` on error, or if the data appears to be ASCII.
    #[unstable = "The underlying API is poorly documented."]
    pub fn charset(&self) -> Option<String> {
        unsafe {
            let internal_str = uchardet_get_charset(self.ptr);
            assert!(internal_str.is_not_null());
            let c_str = CString::new(internal_str, false);
            match c_str.as_str() {
                None =>
                    panic!("uchardet_get_charset returned invalid value"),
                Some("") => None,
                Some(encoding) => Some(encoding.to_string())
            }
        }
    }
}

#[unstable = "Needs review"]
impl Drop for EncodingDetector {
    fn drop(&mut self) {
        unsafe { uchardet_delete(self.ptr) };
    }
}
<|endoftext|>