<commit_before>// Rust JSON-RPC Library
// Written in 2015 by
//   Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # Rust JSON-RPC Library
//!
//! Rust support for the JSON-RPC 2.0 protocol.
//!

// Coding conventions
#![deny(non_upper_case_globals)]
#![deny(non_camel_case_types)]
#![deny(non_snake_case)]
#![deny(unused_mut)]
#![warn(missing_docs)]

extern crate serde;
#[macro_use]
extern crate serde_derive;
pub extern crate serde_json;

#[cfg(feature = "base64-compat")]
pub extern crate base64;

pub mod client;
pub mod error;
mod util;

#[cfg(feature = "simple_http")]
pub mod simple_http;

#[cfg(feature = "simple_tcp")]
pub mod simple_tcp;

#[cfg(all(feature = "simple_uds", not(windows)))]
pub mod simple_uds;

// Re-export error type
pub use crate::error::Error;
pub use crate::client::{Client, Transport};

use serde_json::value::RawValue;

/// Shorthand method to convert an argument into a [Box<serde_json::value::RawValue>].
/// Since serializers rarely fail, it's probably easier to use [arg] instead.
pub fn try_arg<T: serde::Serialize>(arg: T) -> Result<Box<RawValue>, serde_json::Error> {
    RawValue::from_string(serde_json::to_string(&arg)?)
}

/// Shorthand method to convert an argument into a [Box<serde_json::value::RawValue>].
///
/// This conversion should not fail, so to avoid returning a [Result],
/// in case of an error, the error is serialized as the return value.
pub fn arg<T: serde::Serialize>(arg: T) -> Box<RawValue> {
    match try_arg(arg) {
        Ok(v) => v,
        Err(e) => RawValue::from_string(format!("<<ERROR SERIALIZING ARGUMENT: {}>>", e))
            .unwrap_or_else(|_| RawValue::from_string("<<ERROR SERIALIZING ARGUMENT>>".to_owned()).unwrap()),
    }
}

#[derive(Debug, Clone, Serialize)]
/// A JSONRPC request object
pub struct Request<'a> {
    /// The name of the RPC call
    pub method: &'a str,
    /// Parameters to the RPC call
    pub params: &'a [Box<RawValue>],
    /// Identifier for this Request, which should appear in the response
    pub id: serde_json::Value,
    /// jsonrpc field, MUST be "2.0"
    pub jsonrpc: Option<&'a str>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
/// A JSONRPC response object
pub struct Response {
    /// A result if there is one, or null
    pub result: Option<Box<RawValue>>,
    /// An error if there is one, or null
    pub error: Option<error::RpcError>,
    /// Identifier for this Request, which should match that of the request
    pub id: serde_json::Value,
    /// jsonrpc field, MUST be "2.0"
    pub jsonrpc: Option<String>,
}

impl Response {
    /// Extract the result from a response
    pub fn result<T: for<'a> serde::de::Deserialize<'a>>(&self) -> Result<T, Error> {
        if let Some(ref e) = self.error {
            return Err(Error::Rpc(e.clone()));
        }

        if let Some(ref res) = self.result {
            serde_json::from_str(res.get()).map_err(Error::Json)
        } else {
            serde_json::from_value(serde_json::Value::Null).map_err(Error::Json)
        }
    }

    /// Return the RPC error, if there was one, but do not check the result
    pub fn check_error(self) -> Result<(), Error> {
        if let Some(e) = self.error {
            Err(Error::Rpc(e))
        } else {
            Ok(())
        }
    }

    /// Returns whether or not the `result` field is empty
    pub fn is_none(&self) -> bool {
        self.result.is_none()
    }
}

#[cfg(test)]
mod tests {

    use super::Response;
    use serde_json;
    use serde_json::value::RawValue;

    #[test]
    fn response_is_none() {
        let joanna = Response {
            result: Some(RawValue::from_string(serde_json::to_string(&true).unwrap()).unwrap()),
            error: None,
            id: From::from(81),
            jsonrpc: Some(String::from("2.0")),
        };

        let bill = Response {
            result: None,
            error: None,
            id: From::from(66),
            jsonrpc: Some(String::from("2.0")),
        };

        assert!(!joanna.is_none());
        assert!(bill.is_none());
    }

    #[test]
    fn response_extract() {
        let obj = vec!["Mary", "had", "a", "little", "lamb"];
        let response = Response {
            result: Some(RawValue::from_string(serde_json::to_string(&obj).unwrap()).unwrap()),
            error: None,
            id: serde_json::Value::Null,
            jsonrpc: Some(String::from("2.0")),
        };
        let recovered1: Vec<String> = response.result().unwrap();
        assert!(response.clone().check_error().is_ok());
        let recovered2: Vec<String> = response.result().unwrap();
        assert_eq!(obj, recovered1);
        assert_eq!(obj, recovered2);
    }

    #[test]
    fn null_result() {
        let s = r#"{"result":null,"error":null,"id":"test"}"#;
        let response: Response = serde_json::from_str(s).unwrap();
        let recovered1: Result<(), _> = response.result();
        let recovered2: Result<(), _> = response.clone().result();
        assert!(recovered1.is_ok());
        assert!(recovered2.is_ok());

        let recovered1: Result<String, _> = response.result();
        let recovered2: Result<String, _> = response.clone().result();
        assert!(recovered1.is_err());
        assert!(recovered2.is_err());
    }

    #[test]
    fn batch_response() {
        // from the jsonrpc.org spec example
        let s = r#"[
            {"jsonrpc": "2.0", "result": 7, "id": "1"},
            {"jsonrpc": "2.0", "result": 19, "id": "2"},
            {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
            {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "5"},
            {"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"}
        ]"#;
        let batch_response: Vec<Response> = serde_json::from_str(s).unwrap();
        assert_eq!(batch_response.len(), 5);
    }

    #[test]
    fn test_arg() {
        macro_rules! test_arg {
            ($val:expr, $t:ty) => {{
                let val1: $t = $val;
                let arg = super::arg(val1.clone());
                let val2: $t = serde_json::from_str(arg.get()).expect(stringify!($val));
                assert_eq!(val1, val2, "failed test for {}", stringify!($val));
            }}
        }

        test_arg!(true, bool);
        test_arg!(42, u8);
        test_arg!(42, usize);
        test_arg!(42, isize);
        test_arg!(vec![42, 35], Vec<u8>);
        test_arg!(String::from("test"), String);

        #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
        struct Test {
            v: String,
        }
        test_arg!(Test { v: String::from("test"), }, Test);
    }
}
<commit_msg>Remove redundant import<commit_after>// Rust JSON-RPC Library
// Written in 2015 by
//   Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # Rust JSON-RPC Library
//!
//! Rust support for the JSON-RPC 2.0 protocol.
//!

// Coding conventions
#![deny(non_upper_case_globals)]
#![deny(non_camel_case_types)]
#![deny(non_snake_case)]
#![deny(unused_mut)]
#![warn(missing_docs)]

extern crate serde;
#[macro_use]
extern crate serde_derive;
pub extern crate serde_json;

#[cfg(feature = "base64-compat")]
pub extern crate base64;

pub mod client;
pub mod error;
mod util;

#[cfg(feature = "simple_http")]
pub mod simple_http;

#[cfg(feature = "simple_tcp")]
pub mod simple_tcp;

#[cfg(all(feature = "simple_uds", not(windows)))]
pub mod simple_uds;

// Re-export error type
pub use crate::error::Error;
pub use crate::client::{Client, Transport};

use serde_json::value::RawValue;

/// Shorthand method to convert an argument into a [Box<serde_json::value::RawValue>].
/// Since serializers rarely fail, it's probably easier to use [arg] instead.
pub fn try_arg<T: serde::Serialize>(arg: T) -> Result<Box<RawValue>, serde_json::Error> {
    RawValue::from_string(serde_json::to_string(&arg)?)
}

/// Shorthand method to convert an argument into a [Box<serde_json::value::RawValue>].
///
/// This conversion should not fail, so to avoid returning a [Result],
/// in case of an error, the error is serialized as the return value.
pub fn arg<T: serde::Serialize>(arg: T) -> Box<RawValue> {
    match try_arg(arg) {
        Ok(v) => v,
        Err(e) => RawValue::from_string(format!("<<ERROR SERIALIZING ARGUMENT: {}>>", e))
            .unwrap_or_else(|_| RawValue::from_string("<<ERROR SERIALIZING ARGUMENT>>".to_owned()).unwrap()),
    }
}

#[derive(Debug, Clone, Serialize)]
/// A JSONRPC request object
pub struct Request<'a> {
    /// The name of the RPC call
    pub method: &'a str,
    /// Parameters to the RPC call
    pub params: &'a [Box<RawValue>],
    /// Identifier for this Request, which should appear in the response
    pub id: serde_json::Value,
    /// jsonrpc field, MUST be "2.0"
    pub jsonrpc: Option<&'a str>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
/// A JSONRPC response object
pub struct Response {
    /// A result if there is one, or null
    pub result: Option<Box<RawValue>>,
    /// An error if there is one, or null
    pub error: Option<error::RpcError>,
    /// Identifier for this Request, which should match that of the request
    pub id: serde_json::Value,
    /// jsonrpc field, MUST be "2.0"
    pub jsonrpc: Option<String>,
}

impl Response {
    /// Extract the result from a response
    pub fn result<T: for<'a> serde::de::Deserialize<'a>>(&self) -> Result<T, Error> {
        if let Some(ref e) = self.error {
            return Err(Error::Rpc(e.clone()));
        }

        if let Some(ref res) = self.result {
            serde_json::from_str(res.get()).map_err(Error::Json)
        } else {
            serde_json::from_value(serde_json::Value::Null).map_err(Error::Json)
        }
    }

    /// Return the RPC error, if there was one, but do not check the result
    pub fn check_error(self) -> Result<(), Error> {
        if let Some(e) = self.error {
            Err(Error::Rpc(e))
        } else {
            Ok(())
        }
    }

    /// Returns whether or not the `result` field is empty
    pub fn is_none(&self) -> bool {
        self.result.is_none()
    }
}

#[cfg(test)]
mod tests {

    use super::Response;
    use serde_json::value::RawValue;

    #[test]
    fn response_is_none() {
        let joanna = Response {
            result: Some(RawValue::from_string(serde_json::to_string(&true).unwrap()).unwrap()),
            error: None,
            id: From::from(81),
            jsonrpc: Some(String::from("2.0")),
        };

        let bill = Response {
            result: None,
            error: None,
            id: From::from(66),
            jsonrpc: Some(String::from("2.0")),
        };

        assert!(!joanna.is_none());
        assert!(bill.is_none());
    }

    #[test]
    fn response_extract() {
        let obj = vec!["Mary", "had", "a", "little", "lamb"];
        let response = Response {
            result: Some(RawValue::from_string(serde_json::to_string(&obj).unwrap()).unwrap()),
            error: None,
            id: serde_json::Value::Null,
            jsonrpc: Some(String::from("2.0")),
        };
        let recovered1: Vec<String> = response.result().unwrap();
        assert!(response.clone().check_error().is_ok());
        let recovered2: Vec<String> = response.result().unwrap();
        assert_eq!(obj, recovered1);
        assert_eq!(obj, recovered2);
    }

    #[test]
    fn null_result() {
        let s = r#"{"result":null,"error":null,"id":"test"}"#;
        let response: Response = serde_json::from_str(s).unwrap();
        let recovered1: Result<(), _> = response.result();
        let recovered2: Result<(), _> = response.clone().result();
        assert!(recovered1.is_ok());
        assert!(recovered2.is_ok());

        let recovered1: Result<String, _> = response.result();
        let recovered2: Result<String, _> = response.clone().result();
        assert!(recovered1.is_err());
        assert!(recovered2.is_err());
    }

    #[test]
    fn batch_response() {
        // from the jsonrpc.org spec example
        let s = r#"[
            {"jsonrpc": "2.0", "result": 7, "id": "1"},
            {"jsonrpc": "2.0", "result": 19, "id": "2"},
            {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
            {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "5"},
            {"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"}
        ]"#;
        let batch_response: Vec<Response> = serde_json::from_str(s).unwrap();
        assert_eq!(batch_response.len(), 5);
    }

    #[test]
    fn test_arg() {
        macro_rules! test_arg {
            ($val:expr, $t:ty) => {{
                let val1: $t = $val;
                let arg = super::arg(val1.clone());
                let val2: $t = serde_json::from_str(arg.get()).expect(stringify!($val));
                assert_eq!(val1, val2, "failed test for {}", stringify!($val));
            }}
        }

        test_arg!(true, bool);
        test_arg!(42, u8);
        test_arg!(42, usize);
        test_arg!(42, isize);
        test_arg!(vec![42, 35], Vec<u8>);
        test_arg!(String::from("test"), String);

        #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
        struct Test {
            v: String,
        }
        test_arg!(Test { v: String::from("test"), }, Test);
    }
}
<|endoftext|>


<commit_before>//! Replaces the deprecated functionality of std::os::num_cpus.
#![cfg_attr(test, deny(warnings))]
#![deny(missing_docs)]

extern crate libc;

/// Returns the number of CPUs of the current machine.
#[inline]
pub fn get() -> usize {
    get_num_cpus()
}

#[cfg(windows)]
fn get_num_cpus() -> usize {
    unsafe {
        let mut sysinfo: libc::SYSTEM_INFO = ::std::mem::uninitialized();
        libc::GetSystemInfo(&mut sysinfo);
        sysinfo.dwNumberOfProcessors as usize
    }
}

#[cfg(
    all(
        any(
            target_os = "macos",
            target_os = "ios",
            target_os = "freebsd",
            target_os = "dragonfly",
            target_os = "bitrig",
            target_os = "openbsd"
        ),
        not(unix)
    )
)]
fn get_num_cpus() -> usize {
    use libc::{c_int, c_uint};
    use libc::funcs::bsd44::sysctl;

    //XXX: uplift to libc?
    const CTL_HW: c_int = 6;
    const HW_AVAILCPU: c_int = 25;
    const HW_NCPU: c_int = 3;

    let mut cpus: c_uint = 0;
    let mut CPUS_SIZE = ::std::mem::size_of::<c_uint>();
    let mut mib: [c_int; 4] = [CTL_HW, HW_AVAILCPU, 0, 0];

    unsafe {
        sysctl(mib.as_mut_ptr(), 2, &mut cpus, &mut CPUS_SIZE, &mut (), 0);
    }

    if cpus < 1 {
        mib[1] = HW_NCPU;
        unsafe {
            sysctl(mib.as_mut_ptr(), 2, &mut cpus, &mut CPUS_SIZE, &mut (), 0);
        }
        if cpus < 1 {
            cpus = 1;
        }
    }

    cpus as usize
}

#[cfg(target_os= "linux")]
fn get_num_cpus() -> usize {
    //to-do: replace with libc::_SC_NPROCESSORS_ONLN once available
    unsafe {
        libc::sysconf(84) as usize
    }
}

#[cfg(target_os="macos")]
fn get_num_cpus() -> usize {
    //to-do: replace with libc::_SC_NPROCESSORS_ONLN once available
    unsafe {
        libc::sysconf(58) as usize
    }
}

#[test]
fn lower_bound() {
    assert!(get() > 0);
}

#[test]
fn upper_bound() {
    assert!(get() < 236,451);
}
<commit_msg>change comma to underscore<commit_after>//! Replaces the deprecated functionality of std::os::num_cpus.
#![cfg_attr(test, deny(warnings))]
#![deny(missing_docs)]

extern crate libc;

/// Returns the number of CPUs of the current machine.
#[inline]
pub fn get() -> usize {
    get_num_cpus()
}

#[cfg(windows)]
fn get_num_cpus() -> usize {
    unsafe {
        let mut sysinfo: libc::SYSTEM_INFO = ::std::mem::uninitialized();
        libc::GetSystemInfo(&mut sysinfo);
        sysinfo.dwNumberOfProcessors as usize
    }
}

#[cfg(
    all(
        any(
            target_os = "macos",
            target_os = "ios",
            target_os = "freebsd",
            target_os = "dragonfly",
            target_os = "bitrig",
            target_os = "openbsd"
        ),
        not(unix)
    )
)]
fn get_num_cpus() -> usize {
    use libc::{c_int, c_uint};
    use libc::funcs::bsd44::sysctl;

    //XXX: uplift to libc?
    const CTL_HW: c_int = 6;
    const HW_AVAILCPU: c_int = 25;
    const HW_NCPU: c_int = 3;

    let mut cpus: c_uint = 0;
    let mut CPUS_SIZE = ::std::mem::size_of::<c_uint>();
    let mut mib: [c_int; 4] = [CTL_HW, HW_AVAILCPU, 0, 0];

    unsafe {
        sysctl(mib.as_mut_ptr(), 2, &mut cpus, &mut CPUS_SIZE, &mut (), 0);
    }

    if cpus < 1 {
        mib[1] = HW_NCPU;
        unsafe {
            sysctl(mib.as_mut_ptr(), 2, &mut cpus, &mut CPUS_SIZE, &mut (), 0);
        }
        if cpus < 1 {
            cpus = 1;
        }
    }

    cpus as usize
}

#[cfg(target_os= "linux")]
fn get_num_cpus() -> usize {
    //to-do: replace with libc::_SC_NPROCESSORS_ONLN once available
    unsafe {
        libc::sysconf(84) as usize
    }
}

#[cfg(target_os="macos")]
fn get_num_cpus() -> usize {
    //to-do: replace with libc::_SC_NPROCESSORS_ONLN once available
    unsafe {
        libc::sysconf(58) as usize
    }
}

#[test]
fn lower_bound() {
    assert!(get() > 0);
}

#[test]
fn upper_bound() {
    assert!(get() < 236_451);
}
<|endoftext|>


<commit_before>#![feature(core, old_io)]

extern crate crypto;
extern crate "rustc-serialize" as rustc_serialize;
extern crate time;

// TODO: find out where this function is going to be once old_io is gone
use std::old_io::extensions::{u64_to_be_bytes, u64_from_be_bytes};
use std::num::Int;
use crypto::sha1::Sha1;
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use crypto::digest::Digest;
use rustc_serialize::hex::FromHex;

fn dynamic_truncation(hs: &[u8]) -> u64 {
    let offset_bits = (hs[19] & 0xf) as usize;
    let p = u64_from_be_bytes(hs, offset_bits, 4);

    p & 0x7fffffff
}

pub fn hotp_custom<D: Digest>(key: &[u8], counter: u64, digits: u32,
                              hash: D) -> u64 {
    let mut hmac = Hmac::new(hash, key);
    u64_to_be_bytes(counter, 8, |bytes| {
        hmac.input(bytes)
    });
    let result = hmac.result();
    let hs = result.code();

    dynamic_truncation(hs) % 10.pow(digits)
}

pub fn hotp_raw(key: &[u8], counter: u64, digits: u32) -> u64 {
    let hash = Sha1::new();
    hotp_custom(key, counter, digits, hash)
}

pub fn hotp(key: &str, counter: u64, digits: u32) -> Result<u64, &str> {
    match key.from_hex() {
        Ok(bytes) => Ok(hotp_raw(bytes.as_slice(), counter, digits)),
        Err(_) => Err("Unable to parse hex.")
    }
}

pub fn totp_custom<D: Digest>(key: &[u8], digits: u32, epoch: u64,
                              time_step: u64, current_time: u64,
                              hash: D) -> u64 {
    let counter = (current_time - epoch) / time_step;
    hotp_custom(key, counter, digits, hash)
}

pub fn totp_raw(key: &[u8], digits: u32, epoch: u64, time_step: u64) -> u64 {
    let hash = Sha1::new();
    let current_time = time::get_time();
    totp_custom(key, digits, epoch, time_step, current_time.sec as u64, hash)
}

pub fn totp(key: &str, digits: u32, epoch: u64,
            time_step: u64) -> Result<u64, &str> {
    match key.from_hex() {
        Ok(bytes) => Ok(totp_raw(bytes.as_slice(), digits, epoch, time_step)),
        Err(_) => Err("Unable to parse hex.")
    }
}

#[test]
fn test_hotp() {
    assert_eq!(hotp_raw(b"\xff", 23, 6), 330795);
    assert_eq!(hotp("ff", 23, 6).unwrap(), 330795);
    assert_eq!(hotp_custom(b"\xff", 23, 6, Sha1::new()), 330795);
}

#[test]
fn test_totp() {
    assert_eq!(totp_custom(b"\xff", 6, 0, 1, 23, Sha1::new()), 330795);
}
<commit_msg>Use custom u64/be functions<commit_after>#![feature(core)]

extern crate crypto;
extern crate "rustc-serialize" as rustc_serialize;
extern crate time;

// TODO: find out where this function is going to be once old_io is gone
use std::num::Int;
use crypto::sha1::Sha1;
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use crypto::digest::Digest;
use rustc_serialize::hex::FromHex;

fn u64_from_be_bytes_4(bytes: &[u8], start: usize) -> u64 {
    let mut val = 0u64;

    val += (bytes[start]   as u64) << ((3 * 8) as u64);
    val += (bytes[start+1] as u64) << ((2 * 8) as u64);
    val += (bytes[start+2] as u64) << ((1 * 8) as u64);
    val += (bytes[start+3] as u64) << ((0 * 8) as u64);

    val
}

fn u64_to_be_bytes_8(data: u64) -> Vec<u8> {
    let mut v = Vec::new();
    v.push((data >> 56) as u8);
    v.push((data >> 48) as u8);
    v.push((data >> 40) as u8);
    v.push((data >> 32) as u8);
    v.push((data >> 24) as u8);
    v.push((data >> 16) as u8);
    v.push((data >> 8) as u8);
    v.push(data as u8);

    v
}

fn dynamic_truncation(hs: &[u8]) -> u64 {
    let offset_bits = (hs[19] & 0xf) as usize;
    let p = u64_from_be_bytes_4(hs, offset_bits);

    p & 0x7fffffff
}

pub fn hotp_custom<D: Digest>(key: &[u8], counter: u64, digits: u32,
                              hash: D) -> u64 {
    let mut hmac = Hmac::new(hash, key);
    let bytes = u64_to_be_bytes_8(counter);
    hmac.input(bytes.as_slice());
    let result = hmac.result();
    let hs = result.code();

    dynamic_truncation(hs) % 10.pow(digits)
}

pub fn hotp_raw(key: &[u8], counter: u64, digits: u32) -> u64 {
    let hash = Sha1::new();
    hotp_custom(key, counter, digits, hash)
}

pub fn hotp(key: &str, counter: u64, digits: u32) -> Result<u64, &str> {
    match key.from_hex() {
        Ok(bytes) => Ok(hotp_raw(bytes.as_slice(), counter, digits)),
        Err(_) => Err("Unable to parse hex.")
    }
}

pub fn totp_custom<D: Digest>(key: &[u8], digits: u32, epoch: u64,
                              time_step: u64, current_time: u64,
                              hash: D) -> u64 {
    let counter = (current_time - epoch) / time_step;
    hotp_custom(key, counter, digits, hash)
}

pub fn totp_raw(key: &[u8], digits: u32, epoch: u64, time_step: u64) -> u64 {
    let hash = Sha1::new();
    let current_time = time::get_time();
    totp_custom(key, digits, epoch, time_step, current_time.sec as u64, hash)
}

pub fn totp(key: &str, digits: u32, epoch: u64,
            time_step: u64) -> Result<u64, &str> {
    match key.from_hex() {
        Ok(bytes) => Ok(totp_raw(bytes.as_slice(), digits, epoch, time_step)),
        Err(_) => Err("Unable to parse hex.")
    }
}

#[test]
fn test_hotp() {
    assert_eq!(hotp_raw(b"\xff", 23, 6), 330795);
    assert_eq!(hotp("ff", 23, 6).unwrap(), 330795);
    assert_eq!(hotp_custom(b"\xff", 23, 6, Sha1::new()), 330795);
}

#[test]
fn test_totp() {
    assert_eq!(totp_custom(b"\xff", 6, 0, 1, 23, Sha1::new()), 330795);
}
<|endoftext|>


<commit_before>//! An implementation of [FLAC](https://xiph.org/flac), free lossless audio
//! codec, written in Rust.
//!
//! # Examples
//!
//! Basic decoding from a file.
//!
//! ```
//! match flac::Stream::from_file("path/to/file.flac") {
//!   Ok(mut stream) => {
//!     // Copy of `StreamInfo` to help convert to a different audio format.
//!     let info = stream.info();
//!
//!     for sample in stream.iter() {
//!       // Iterate over each decoded sample
//!     }
//!   }
//!   Err(error)     => println!("{}", error),
//! }
//! ```

#[macro_use]
extern crate nom;

#[macro_use]
mod utility;
pub mod metadata;
mod frame;
mod subframe;
pub mod stream;

pub use metadata::Metadata;
pub use stream::{stream_parser, Stream};
<commit_msg>Remove reexport of `stream_parser`<commit_after>//! An implementation of [FLAC](https://xiph.org/flac), free lossless audio
//! codec, written in Rust.
//!
//! # Examples
//!
//! Basic decoding from a file.
//!
//! ```
//! match flac::Stream::from_file("path/to/file.flac") {
//!   Ok(mut stream) => {
//!     // Copy of `StreamInfo` to help convert to a different audio format.
//!     let info = stream.info();
//!
//!     for sample in stream.iter() {
//!       // Iterate over each decoded sample
//!     }
//!   }
//!   Err(error)     => println!("{}", error),
//! }
//! ```

#[macro_use]
extern crate nom;

#[macro_use]
mod utility;
pub mod metadata;
mod frame;
mod subframe;
pub mod stream;

pub use metadata::Metadata;
pub use stream::Stream;
<|endoftext|>


<commit_before>// Copyright 2014 Valentin Vasilyev.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

Heliotrope is a Solr client for the [Rust](http://rust-lang.org/) programming language.

It builds with [Cargo](http://crates.io/).
To use it in your project, add this to your `Cargo.toml` file:

```Cargo
[dependencies.heliotrope]
git = "https://github.com/Valve/heliotrope"
```

## Indexing

### Adding new document to solr

```
extern crate url;

use url::{Url};
use heliotrope::{Solr, SolrDocument, SolrString, SolrI64};

fn main(){
  let url = Url::parse("http://localhost:8983/solr/test/").unwrap();
  let solr = Solr::new(url);
  let mut document = SolrDocument::new();
  document.add_field("id", SolrI64(1));
  document.add_field("type", SolrString("Book".to_string()));
  document.add_field("title", SolrString("How to train your dragon".to_string()));
  document.add_field("body", SolrString("Vala Morgulis".to_string()));
  match solr.add(&document) {
    Ok(solr_response) => println!("{:?}", solr_response),
    Err(solr_error) => println!("{:?}", solr_error)
  }
  match solr.commit() {
    Ok(solr_response) => println!("{:?}", solr_response),
    Err(solr_error) => println!("{:?}", solr_error)
  }
}
```

### Add and commit in one step

```
extern crate url;
use url::{Url};
use heliotrope::{Solr, SolrDocument, SolrString, SolrI64};

fn main(){
  let url = Url::parse("http://localhost:8983/solr/test/").unwrap();
  let solr = Solr::new(url);
  let mut document = SolrDocument::new();
  document.add_field("id", SolrI64(2));
  document.add_field("type", SolrString("Book".to_string()));
  document.add_field("title", SolrString("The Great Gatsby".to_string()));
  document.add_field("body", SolrString("In my younger and more vulnerable years..".to_string()));
  match solr.add_and_commit(&document) {
    Ok(solr_response) => println!("{:?}", solr_response),
    Err(solr_error) => println!("Status: {}, Message: {}", solr_error.status, solr_error.message)
  }
}
```

### Adding multiple document at once

```rust
extern crate url;
use url::{Url};
use heliotrope::{Solr, SolrDocument, SolrString, SolrI64};

let url = Url::parse("http://localhost:8983/solr/test/").unwrap();
let solr = Solr::new(url);
let mut document1 = SolrDocument::new();
document1.add_field("id", SolrI64(3));
document1.add_field("type", SolrString("Book".to_string()));
document1.add_field("title", SolrString("The Great Gatsby".to_string()));
document1.add_field("body", SolrString("In my younger and more vulnerable years".to_string()));

let mut document2 = SolrDocument::new();
document1.add_field("id", SolrI64(4));
document1.add_field("type", SolrString("Book".to_string()));
document2.add_field("title", SolrString("Moby Dick".to_string()));
document2.add_field("body", SolrString("Call me Ishmael".to_string()));

match solr.add_many_and_commit(vec!(&document1, &document2)) {
  Ok(solr_response) => println!("{:?}", solr_response),
  Err(solr_error) => println!("Status: {}, Message: {}", solr_error.status, solr_error.message)
}
```

## Querying

```rust
extern crate url;
use url::{Url};
use heliotrope::{Solr, SolrDocument, SolrString, SolrI64};

let url = Url::parse("http://localhost:8983/solr/test/").unwrap();
let solr = Solr::new(url);
let query = SolrQuery::new("*:*");
match solr.query(&query) {
  Ok(solr_response) => {
    println!("Status: {}", solr_response.status);
    println!("Time: {}", solr_response.time);
    println!("Total rows found: {}", solr_response.total);
    println!("Offset: {}", solr_response.start);
    for item in solr_response.items.iter() {
      println!("{}", item);
    }
  }
  Err(solr_error) => println!("Status: {}, Message: {}", solr_error.status, solr_error.message)
}
```
*/

#![crate_name="heliotrope"]

extern crate serialize;
extern crate url;
extern crate http;
extern crate debug;

use std::io::IoResult;
use url::{Url, UrlParser};
use serialize::{json, Decodable};
use serialize::json::Decoder as JsonDecoder;
use serialize::json::{DecoderError};
use http_utils::HttpResponse;

pub use document::{SolrField, SolrDocument, SolrValue, SolrF64, SolrI64, SolrString};
pub use response::{SolrError, SolrUpdateResult, SolrQueryResult, SolrUpdateResponse, SolrQueryResponse};
pub use query::{SolrQuery};

mod http_utils;
mod document;
mod query;
mod response;

/// Represents your API connection to Solr.
/// You will use this struct to perform operations on Solr.
pub struct Solr {
  /// Base URL to connect to Solr. Should include the core.
  /// For example http://localhost:8983/solr/production/
  pub base_url: Url,
  select_url: Url,
  update_url: Url,
  commit_url: Url
}

impl Solr {

  fn build_update_url(url: &Url) -> Url{
    let mut url_parser = UrlParser::new();
    url_parser.base_url(url).parse("./update").unwrap()
  }

  fn build_select_url(url: &Url) -> Url {
    let mut url_parser = UrlParser::new();
    url_parser.base_url(url).parse("./select").unwrap()
  }

  fn build_commit_url(url: &Url) -> Url {
    let mut url_parser = UrlParser::new();
    url_parser.base_url(url).parse("./update?commit=true").unwrap()
  }

  /// Creates a new instance of Solr.
  pub fn new(url: &Url) -> Solr {
    Solr {base_url: url.clone(),
      select_url: Solr::build_select_url(url),
      update_url: Solr::build_update_url(url),
      commit_url: Solr::build_commit_url(url)}
  }

  /// Adds new document to Solr, without committing
  pub fn add(&self, document: &SolrDocument) -> SolrUpdateResult {
    self.add_many([document])
  }

  /// Adds new document to Solr and commits it
  pub fn add_and_commit(&self, document: &SolrDocument) -> SolrUpdateResult {
    self.add_many_and_commit([document])
  }

  /// Adds multiple documents to Solr, without committing it
  pub fn add_many(&self, documents: &[&SolrDocument]) -> SolrUpdateResult {
    let raw_json = json::encode(&documents);
    let http_result =  http_utils::post_json(&self.update_url, raw_json.as_slice());
    handle_http_result(http_result)
  }

  /// Ads multiple documents to Solr and commits them
  pub fn add_many_and_commit(&self, documents: &[&SolrDocument]) -> SolrUpdateResult {
    let raw_json = json::encode(&documents);
    println!("{}", raw_json);
    let http_result =  http_utils::post_json(&self.commit_url, raw_json.as_slice());
    handle_http_result(http_result)
  }

  /// Performs Solr commit
  pub fn commit(&self) -> SolrUpdateResult {
    let http_result = http_utils::post(&self.commit_url);
    handle_http_result(http_result)
  }

  /// Performs Solr query
  pub fn query(&self, query: &SolrQuery) -> SolrQueryResult {
    let mut query_url = self.select_url.clone();
    query_url.set_query_from_pairs(query.to_pairs().iter().map(|&(k,v)| (k,v)));
    let http_result = http_utils::get(&query_url);
    handle_http_result(http_result)
  }
}

fn handle_http_result<R: Decodable<JsonDecoder, DecoderError>>(result: IoResult<HttpResponse>) -> Result<R, SolrError> {
  match result {
    Ok(http_response) => {
      match http_response.code {
        200 => {
          let response: R = json::decode(http_response.body_str().unwrap()).unwrap();
          Ok(response)
        },
        _ => {
          let error: SolrError = json::decode(http_response.body_str().unwrap()).unwrap();
          Err(error)
        }
      }
    },
    Err(err) => {
      Err(SolrError{status: 0, time: 0, message: err.desc.to_string()})
    }
  }
}

<commit_msg>Fix docs to ignore code<commit_after>// Copyright 2014 Valentin Vasilyev.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

Heliotrope is a Solr client for the [Rust](http://rust-lang.org/) programming language.

It builds with [Cargo](http://crates.io/).
To use it in your project, add this to your `Cargo.toml` file:

```Cargo
[dependencies.heliotrope]
git = "https://github.com/Valve/heliotrope"
```

## Indexing

### Adding new document to solr

```ignore
use url::Url;
use heliotrope::{Solr, SolrDocument, SolrString, SolrI64};

fn main(){
  let url = Url::parse("http://localhost:8983/solr/test/").unwrap();
  let solr = Solr::new(url);
  let mut document = SolrDocument::new();
  document.add_field("id", SolrI64(1));
  document.add_field("type", SolrString("Book".to_string()));
  document.add_field("title", SolrString("How to train your dragon".to_string()));
  document.add_field("body", SolrString("Vala Morgulis".to_string()));
  match solr.add(&document) {
    Ok(solr_response) => println!("{:?}", solr_response),
    Err(solr_error) => println!("{:?}", solr_error)
  }
  match solr.commit() {
    Ok(solr_response) => println!("{:?}", solr_response),
    Err(solr_error) => println!("{:?}", solr_error)
  }
}
```

### Add and commit in one step

```ignore
use url::{Url};
use heliotrope::{Solr, SolrDocument, SolrString, SolrI64};

fn main(){
  let url = Url::parse("http://localhost:8983/solr/test/").unwrap();
  let solr = Solr::new(url);
  let mut document = SolrDocument::new();
  document.add_field("id", SolrI64(2));
  document.add_field("type", SolrString("Book".to_string()));
  document.add_field("title", SolrString("The Great Gatsby".to_string()));
  document.add_field("body", SolrString("In my younger and more vulnerable years..".to_string()));
  match solr.add_and_commit(&document) {
    Ok(solr_response) => println!("{:?}", solr_response),
    Err(solr_error) => println!("Status: {}, Message: {}", solr_error.status, solr_error.message)
  }
}
```

### Adding multiple document at once

```ignore
use url::{Url};
use heliotrope::{Solr, SolrDocument, SolrString, SolrI64};

let url = Url::parse("http://localhost:8983/solr/test/").unwrap();
let solr = Solr::new(url);
let mut document1 = SolrDocument::new();
document1.add_field("id", SolrI64(3));
document1.add_field("type", SolrString("Book".to_string()));
document1.add_field("title", SolrString("The Great Gatsby".to_string()));
document1.add_field("body", SolrString("In my younger and more vulnerable years".to_string()));

let mut document2 = SolrDocument::new();
document1.add_field("id", SolrI64(4));
document1.add_field("type", SolrString("Book".to_string()));
document2.add_field("title", SolrString("Moby Dick".to_string()));
document2.add_field("body", SolrString("Call me Ishmael".to_string()));

match solr.add_many_and_commit(vec!(&document1, &document2)) {
  Ok(solr_response) => println!("{:?}", solr_response),
  Err(solr_error) => println!("Status: {}, Message: {}", solr_error.status, solr_error.message)
}
```

## Querying

```ignore
extern crate url;
use url::{Url};
use heliotrope::{Solr, SolrDocument, SolrString, SolrI64};

let url = Url::parse("http://localhost:8983/solr/test/").unwrap();
let solr = Solr::new(url);
let query = SolrQuery::new("*:*");
match solr.query(&query) {
  Ok(solr_response) => {
    println!("Status: {}", solr_response.status);
    println!("Time: {}", solr_response.time);
    println!("Total rows found: {}", solr_response.total);
    println!("Offset: {}", solr_response.start);
    for item in solr_response.items.iter() {
      println!("{}", item);
    }
  }
  Err(solr_error) => println!("Status: {}, Message: {}", solr_error.status, solr_error.message)
}
```
*/

#![crate_name="heliotrope"]

extern crate serialize;
extern crate url;
extern crate http;
extern crate debug;

use std::io::IoResult;
use url::{Url, UrlParser};
use serialize::{json, Decodable};
use serialize::json::Decoder as JsonDecoder;
use serialize::json::{DecoderError};
use http_utils::HttpResponse;

pub use document::{SolrField, SolrDocument, SolrValue, SolrF64, SolrI64, SolrString};
pub use response::{SolrError, SolrUpdateResult, SolrQueryResult, SolrUpdateResponse, SolrQueryResponse};
pub use query::{SolrQuery};

mod http_utils;
mod document;
mod query;
mod response;

/// Represents your API connection to Solr.
/// You will use this struct to perform operations on Solr.
pub struct Solr {
  /// Base URL to connect to Solr. Should include the core.
  /// For example http://localhost:8983/solr/production/
  pub base_url: Url,
  select_url: Url,
  update_url: Url,
  commit_url: Url
}

impl Solr {

  fn build_update_url(url: &Url) -> Url{
    let mut url_parser = UrlParser::new();
    url_parser.base_url(url).parse("./update").unwrap()
  }

  fn build_select_url(url: &Url) -> Url {
    let mut url_parser = UrlParser::new();
    url_parser.base_url(url).parse("./select").unwrap()
  }

  fn build_commit_url(url: &Url) -> Url {
    let mut url_parser = UrlParser::new();
    url_parser.base_url(url).parse("./update?commit=true").unwrap()
  }

  /// Creates a new instance of Solr.
  pub fn new(url: &Url) -> Solr {
    Solr {base_url: url.clone(),
      select_url: Solr::build_select_url(url),
      update_url: Solr::build_update_url(url),
      commit_url: Solr::build_commit_url(url)}
  }

  /// Adds new document to Solr, without committing
  pub fn add(&self, document: &SolrDocument) -> SolrUpdateResult {
    self.add_many([document])
  }

  /// Adds new document to Solr and commits it
  pub fn add_and_commit(&self, document: &SolrDocument) -> SolrUpdateResult {
    self.add_many_and_commit([document])
  }

  /// Adds multiple documents to Solr, without committing it
  pub fn add_many(&self, documents: &[&SolrDocument]) -> SolrUpdateResult {
    let raw_json = json::encode(&documents);
    let http_result =  http_utils::post_json(&self.update_url, raw_json.as_slice());
    handle_http_result(http_result)
  }

  /// Ads multiple documents to Solr and commits them
  pub fn add_many_and_commit(&self, documents: &[&SolrDocument]) -> SolrUpdateResult {
    let raw_json = json::encode(&documents);
    println!("{}", raw_json);
    let http_result =  http_utils::post_json(&self.commit_url, raw_json.as_slice());
    handle_http_result(http_result)
  }

  /// Performs Solr commit
  pub fn commit(&self) -> SolrUpdateResult {
    let http_result = http_utils::post(&self.commit_url);
    handle_http_result(http_result)
  }

  /// Performs Solr query
  pub fn query(&self, query: &SolrQuery) -> SolrQueryResult {
    let mut query_url = self.select_url.clone();
    query_url.set_query_from_pairs(query.to_pairs().iter().map(|&(k,v)| (k,v)));
    let http_result = http_utils::get(&query_url);
    handle_http_result(http_result)
  }
}

fn handle_http_result<R: Decodable<JsonDecoder, DecoderError>>(result: IoResult<HttpResponse>) -> Result<R, SolrError> {
  match result {
    Ok(http_response) => {
      match http_response.code {
        200 => {
          let response: R = json::decode(http_response.body_str().unwrap()).unwrap();
          Ok(response)
        },
        _ => {
          let error: SolrError = json::decode(http_response.body_str().unwrap()).unwrap();
          Err(error)
        }
      }
    },
    Err(err) => {
      Err(SolrError{status: 0, time: 0, message: err.desc.to_string()})
    }
  }
}

<|endoftext|>


<commit_before>extern crate num;
#[macro_use]
extern crate approx;
extern crate angular_units as angle;

#[macro_use]
mod impl_macros;

pub mod channel;
pub mod convert;
pub mod color;
pub mod chromaticity;
pub mod linalg;

pub mod white_point;

pub mod encoding;
pub mod color_space;

pub mod alpha;

pub mod rgb;
pub mod rgi;
pub mod hsv;
pub mod hsl;
pub mod hwb;
pub mod hsi;
pub mod ehsi;
pub mod ycbcr;
pub mod xyz;
pub mod xyy;
pub mod lab;
pub mod lchab;
pub mod luv;
pub mod lchuv;
pub mod lms;

#[cfg(test)]
pub mod test;
<commit_msg>Reexport color types<commit_after>extern crate num;
#[macro_use]
extern crate approx;
extern crate angular_units as angle;

#[macro_use]
mod impl_macros;

pub mod channel;
pub mod convert;
pub mod color;
pub mod chromaticity;
pub mod linalg;

pub mod white_point;

pub mod encoding;
pub mod color_space;

pub mod alpha;

pub mod rgb;
pub mod rgi;
pub mod hsv;
pub mod hsl;
pub mod hwb;
pub mod hsi;
pub mod ehsi;
pub mod ycbcr;
pub mod xyz;
pub mod xyy;
pub mod lab;
pub mod lchab;
pub mod luv;
pub mod lchuv;
pub mod lms;

#[cfg(test)]
pub mod test;

pub use color::*;
pub use rgb::{Rgb, Rgba, RgbTag};
pub use rgi::{Rgi, RgiTag};
pub use hsv::{Hsv, Hsva, HsvTag};
pub use hsl::{Hsl, Hsla, HslTag};
pub use hwb::{Hwb, Hwba, HwbTag, HwbBoundedChannelTraits};
pub use hsi::{Hsi, HsiTag};
pub use ehsi::{eHsi, EHsiTag};
pub use xyz::{Xyz, XyzTag};
pub use xyy::{XyY, XyYTag};
pub use lab::{Lab, LabTag};
pub use lchab::{Lchab, LchabTag};
pub use luv::{Luv, LuvTag};
pub use lchuv::{Lchuv, LchuvTag};
pub use lms::{Lms, LmsModel, LmsTag, LmsBradford, LmsCam97s, LmsCam2002};
<|endoftext|>


<commit_before>#![crate_name = "bodyparser"]
#![feature(core, io)]

//! Body Parser Plugin for Iron
//!
//! This plugin parses JSON out of an incoming Request.

extern crate iron;
extern crate "rustc-serialize" as rustc_serialize;
extern crate plugin;
extern crate persistent;

use rustc_serialize::{json, Decodable};

use iron::mime;
use iron::prelude::*;
use iron::headers;
use iron::typemap::{Key};
use std::io::Read;
use std::marker;

pub use self::errors::{BodyError, BodyErrorCause};
pub use self::limit_reader::{LimitReader};

mod errors;
mod limit_reader;

fn read_body_as_utf8(req: &mut Request, limit: usize) -> Result<String, errors::BodyError> {
    let mut bytes = Vec::new();
    match LimitReader::new(req.body.by_ref(), limit).read_to_end(&mut bytes) {
        Ok(_) => {
             match String::from_utf8(bytes) {
                Ok(e) => Ok(e),
                Err(err) => Err(errors::BodyError {
                    detail: "Invalid UTF-8 sequence".to_string(),
                    cause: errors::BodyErrorCause::Utf8Error(err.utf8_error())
                })
            }
        },
        Err(err) => Err(errors::BodyError {
            detail: "Can't read request body".to_string(),
            cause: errors::BodyErrorCause::IoError(err)
        })
    }
}

/// Use this key to modify the default body limit.
pub struct MaxBodyLength;
impl Key for MaxBodyLength {
    type Value = usize;
}

/// Raw is a plugin to read a request body into UTF-8 String.
/// Doesn't read `multipart/form-data`.
pub struct Raw;

impl Key for Raw {
    type Value = Option<String>;
}

const DEFAULT_BODY_LIMIT: usize = 1024 * 1024 * 100;

impl<'a> plugin::Plugin<Request<'a>> for Raw {
    type Error = BodyError;

    fn eval(req: &mut Request) -> Result<Option<String>, BodyError> {
        let need_read = req.headers.get::<headers::ContentType>().map(|header| {
            match **header {
                mime::Mime(mime::TopLevel::Multipart, mime::SubLevel::FormData, _) => false,
                _ => true
            }
        }).unwrap_or(false);

        if need_read {
            let max_length = req.get::<persistent::Read<MaxBodyLength>>()
                .ok().cloned().unwrap_or(DEFAULT_BODY_LIMIT);
            let body = try!(read_body_as_utf8(req, max_length));
            Ok(Some(body))
        } else {
            Ok(None)
        }
    }
}

/// Json is a plugin to parse a request body into JSON.
/// Uses Raw plugin to parse the body with limit.
#[derive(Clone)]
pub struct Json;
impl Key for Json {
    type Value = Option<json::Json>;
}

impl<'a> plugin::Plugin<Request<'a>> for Json {
    type Error = BodyError;

    fn eval(req: &mut Request) -> Result<Option<json::Json>, BodyError> {
        req.get::<Raw>()
            .and_then(|maybe_body| {
                reverse_option(maybe_body.map(|body| body.parse()))
                    .map_err(|err| {
                        BodyError {
                            detail: "Can't parse body to JSON".to_string(),
                            cause: BodyErrorCause::ParserError(err)
                        }
                    })
            })
    }
}

/// Struct is a plugin to parse a request body into a struct.
/// Uses Raw plugin to parse the body with limit.
#[derive(Clone)]
pub struct Struct<T: Decodable> {
    marker: marker::PhantomData<T>
}
impl<T: 'static + Decodable> Key for Struct<T> {
    type Value = Option<T>;
}

impl<'a, T: 'static + Decodable> plugin::Plugin<Request<'a>> for Struct<T> {
    type Error = BodyError;

    fn eval(req: &mut Request) -> Result<Option<T>, BodyError> {
        req.get::<Json>()
            .and_then(|maybe_body| {
                reverse_option(maybe_body.map(|body| Decodable::decode(&mut json::Decoder::new(body))))
                    .map_err(|err| BodyError {
                        detail: "Can't parse body to the struct".to_string(),
                        cause: BodyErrorCause::DecoderError(err)
                    })
            })
    }
}

fn reverse_option<T,E>(value: Option<Result<T, E>>) -> Result<Option<T>, E> {
    match value {
        Some(Ok(val)) => Ok(Some(val)),
        Some(Err(err)) => Err(err),
        None => Ok(None),
    }
}<commit_msg>(fix) add 2nd lifetime parameter to Request<commit_after>#![crate_name = "bodyparser"]
#![feature(core, io)]

//! Body Parser Plugin for Iron
//!
//! This plugin parses JSON out of an incoming Request.

extern crate iron;
extern crate "rustc-serialize" as rustc_serialize;
extern crate plugin;
extern crate persistent;

use rustc_serialize::{json, Decodable};

use iron::mime;
use iron::prelude::*;
use iron::headers;
use iron::typemap::{Key};
use std::io::Read;
use std::marker;

pub use self::errors::{BodyError, BodyErrorCause};
pub use self::limit_reader::{LimitReader};

mod errors;
mod limit_reader;

fn read_body_as_utf8(req: &mut Request, limit: usize) -> Result<String, errors::BodyError> {
    let mut bytes = Vec::new();
    match LimitReader::new(req.body.by_ref(), limit).read_to_end(&mut bytes) {
        Ok(_) => {
             match String::from_utf8(bytes) {
                Ok(e) => Ok(e),
                Err(err) => Err(errors::BodyError {
                    detail: "Invalid UTF-8 sequence".to_string(),
                    cause: errors::BodyErrorCause::Utf8Error(err.utf8_error())
                })
            }
        },
        Err(err) => Err(errors::BodyError {
            detail: "Can't read request body".to_string(),
            cause: errors::BodyErrorCause::IoError(err)
        })
    }
}

/// Use this key to modify the default body limit.
pub struct MaxBodyLength;
impl Key for MaxBodyLength {
    type Value = usize;
}

/// Raw is a plugin to read a request body into UTF-8 String.
/// Doesn't read `multipart/form-data`.
pub struct Raw;

impl Key for Raw {
    type Value = Option<String>;
}

const DEFAULT_BODY_LIMIT: usize = 1024 * 1024 * 100;

impl<'a, 'b> plugin::Plugin<Request<'a, 'b>> for Raw {
    type Error = BodyError;

    fn eval(req: &mut Request) -> Result<Option<String>, BodyError> {
        let need_read = req.headers.get::<headers::ContentType>().map(|header| {
            match **header {
                mime::Mime(mime::TopLevel::Multipart, mime::SubLevel::FormData, _) => false,
                _ => true
            }
        }).unwrap_or(false);

        if need_read {
            let max_length = req.get::<persistent::Read<MaxBodyLength>>()
                .ok().cloned().unwrap_or(DEFAULT_BODY_LIMIT);
            let body = try!(read_body_as_utf8(req, max_length));
            Ok(Some(body))
        } else {
            Ok(None)
        }
    }
}

/// Json is a plugin to parse a request body into JSON.
/// Uses Raw plugin to parse the body with limit.
#[derive(Clone)]
pub struct Json;
impl Key for Json {
    type Value = Option<json::Json>;
}

impl<'a, 'b> plugin::Plugin<Request<'a, 'b>> for Json {
    type Error = BodyError;

    fn eval(req: &mut Request) -> Result<Option<json::Json>, BodyError> {
        req.get::<Raw>()
            .and_then(|maybe_body| {
                reverse_option(maybe_body.map(|body| body.parse()))
                    .map_err(|err| {
                        BodyError {
                            detail: "Can't parse body to JSON".to_string(),
                            cause: BodyErrorCause::ParserError(err)
                        }
                    })
            })
    }
}

/// Struct is a plugin to parse a request body into a struct.
/// Uses Raw plugin to parse the body with limit.
#[derive(Clone)]
pub struct Struct<T: Decodable> {
    marker: marker::PhantomData<T>
}
impl<T: 'static + Decodable> Key for Struct<T> {
    type Value = Option<T>;
}

impl<'a, 'b, T: 'static + Decodable> plugin::Plugin<Request<'a, 'b>> for Struct<T> {
    type Error = BodyError;

    fn eval(req: &mut Request) -> Result<Option<T>, BodyError> {
        req.get::<Json>()
            .and_then(|maybe_body| {
                reverse_option(maybe_body.map(|body| Decodable::decode(&mut json::Decoder::new(body))))
                    .map_err(|err| BodyError {
                        detail: "Can't parse body to the struct".to_string(),
                        cause: BodyErrorCause::DecoderError(err)
                    })
            })
    }
}

fn reverse_option<T,E>(value: Option<Result<T, E>>) -> Result<Option<T>, E> {
    match value {
        Some(Ok(val)) => Ok(Some(val)),
        Some(Err(err)) => Err(err),
        None => Ok(None),
    }
}<|endoftext|>


<commit_before>#![crate_type="dylib"]
#![feature(plugin_registrar, rustc_private)]
extern crate syntax;
extern crate rustc;

extern crate rustc_plugin;

#[macro_use]
extern crate bitflags;

use rustc_plugin::Registry;

use syntax::ast;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, Annotatable};
use syntax::ext::base::SyntaxExtension::MultiModifier;
use syntax::ext::build::AstBuilder;
use syntax::parse::token::intern;
use syntax::ptr::P;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(intern("apply_attr"), MultiModifier(Box::new(expand)));
}

bitflags! {
    flags ItemMask: u16 {
        const ITEM_NONE         = 0b0,
        const ITEM_EXT_CRATE    = 0b1 <<  0,
        const ITEM_USE          = 0b1 <<  1,
        const ITEM_STATIC       = 0b1 <<  2,
        const ITEM_CONST        = 0b1 <<  3,
        const ITEM_FN           = 0b1 <<  4,
        const ITEM_MOD          = 0b1 <<  5,
        const ITEM_FGN_MOD      = 0b1 <<  6,
        const ITEM_TY           = 0b1 <<  7,
        const ITEM_ENUM         = 0b1 <<  8,
        const ITEM_STRUCT       = 0b1 <<  9,
        const ITEM_TRAIT        = 0b1 << 10,
        const ITEM_DEF_IMPL     = 0b1 << 11,
        const ITEM_IMPL         = 0b1 << 12,
        const ITEM_MAC          = 0b1 << 13,
    }
}

type Selector = P<ast::MetaItem>;
type Selectors<'a> = &'a [Selector];

trait SelectorValidation {
    fn validate(&self, ctx: &mut ExtCtxt) -> bool;
}

impl SelectorValidation for Selector {
    fn validate(&self, ctx: &mut ExtCtxt) -> bool {
        match self.node {
            ast::MetaItemKind::List(ref name, ref sub_selectors) => {
                let valid_item = match &**name {
                    "mods" | "traits" | "impls" => true,
                    _ => {
                        let error_msg = format!("Unrecognized selector `{}(...)`.", name);
                        ctx.span_err(self.span, &error_msg);
                        false
                    }
                };
                let valid_sub_selectors = sub_selectors.iter()
                    .fold(true,
                          |valid, sub_selector| valid & sub_selector.validate(ctx));
                valid_item & valid_sub_selectors
            }
            ast::MetaItemKind::Word(ref name) => {
                let valid_item = match &**name {
                    "crates" | "uses" | "statics" | "consts" | "fns" | "mods" | "fgn_mods" |
                    "types" | "enums" | "structs" | "traits" | "def_impls" | "impls" | "macros" => {
                        true
                    }
                    _ => {
                        let error_msg = format!("Unrecognized selector `{}`.", name);
                        ctx.span_err(self.span, &error_msg);
                        false
                    }
                };
                valid_item
            }
            ast::MetaItemKind::NameValue(ref name, ref _value) => {
                let valid_item = false;
                let error_msg = format!("Unexpected name value pair `{} = ...`.", name);
                ctx.span_err(self.span, &error_msg);
                valid_item
            }
        }
    }
}

type Attribute = syntax::codemap::Spanned<syntax::ast::Attribute_>;
enum Attributes {
    Default(Vec<Attribute>),
    Override(Vec<Attribute>),
}

impl Attributes {
    fn augment(&self, existing: &[Attribute]) -> Vec<Attribute> {
        let mut expanded_attrs = vec![];
        match self {
            &Attributes::Default(ref attrs) => {
                expanded_attrs.extend(attrs.iter().cloned());
                expanded_attrs.extend(existing.iter().cloned());
            }
            &Attributes::Override(ref attrs) => {
                expanded_attrs.extend(existing.iter().cloned());
                expanded_attrs.extend(attrs.iter().cloned());
            }
        }
        expanded_attrs
    }
}

fn expand(ctx: &mut ExtCtxt, span: Span, meta: &ast::MetaItem, ann: Annotatable) -> Annotatable {
    if let Some((selectors, attributes)) = extract_meta(ctx, meta) {
        fn not_applicable(ctx: &mut ExtCtxt, span: Span) {
            ctx.span_err(span, "Only applicable to `mod`, `trait` or `impl` items.");
        }
        match ann {
            Annotatable::Item(item_ptr) => {
                let ptr = item_ptr.map(|item| {
                    match item.node {
                        ast::ItemKind::Mod(..) |
                        ast::ItemKind::Trait(..) |
                        ast::ItemKind::Impl(..) => {}
                        _ => {
                            not_applicable(ctx, span);
                        }
                    }
                    expand_item(ctx, item, selectors, &attributes, true)
                });
                Annotatable::Item(ptr)
            }
            Annotatable::TraitItem(item_ptr) => {
                not_applicable(ctx, span);
                let ptr =
                    item_ptr.map(|item| expand_trait_item(ctx, item, selectors, &attributes, true));
                Annotatable::TraitItem(ptr)
            }
            Annotatable::ImplItem(item_ptr) => {
                not_applicable(ctx, span);
                let ptr =
                    item_ptr.map(|item| expand_impl_item(ctx, item, selectors, &attributes, true));
                Annotatable::ImplItem(ptr)
            }
        }
    } else {
        ann
    }
}

fn expand_item(ctx: &mut ExtCtxt,
               item: ast::Item,
               selectors: Selectors,
               attributes: &Attributes,
               is_root: bool)
               -> ast::Item {
    let item_mask = map_item_to_mask(&item);
    let selector_mask = extract_mask_from_selectors(selectors);
    let sub_selectors = if is_root {
        selectors.to_owned() // simply forward selectors for root item
    } else {
        extract_sub_selectors(selectors, item_mask)
    };
    let augmented_attributes = fold_attributes(item_mask, selector_mask, &item.attrs, &attributes);
    let node = match item.node {
        ast::ItemKind::Mod(m) => {
            let expanded_items = m.items
                .into_iter()
                .map(|item_ptr| {
                    item_ptr.map(|item| expand_item(ctx, item, &sub_selectors, attributes, false))
                });
            ast::ItemKind::Mod(ast::Mod {
                inner: m.inner,
                items: expanded_items.collect(),
            })
        }
        ast::ItemKind::Trait(unsafety, generics, bounds, items) => {
            let expanded_items = items.into_iter()
                .map(|item| expand_trait_item(ctx, item, &sub_selectors, attributes, false));
            ast::ItemKind::Trait(unsafety, generics, bounds, expanded_items.collect())
        }
        ast::ItemKind::Impl(unsafety, polarity, generics, trt, typ, items) => {
            let expanded_items = items.into_iter()
                .map(|item| expand_impl_item(ctx, item, &sub_selectors, attributes, false));
            ast::ItemKind::Impl(unsafety,
                                polarity,
                                generics,
                                trt,
                                typ,
                                expanded_items.collect())
        }
        _ => item.node,
    };
    ast::Item {
        node: node,
        attrs: augmented_attributes,
        ..item
    }
}

fn expand_trait_item(_ctx: &mut ExtCtxt,
                     item: ast::TraitItem,
                     selectors: Selectors,
                     attributes: &Attributes,
                     _is_root: bool)
                     -> ast::TraitItem {
    let item_mask = map_trait_item_to_mask(&item);
    let selector_mask = extract_mask_from_selectors(selectors);
    let augmented_attributes = fold_attributes(item_mask, selector_mask, &item.attrs, &attributes);
    ast::TraitItem { attrs: augmented_attributes, ..item }
}

fn expand_impl_item(_ctx: &mut ExtCtxt,
                    item: ast::ImplItem,
                    selectors: Selectors,
                    attributes: &Attributes,
                    _is_root: bool)
                    -> ast::ImplItem {
    let item_mask = map_impl_item_to_mask(&item);
    let selector_mask = extract_mask_from_selectors(selectors);
    let augmented_attributes = fold_attributes(item_mask, selector_mask, &item.attrs, &attributes);
    ast::ImplItem { attrs: augmented_attributes, ..item }
}

fn extract_mask_from_selectors(selectors: Selectors) -> ItemMask {
    selectors.iter().fold(ITEM_NONE, |mask, selector| {
        mask |
        match (*selector).node {
            ast::MetaItemKind::Word(ref name) => map_selector_to_mask(&**name),
            _ => ITEM_NONE,
        }
    })
}

fn extract_sub_selectors(selectors: Selectors, mask: ItemMask) -> Vec<Selector> {
    for selector in selectors {
        if let ast::MetaItemKind::List(ref name, ref vec) = (*selector).node {
            if mask & map_selector_to_mask(&**name) != ITEM_NONE {
                return vec.clone();
            }
        }
    }
    vec![]
}

fn extract_meta<'a>(ctx: &mut ExtCtxt,
                    meta: &'a ast::MetaItem)
                    -> Option<(Selectors<'a>, Attributes)> {
    if let ast::MetaItemKind::List(_, ref vec) = meta.node {
        if vec.len() == 2 {
            let selectors = extract_selectors(ctx, &*vec[0]);
            let attributes = extract_attributes(ctx, &*vec[1]);
            if let (Some(selectors), Some(attributes)) = (selectors, attributes) {
                return Some((selectors, attributes));
            }
        }
    }
    ctx.span_err(meta.span,
                 "Expected 'apply_attr(to(...), as_default|as_override(...))'.");
    None
}

fn fold_attributes(item_mask: ItemMask,
                   selector_mask: ItemMask,
                   item_attributes: &[Attribute],
                   attributes: &Attributes)
                   -> Vec<Attribute> {
    if (selector_mask & item_mask) != ITEM_NONE {
        attributes.augment(&item_attributes)
    } else {
        item_attributes.to_owned()
    }
}

fn extract_selectors<'a>(ctx: &mut ExtCtxt, meta: &'a ast::MetaItem) -> Option<Selectors<'a>> {
    if let &ast::MetaItemKind::List(ref name, ref selectors) = &meta.node {
        if name == "to" {
            let valid_selectors = selectors.iter()
                .fold(true, |valid, selector| valid & selector.validate(ctx));
            if !valid_selectors {
                return None;
            }
            return Some(selectors);
        }
    }
    ctx.span_err(meta.span, "Expected `to(...)`.");
    None
}

fn extract_attributes(ctx: &mut ExtCtxt, meta: &ast::MetaItem) -> Option<Attributes> {
    if let ast::MetaItemKind::List(ref name, ref vec) = meta.node {
        let attributes = vec.iter().map(|meta| ctx.attribute(meta.span, meta.clone()));
        if name == "as_default" {
            return Some(Attributes::Default(attributes.collect()));
        } else if name == "as_override" {
            return Some(Attributes::Override(attributes.collect()));
        }
    }
    ctx.span_err(meta.span, "Expected `as_default(...)` or `as_override(...)`.");
    None
}

fn map_selector_to_mask(selector: &str) -> ItemMask {
    match selector {
        "crates" => ITEM_EXT_CRATE,
        "uses" => ITEM_USE,
        "statics" => ITEM_STATIC,
        "consts" => ITEM_CONST,
        "fns" => ITEM_FN,
        "mods" => ITEM_MOD,
        "fgn_mods" => ITEM_FGN_MOD,
        "types" => ITEM_TY,
        "enums" => ITEM_ENUM,
        "structs" => ITEM_STRUCT,
        "traits" => ITEM_TRAIT,
        "def_impls" => ITEM_DEF_IMPL,
        "impls" => ITEM_IMPL,
        "macros" => ITEM_MAC,
        _ => ITEM_NONE,
    }
}

fn map_item_to_mask(item: &ast::Item) -> ItemMask {
    match item.node {
        ast::ItemKind::ExternCrate(..) => ITEM_EXT_CRATE,
        ast::ItemKind::Use(..) => ITEM_USE,
        ast::ItemKind::Static(..) => ITEM_STATIC,
        ast::ItemKind::Const(..) => ITEM_CONST,
        ast::ItemKind::Fn(..) => ITEM_FN,
        ast::ItemKind::Mod(..) => ITEM_MOD,
        ast::ItemKind::ForeignMod(..) => ITEM_FGN_MOD,
        ast::ItemKind::Ty(..) => ITEM_TY,
        ast::ItemKind::Enum(..) => ITEM_ENUM,
        ast::ItemKind::Struct(..) => ITEM_STRUCT,
        ast::ItemKind::Trait(..) => ITEM_TRAIT,
        ast::ItemKind::DefaultImpl(..) => ITEM_DEF_IMPL,
        ast::ItemKind::Impl(..) => ITEM_IMPL,
        ast::ItemKind::Mac(..) => ITEM_MAC,
    }
}

fn map_trait_item_to_mask(item: &ast::TraitItem) -> ItemMask {
    match item.node {
        ast::TraitItemKind::Const(..) => ITEM_CONST,
        ast::TraitItemKind::Method(..) => ITEM_FN,
        ast::TraitItemKind::Type(..) => ITEM_TY,
    }
}

fn map_impl_item_to_mask(item: &ast::ImplItem) -> ItemMask {
    match item.node {
        ast::ImplItemKind::Const(..) => ITEM_CONST,
        ast::ImplItemKind::Method(..) => ITEM_FN,
        ast::ImplItemKind::Type(..) => ITEM_TY,
        ast::ImplItemKind::Macro(..) => ITEM_MAC,
    }
}
<commit_msg>Fix Clippy warnings (#1)<commit_after>#![crate_type="dylib"]
#![feature(plugin_registrar, rustc_private)]
extern crate syntax;
extern crate rustc;

extern crate rustc_plugin;

#[macro_use]
extern crate bitflags;

use rustc_plugin::Registry;

use syntax::ast;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, Annotatable};
use syntax::ext::base::SyntaxExtension::MultiModifier;
use syntax::ext::build::AstBuilder;
use syntax::parse::token::intern;
use syntax::ptr::P;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(intern("apply_attr"), MultiModifier(Box::new(expand)));
}

bitflags! {
    flags ItemMask: u16 {
        const ITEM_NONE         = 0b0,
        const ITEM_EXT_CRATE    = 0b1 <<  0,
        const ITEM_USE          = 0b1 <<  1,
        const ITEM_STATIC       = 0b1 <<  2,
        const ITEM_CONST        = 0b1 <<  3,
        const ITEM_FN           = 0b1 <<  4,
        const ITEM_MOD          = 0b1 <<  5,
        const ITEM_FGN_MOD      = 0b1 <<  6,
        const ITEM_TY           = 0b1 <<  7,
        const ITEM_ENUM         = 0b1 <<  8,
        const ITEM_STRUCT       = 0b1 <<  9,
        const ITEM_TRAIT        = 0b1 << 10,
        const ITEM_DEF_IMPL     = 0b1 << 11,
        const ITEM_IMPL         = 0b1 << 12,
        const ITEM_MAC          = 0b1 << 13,
    }
}

type Selector = P<ast::MetaItem>;
type Selectors<'a> = &'a [Selector];

trait SelectorValidation {
    fn validate(&self, ctx: &mut ExtCtxt) -> bool;
}

impl SelectorValidation for Selector {
    fn validate(&self, ctx: &mut ExtCtxt) -> bool {
        match self.node {
            ast::MetaItemKind::List(ref name, ref sub_selectors) => {
                let valid_item = match &**name {
                    "mods" | "traits" | "impls" => true,
                    _ => {
                        let error_msg = format!("Unrecognized selector `{}(...)`.", name);
                        ctx.span_err(self.span, &error_msg);
                        false
                    }
                };
                let valid_sub_selectors = sub_selectors.iter()
                    .fold(true,
                          |valid, sub_selector| valid & sub_selector.validate(ctx));
                valid_item & valid_sub_selectors
            }
            ast::MetaItemKind::Word(ref name) => {
                match &**name {
                    "crates" | "uses" | "statics" | "consts" | "fns" | "mods" | "fgn_mods" |
                    "types" | "enums" | "structs" | "traits" | "def_impls" | "impls" | "macros" => {
                        true
                    }
                    _ => {
                        let error_msg = format!("Unrecognized selector `{}`.", name);
                        ctx.span_err(self.span, &error_msg);
                        false
                    }
                }
            }
            ast::MetaItemKind::NameValue(ref name, ref _value) => {
                let valid_item = false;
                let error_msg = format!("Unexpected name value pair `{} = ...`.", name);
                ctx.span_err(self.span, &error_msg);
                valid_item
            }
        }
    }
}

type Attribute = syntax::codemap::Spanned<syntax::ast::Attribute_>;
enum Attributes {
    Default(Vec<Attribute>),
    Override(Vec<Attribute>),
}

impl Attributes {
    fn augment(&self, existing: &[Attribute]) -> Vec<Attribute> {
        let mut expanded_attrs = vec![];
        match *self {
            Attributes::Default(ref attrs) => {
                expanded_attrs.extend(attrs.iter().cloned());
                expanded_attrs.extend(existing.iter().cloned());
            }
            Attributes::Override(ref attrs) => {
                expanded_attrs.extend(existing.iter().cloned());
                expanded_attrs.extend(attrs.iter().cloned());
            }
        }
        expanded_attrs
    }
}

fn expand(ctx: &mut ExtCtxt, span: Span, meta: &ast::MetaItem, ann: Annotatable) -> Annotatable {
    if let Some((selectors, attributes)) = extract_meta(ctx, meta) {
        fn not_applicable(ctx: &mut ExtCtxt, span: Span) {
            ctx.span_err(span, "Only applicable to `mod`, `trait` or `impl` items.");
        }
        match ann {
            Annotatable::Item(item_ptr) => {
                let ptr = item_ptr.map(|item| {
                    match item.node {
                        ast::ItemKind::Mod(..) |
                        ast::ItemKind::Trait(..) |
                        ast::ItemKind::Impl(..) => {}
                        _ => {
                            not_applicable(ctx, span);
                        }
                    }
                    expand_item(ctx, item, selectors, &attributes, true)
                });
                Annotatable::Item(ptr)
            }
            Annotatable::TraitItem(item_ptr) => {
                not_applicable(ctx, span);
                let ptr =
                    item_ptr.map(|item| expand_trait_item(ctx, item, selectors, &attributes, true));
                Annotatable::TraitItem(ptr)
            }
            Annotatable::ImplItem(item_ptr) => {
                not_applicable(ctx, span);
                let ptr =
                    item_ptr.map(|item| expand_impl_item(ctx, item, selectors, &attributes, true));
                Annotatable::ImplItem(ptr)
            }
        }
    } else {
        ann
    }
}

fn expand_item(ctx: &mut ExtCtxt,
               item: ast::Item,
               selectors: Selectors,
               attributes: &Attributes,
               is_root: bool)
               -> ast::Item {
    let item_mask = map_item_to_mask(&item);
    let selector_mask = extract_mask_from_selectors(selectors);
    let sub_selectors = if is_root {
        selectors.to_owned() // simply forward selectors for root item
    } else {
        extract_sub_selectors(selectors, item_mask)
    };
    let augmented_attributes = fold_attributes(item_mask, selector_mask, &item.attrs, attributes);
    let node = match item.node {
        ast::ItemKind::Mod(m) => {
            let expanded_items = m.items
                .into_iter()
                .map(|item_ptr| {
                    item_ptr.map(|item| expand_item(ctx, item, &sub_selectors, attributes, false))
                });
            ast::ItemKind::Mod(ast::Mod {
                inner: m.inner,
                items: expanded_items.collect(),
            })
        }
        ast::ItemKind::Trait(unsafety, generics, bounds, items) => {
            let expanded_items = items.into_iter()
                .map(|item| expand_trait_item(ctx, item, &sub_selectors, attributes, false));
            ast::ItemKind::Trait(unsafety, generics, bounds, expanded_items.collect())
        }
        ast::ItemKind::Impl(unsafety, polarity, generics, trt, typ, items) => {
            let expanded_items = items.into_iter()
                .map(|item| expand_impl_item(ctx, item, &sub_selectors, attributes, false));
            ast::ItemKind::Impl(unsafety,
                                polarity,
                                generics,
                                trt,
                                typ,
                                expanded_items.collect())
        }
        _ => item.node,
    };
    ast::Item {
        node: node,
        attrs: augmented_attributes,
        ..item
    }
}

fn expand_trait_item(_ctx: &mut ExtCtxt,
                     item: ast::TraitItem,
                     selectors: Selectors,
                     attributes: &Attributes,
                     _is_root: bool)
                     -> ast::TraitItem {
    let item_mask = map_trait_item_to_mask(&item);
    let selector_mask = extract_mask_from_selectors(selectors);
    let augmented_attributes = fold_attributes(item_mask, selector_mask, &item.attrs, attributes);
    ast::TraitItem { attrs: augmented_attributes, ..item }
}

fn expand_impl_item(_ctx: &mut ExtCtxt,
                    item: ast::ImplItem,
                    selectors: Selectors,
                    attributes: &Attributes,
                    _is_root: bool)
                    -> ast::ImplItem {
    let item_mask = map_impl_item_to_mask(&item);
    let selector_mask = extract_mask_from_selectors(selectors);
    let augmented_attributes = fold_attributes(item_mask, selector_mask, &item.attrs, attributes);
    ast::ImplItem { attrs: augmented_attributes, ..item }
}

fn extract_mask_from_selectors(selectors: Selectors) -> ItemMask {
    selectors.iter().fold(ITEM_NONE, |mask, selector| {
        mask |
        match (*selector).node {
            ast::MetaItemKind::Word(ref name) => map_selector_to_mask(&**name),
            _ => ITEM_NONE,
        }
    })
}

fn extract_sub_selectors(selectors: Selectors, mask: ItemMask) -> Vec<Selector> {
    for selector in selectors {
        if let ast::MetaItemKind::List(ref name, ref vec) = (*selector).node {
            if mask & map_selector_to_mask(&**name) != ITEM_NONE {
                return vec.clone();
            }
        }
    }
    vec![]
}

fn extract_meta<'a>(ctx: &mut ExtCtxt,
                    meta: &'a ast::MetaItem)
                    -> Option<(Selectors<'a>, Attributes)> {
    if let ast::MetaItemKind::List(_, ref vec) = meta.node {
        if vec.len() == 2 {
            let selectors = extract_selectors(ctx, &*vec[0]);
            let attributes = extract_attributes(ctx, &*vec[1]);
            if let (Some(selectors), Some(attributes)) = (selectors, attributes) {
                return Some((selectors, attributes));
            }
        }
    }
    ctx.span_err(meta.span,
                 "Expected 'apply_attr(to(...), as_default|as_override(...))'.");
    None
}

fn fold_attributes(item_mask: ItemMask,
                   selector_mask: ItemMask,
                   item_attributes: &[Attribute],
                   attributes: &Attributes)
                   -> Vec<Attribute> {
    if (selector_mask & item_mask) != ITEM_NONE {
        attributes.augment(item_attributes)
    } else {
        item_attributes.to_owned()
    }
}

fn extract_selectors<'a>(ctx: &mut ExtCtxt, meta: &'a ast::MetaItem) -> Option<Selectors<'a>> {
    if let ast::MetaItemKind::List(ref name, ref selectors) = meta.node {
        if name == "to" {
            let valid_selectors = selectors.iter()
                .fold(true, |valid, selector| valid & selector.validate(ctx));
            if !valid_selectors {
                return None;
            }
            return Some(selectors);
        }
    }
    ctx.span_err(meta.span, "Expected `to(...)`.");
    None
}

fn extract_attributes(ctx: &mut ExtCtxt, meta: &ast::MetaItem) -> Option<Attributes> {
    if let ast::MetaItemKind::List(ref name, ref vec) = meta.node {
        let attributes = vec.iter().map(|meta| ctx.attribute(meta.span, meta.clone()));
        if name == "as_default" {
            return Some(Attributes::Default(attributes.collect()));
        } else if name == "as_override" {
            return Some(Attributes::Override(attributes.collect()));
        }
    }
    ctx.span_err(meta.span, "Expected `as_default(...)` or `as_override(...)`.");
    None
}

fn map_selector_to_mask(selector: &str) -> ItemMask {
    match selector {
        "crates" => ITEM_EXT_CRATE,
        "uses" => ITEM_USE,
        "statics" => ITEM_STATIC,
        "consts" => ITEM_CONST,
        "fns" => ITEM_FN,
        "mods" => ITEM_MOD,
        "fgn_mods" => ITEM_FGN_MOD,
        "types" => ITEM_TY,
        "enums" => ITEM_ENUM,
        "structs" => ITEM_STRUCT,
        "traits" => ITEM_TRAIT,
        "def_impls" => ITEM_DEF_IMPL,
        "impls" => ITEM_IMPL,
        "macros" => ITEM_MAC,
        _ => ITEM_NONE,
    }
}

fn map_item_to_mask(item: &ast::Item) -> ItemMask {
    match item.node {
        ast::ItemKind::ExternCrate(..) => ITEM_EXT_CRATE,
        ast::ItemKind::Use(..) => ITEM_USE,
        ast::ItemKind::Static(..) => ITEM_STATIC,
        ast::ItemKind::Const(..) => ITEM_CONST,
        ast::ItemKind::Fn(..) => ITEM_FN,
        ast::ItemKind::Mod(..) => ITEM_MOD,
        ast::ItemKind::ForeignMod(..) => ITEM_FGN_MOD,
        ast::ItemKind::Ty(..) => ITEM_TY,
        ast::ItemKind::Enum(..) => ITEM_ENUM,
        ast::ItemKind::Struct(..) => ITEM_STRUCT,
        ast::ItemKind::Trait(..) => ITEM_TRAIT,
        ast::ItemKind::DefaultImpl(..) => ITEM_DEF_IMPL,
        ast::ItemKind::Impl(..) => ITEM_IMPL,
        ast::ItemKind::Mac(..) => ITEM_MAC,
    }
}

fn map_trait_item_to_mask(item: &ast::TraitItem) -> ItemMask {
    match item.node {
        ast::TraitItemKind::Const(..) => ITEM_CONST,
        ast::TraitItemKind::Method(..) => ITEM_FN,
        ast::TraitItemKind::Type(..) => ITEM_TY,
    }
}

fn map_impl_item_to_mask(item: &ast::ImplItem) -> ItemMask {
    match item.node {
        ast::ImplItemKind::Const(..) => ITEM_CONST,
        ast::ImplItemKind::Method(..) => ITEM_FN,
        ast::ImplItemKind::Type(..) => ITEM_TY,
        ast::ImplItemKind::Macro(..) => ITEM_MAC,
    }
}
<|endoftext|>


<commit_before>#![feature(lang_items)]
#![feature(const_fn)]
#![feature(unique)]
#![feature(custom_attribute)]
#![feature(asm)]
#![no_std]

extern crate rlibc;
extern crate spin;

#[macro_use]
mod vga_buffer;

#[no_mangle]
pub extern fn rust_main() {
    // ATTENTION: we have a very small stack and no guard page

    vga_buffer::clear_screen();
    println!("Hello, world{}", "!");

    loop{}
}

#[lang = "eh_personality"] extern fn eh_personality() { }
#[lang = "panic_fmt"] extern fn panic_fmt() -> ! {loop { }}
<commit_msg>update panic function<commit_after>#![feature(lang_items)]
#![feature(const_fn)]
#![feature(unique)]
#![feature(custom_attribute)]
#![feature(asm)]
#![no_std]

extern crate rlibc;
extern crate spin;

#[macro_use]
mod vga_buffer;

#[no_mangle]
pub extern fn rust_main() {
    // ATTENTION: we have a very small stack and no guard page

    vga_buffer::clear_screen();
    println!("Hello, world{}", "!");

    loop{}
}

#[lang = "eh_personality"] extern fn eh_personality() { }
#[lang = "panic_fmt"]
extern fn panic_fmt(fmt: core::fmt::Arguments, file: &str, line: u32) -> ! {
    println!("\n\nPANIC in {} at line {}:", file, line);
    println!("    {}", fmt);
    loop{}
}
<|endoftext|>


<commit_before>//! A TOML-parsing library
//!
//! This library is an implementation in Rust of a parser for TOML configuration
//! files [1]. It is focused around high quality errors including specific spans
//! and detailed error messages when things go wrong.
//!
//! This implementation currently passes the language agnostic [test suite][2].
//!
//! # Example
//!
//! ```
//! let toml = r#"
//!     [test]
//!     foo = "bar"
//! "#;
//!
//! let value = toml::Parser::new(toml).parse().unwrap();
//! println!("{:?}", value);
//! ```
//!
//! # Conversions
//!
//! This library also supports using the standard `Encodable` and `Decodable`
//! traits with TOML values. This library provides the following conversion
//! capabilities:
//!
//! * `String` => `toml::Value` - via `Parser`
//! * `toml::Value` => `String` - via `Display`
//! * `toml::Value` => rust object - via `Decoder`
//! * rust object => `toml::Value` - via `Encoder`
//!
//! Convenience functions for performing multiple conversions at a time are also
//! provided.
//!
//! [1]: https://github.com/mojombo/toml
//! [2]: https://github.com/BurntSushi/toml-test

#![doc(html_root_url = "http://alexcrichton.com/toml-rs")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

#[cfg(feature = "rustc-serialize")] extern crate rustc_serialize;
#[cfg(feature = "serde")] extern crate serde;

use std::collections::BTreeMap;
use std::str::FromStr;
use std::str::Split;

pub use parser::{Parser, ParserError};

#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
pub use self::encoder::{Encoder, Error, encode, encode_str};
#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
pub use self::decoder::{Decoder, DecodeError, DecodeErrorKind, decode, decode_str};

mod parser;
mod display;
#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
mod encoder;
#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
mod decoder;

/// Representation of a TOML value.
#[derive(PartialEq, Clone, Debug)]
#[allow(missing_docs)]
pub enum Value {
    String(String),
    Integer(i64),
    Float(f64),
    Boolean(bool),
    Datetime(String),
    Array(Array),
    Table(Table),
}

/// Type representing a TOML array, payload of the Value::Array variant
pub type Array = Vec<Value>;

/// Type representing a TOML table, payload of the Value::Table variant
pub type Table = BTreeMap<String, Value>;

impl Value {
    /// Tests whether this and another value have the same type.
    pub fn same_type(&self, other: &Value) -> bool {
        match (self, other) {
            (&Value::String(..), &Value::String(..)) |
            (&Value::Integer(..), &Value::Integer(..)) |
            (&Value::Float(..), &Value::Float(..)) |
            (&Value::Boolean(..), &Value::Boolean(..)) |
            (&Value::Datetime(..), &Value::Datetime(..)) |
            (&Value::Array(..), &Value::Array(..)) |
            (&Value::Table(..), &Value::Table(..)) => true,

            _ => false,
        }
    }

    /// Returns a human-readable representation of the type of this value.
    pub fn type_str(&self) -> &'static str {
        match *self {
            Value::String(..) => "string",
            Value::Integer(..) => "integer",
            Value::Float(..) => "float",
            Value::Boolean(..) => "boolean",
            Value::Datetime(..) => "datetime",
            Value::Array(..) => "array",
            Value::Table(..) => "table",
        }
    }

    /// Extracts the string of this value if it is a string.
    pub fn as_str(&self) -> Option<&str> {
        match *self { Value::String(ref s) => Some(&**s), _ => None }
    }

    /// Extracts the integer value if it is an integer.
    pub fn as_integer(&self) -> Option<i64> {
        match *self { Value::Integer(i) => Some(i), _ => None }
    }

    /// Extracts the float value if it is a float.
    pub fn as_float(&self) -> Option<f64> {
        match *self { Value::Float(f) => Some(f), _ => None }
    }

    /// Extracts the boolean value if it is a boolean.
    pub fn as_bool(&self) -> Option<bool> {
        match *self { Value::Boolean(b) => Some(b), _ => None }
    }

    /// Extracts the datetime value if it is a datetime.
    ///
    /// Note that a parsed TOML value will only contain ISO 8601 dates. An
    /// example date is:
    ///
    /// ```notrust
    /// 1979-05-27T07:32:00Z
    /// ```
    pub fn as_datetime(&self) -> Option<&str> {
        match *self { Value::Datetime(ref s) => Some(&**s), _ => None }
    }

    /// Extracts the array value if it is an array.
    pub fn as_slice(&self) -> Option<&[Value]> {
        match *self { Value::Array(ref s) => Some(&**s), _ => None }
    }

    /// Extracts the table value if it is a table.
    pub fn as_table(&self) -> Option<&Table> {
        match *self { Value::Table(ref s) => Some(s), _ => None }
    }

    /// Lookups for value at specified path.
    ///
    /// Uses '.' as a path separator.
    ///
    /// Note: arrays have zero-based indexes.
    ///
    /// Note: empty path returns self.
    ///
    /// ```
    /// # #![allow(unstable)]
    /// let toml = r#"
    ///      [test]
    ///      foo = "bar"
    ///
    ///      [[values]]
    ///      foo = "baz"
    ///
    ///      [[values]]
    ///      foo = "qux"
    /// "#;
    /// let value: toml::Value = toml.parse().unwrap();
    ///
    /// let foo = value.lookup("test.foo").unwrap();
    /// assert_eq!(foo.as_str().unwrap(), "bar");
    ///
    /// let foo = value.lookup("values.1.foo").unwrap();
    /// assert_eq!(foo.as_str().unwrap(), "qux");
    ///
    /// let no_bar = value.lookup("test.bar");
    /// assert_eq!(no_bar.is_none(), true);
    /// ```
    pub fn lookup<'a>(&'a self, path: &'a str) -> Option<&'a Value> {
        let mut cur_value = self;
        if path.len() == 0 {
            return Some(cur_value)
        }

        for key in path.split('.') {
            match *cur_value {
                Value::Table(ref hm) => {
                    match hm.get(key) {
                        Some(v) => cur_value = v,
                        None => return None
                    }
                },
                Value::Array(ref v) => {
                    match key.parse::<usize>().ok() {
                        Some(idx) if idx < v.len() => cur_value = &v[idx],
                        _ => return None
                    }
                },
                _ => return None
            }
        };

        Some(cur_value)
    }

    fn lookup_mut_recurse<'a>(&'a mut self, matches: &mut Split<'a, char>) -> Option<&'a mut Value> {
        if let Some(key) = matches.next() {
            match *self {
                Value::Table(ref mut hm) => {
                    match hm.get_mut(key) {
                      Some(v) => return v.lookup_mut_recurse(matches),
                      None => return None,
                  }
              },
              Value::Array(ref mut v) => {
                  match key.parse::<usize>().ok() {
                      Some(idx) if idx < v.len()
                          => return (&mut v[idx]).lookup_mut_recurse(matches),
                        _ => return None,
                    }
                },
            _ => return None
            }
        }
        Some(self)
    }

    /// Lookups for mutable value at specified path.
    ///
    /// Uses '.' as a path separator.
    ///
    /// Note: arrays have zero-based indexes.
    ///
    /// Note: empty path returns self.
    ///
    /// ```
    /// # #![allow(unstable)]
    /// let toml = r#"
    ///      [test]
    ///      foo = "bar"
    ///
    ///      [[values]]
    ///      foo = "baz"
    ///
    ///      [[values]]
    ///      foo = "qux"
    /// "#;
    /// let mut value: toml::Value = toml.parse().unwrap();
    /// {
    ///    let string = value.lookup_mut("test.foo").unwrap();
    ///    assert_eq!(string, &mut toml::Value::String(String::from("bar")));
    ///    *string = toml::Value::String(String::from("foo"));
    /// }
    /// let result = value.lookup_mut("test.foo").unwrap();
    /// assert_eq!(result.as_str().unwrap(), "foo");
    /// ```
    pub fn lookup_mut<'a>(&'a mut self, path: &'a str) -> Option<&'a mut Value> {
      if path.len() == 0 {
          return Some(self)
      }

      let mut matches = path.split('.');
      self.lookup_mut_recurse(&mut matches)
  }

}

impl FromStr for Value {
    type Err = Vec<ParserError>;
    fn from_str(s: &str) -> Result<Value, Vec<ParserError>> {
        let mut p = Parser::new(s);
        match p.parse().map(Value::Table) {
            Some(n) => Ok(n),
            None => Err(p.errors),
        }
    }
}

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

    #[test]
    fn lookup_valid() {
        let toml = r#"
              [test]
              foo = "bar"

              [[values]]
              foo = "baz"

              [[values]]
              foo = "qux"
        "#;

        let value: Value = toml.parse().unwrap();

        let test_foo = value.lookup("test.foo").unwrap();
        assert_eq!(test_foo.as_str().unwrap(), "bar");

        let foo1 = value.lookup("values.1.foo").unwrap();
        assert_eq!(foo1.as_str().unwrap(), "qux");

        assert!(value.lookup("test.bar").is_none());
        assert!(value.lookup("test.foo.bar").is_none());
    }

    #[test]
    fn lookup_invalid_index() {
        let toml = r#"
            [[values]]
            foo = "baz"
        "#;

        let value: Value = toml.parse().unwrap();

        let foo = value.lookup("test.foo");
        assert!(foo.is_none());

        let foo = value.lookup("values.100.foo");
        assert!(foo.is_none());

        let foo = value.lookup("values.str.foo");
        assert!(foo.is_none());
    }

    #[test]
    fn lookup_self() {
        let value: Value = r#"foo = "bar""#.parse().unwrap();

        let foo = value.lookup("foo").unwrap();
        assert_eq!(foo.as_str().unwrap(), "bar");

        let foo = value.lookup("").unwrap();
        assert!(foo.as_table().is_some());

        let baz = foo.lookup("foo").unwrap();
        assert_eq!(baz.as_str().unwrap(), "bar");
    }
}
<commit_msg>Implement the non-recursive lookup_mut<commit_after>//! A TOML-parsing library
//!
//! This library is an implementation in Rust of a parser for TOML configuration
//! files [1]. It is focused around high quality errors including specific spans
//! and detailed error messages when things go wrong.
//!
//! This implementation currently passes the language agnostic [test suite][2].
//!
//! # Example
//!
//! ```
//! let toml = r#"
//!     [test]
//!     foo = "bar"
//! "#;
//!
//! let value = toml::Parser::new(toml).parse().unwrap();
//! println!("{:?}", value);
//! ```
//!
//! # Conversions
//!
//! This library also supports using the standard `Encodable` and `Decodable`
//! traits with TOML values. This library provides the following conversion
//! capabilities:
//!
//! * `String` => `toml::Value` - via `Parser`
//! * `toml::Value` => `String` - via `Display`
//! * `toml::Value` => rust object - via `Decoder`
//! * rust object => `toml::Value` - via `Encoder`
//!
//! Convenience functions for performing multiple conversions at a time are also
//! provided.
//!
//! [1]: https://github.com/mojombo/toml
//! [2]: https://github.com/BurntSushi/toml-test

#![doc(html_root_url = "http://alexcrichton.com/toml-rs")]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

#[cfg(feature = "rustc-serialize")] extern crate rustc_serialize;
#[cfg(feature = "serde")] extern crate serde;

use std::collections::BTreeMap;
use std::str::FromStr;

pub use parser::{Parser, ParserError};

#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
pub use self::encoder::{Encoder, Error, encode, encode_str};
#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
pub use self::decoder::{Decoder, DecodeError, DecodeErrorKind, decode, decode_str};

mod parser;
mod display;
#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
mod encoder;
#[cfg(any(feature = "rustc-serialize", feature = "serde"))]
mod decoder;

/// Representation of a TOML value.
#[derive(PartialEq, Clone, Debug)]
#[allow(missing_docs)]
pub enum Value {
    String(String),
    Integer(i64),
    Float(f64),
    Boolean(bool),
    Datetime(String),
    Array(Array),
    Table(Table),
}

/// Type representing a TOML array, payload of the Value::Array variant
pub type Array = Vec<Value>;

/// Type representing a TOML table, payload of the Value::Table variant
pub type Table = BTreeMap<String, Value>;

impl Value {
    /// Tests whether this and another value have the same type.
    pub fn same_type(&self, other: &Value) -> bool {
        match (self, other) {
            (&Value::String(..), &Value::String(..)) |
            (&Value::Integer(..), &Value::Integer(..)) |
            (&Value::Float(..), &Value::Float(..)) |
            (&Value::Boolean(..), &Value::Boolean(..)) |
            (&Value::Datetime(..), &Value::Datetime(..)) |
            (&Value::Array(..), &Value::Array(..)) |
            (&Value::Table(..), &Value::Table(..)) => true,

            _ => false,
        }
    }

    /// Returns a human-readable representation of the type of this value.
    pub fn type_str(&self) -> &'static str {
        match *self {
            Value::String(..) => "string",
            Value::Integer(..) => "integer",
            Value::Float(..) => "float",
            Value::Boolean(..) => "boolean",
            Value::Datetime(..) => "datetime",
            Value::Array(..) => "array",
            Value::Table(..) => "table",
        }
    }

    /// Extracts the string of this value if it is a string.
    pub fn as_str(&self) -> Option<&str> {
        match *self { Value::String(ref s) => Some(&**s), _ => None }
    }

    /// Extracts the integer value if it is an integer.
    pub fn as_integer(&self) -> Option<i64> {
        match *self { Value::Integer(i) => Some(i), _ => None }
    }

    /// Extracts the float value if it is a float.
    pub fn as_float(&self) -> Option<f64> {
        match *self { Value::Float(f) => Some(f), _ => None }
    }

    /// Extracts the boolean value if it is a boolean.
    pub fn as_bool(&self) -> Option<bool> {
        match *self { Value::Boolean(b) => Some(b), _ => None }
    }

    /// Extracts the datetime value if it is a datetime.
    ///
    /// Note that a parsed TOML value will only contain ISO 8601 dates. An
    /// example date is:
    ///
    /// ```notrust
    /// 1979-05-27T07:32:00Z
    /// ```
    pub fn as_datetime(&self) -> Option<&str> {
        match *self { Value::Datetime(ref s) => Some(&**s), _ => None }
    }

    /// Extracts the array value if it is an array.
    pub fn as_slice(&self) -> Option<&[Value]> {
        match *self { Value::Array(ref s) => Some(&**s), _ => None }
    }

    /// Extracts the table value if it is a table.
    pub fn as_table(&self) -> Option<&Table> {
        match *self { Value::Table(ref s) => Some(s), _ => None }
    }

    /// Lookups for value at specified path.
    ///
    /// Uses '.' as a path separator.
    ///
    /// Note: arrays have zero-based indexes.
    ///
    /// Note: empty path returns self.
    ///
    /// ```
    /// # #![allow(unstable)]
    /// let toml = r#"
    ///      [test]
    ///      foo = "bar"
    ///
    ///      [[values]]
    ///      foo = "baz"
    ///
    ///      [[values]]
    ///      foo = "qux"
    /// "#;
    /// let value: toml::Value = toml.parse().unwrap();
    ///
    /// let foo = value.lookup("test.foo").unwrap();
    /// assert_eq!(foo.as_str().unwrap(), "bar");
    ///
    /// let foo = value.lookup("values.1.foo").unwrap();
    /// assert_eq!(foo.as_str().unwrap(), "qux");
    ///
    /// let no_bar = value.lookup("test.bar");
    /// assert_eq!(no_bar.is_none(), true);
    /// ```
    pub fn lookup<'a>(&'a self, path: &'a str) -> Option<&'a Value> {
        let mut cur_value = self;
        if path.len() == 0 {
            return Some(cur_value)
        }

        for key in path.split('.') {
            match *cur_value {
                Value::Table(ref hm) => {
                    match hm.get(key) {
                        Some(v) => cur_value = v,
                        None => return None
                    }
                },
                Value::Array(ref v) => {
                    match key.parse::<usize>().ok() {
                        Some(idx) if idx < v.len() => cur_value = &v[idx],
                        _ => return None
                    }
                },
                _ => return None
            }
        };

        Some(cur_value)
    }

    /// Lookups for mutable value at specified path.
    ///
    /// Uses '.' as a path separator.
    ///
    /// Note: arrays have zero-based indexes.
    ///
    /// Note: empty path returns self.
    ///
    /// ```
    /// # #![allow(unstable)]
    /// let toml = r#"
    ///      [test]
    ///      foo = "bar"
    ///
    ///      [[values]]
    ///      foo = "baz"
    ///
    ///      [[values]]
    ///      foo = "qux"
    /// "#;
    /// let mut value: toml::Value = toml.parse().unwrap();
    /// {
    ///    let string = value.lookup_mut("test.foo").unwrap();
    ///    assert_eq!(string, &mut toml::Value::String(String::from("bar")));
    ///    *string = toml::Value::String(String::from("foo"));
    /// }
    /// let result = value.lookup_mut("test.foo").unwrap();
    /// assert_eq!(result.as_str().unwrap(), "foo");
    /// ```
    pub fn lookup_mut(&mut self, path: &str) -> Option<&mut Value> {
        let mut cur = self;
        if path.len() == 0 {
            return Some(cur)
        }

        for key in path.split('.') {
            let tmp = cur;
            match *tmp {
                Value::Table(ref mut hm) => {
                    match hm.get_mut(key) {
                        Some(v) => cur = v,
                        None => return None
                    }
                }
                Value::Array(ref mut v) => {
                    match key.parse::<usize>().ok() {
                        Some(idx) if idx < v.len() => cur = &mut v[idx],
                        _ => return None
                    }
                }
                _ => return None
           }
        }
        Some(cur)
    }
}

impl FromStr for Value {
    type Err = Vec<ParserError>;
    fn from_str(s: &str) -> Result<Value, Vec<ParserError>> {
        let mut p = Parser::new(s);
        match p.parse().map(Value::Table) {
            Some(n) => Ok(n),
            None => Err(p.errors),
        }
    }
}

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

    #[test]
    fn lookup_mut_valid() {
        let toml = r#"
              [test]
              foo = "bar"

              [[values]]
              foo = "baz"

              [[values]]
              foo = "qux"
        "#;

        let mut value: Value = toml.parse().unwrap();

        {
            let test_foo = value.lookup_mut("test.foo").unwrap();
            assert_eq!(test_foo.as_str().unwrap(), "bar");
        }

        {
            let foo1 = value.lookup_mut("values.1.foo").unwrap();
            assert_eq!(foo1.as_str().unwrap(), "qux");
        }

        assert!(value.lookup_mut("test.bar").is_none());
        assert!(value.lookup_mut("test.foo.bar").is_none());
    }

    #[test]
    fn lookup_mut_invalid_index() {
        let toml = r#"
            [[values]]
            foo = "baz"
        "#;

        let mut value: Value = toml.parse().unwrap();

        {
            let foo = value.lookup_mut("test.foo");
            assert!(foo.is_none());
        }

        {
            let foo = value.lookup_mut("values.100.foo");
            assert!(foo.is_none());
        }

        {
            let foo = value.lookup_mut("values.str.foo");
            assert!(foo.is_none());
        }
    }

    #[test]
    fn lookup_mut_self() {
        let mut value: Value = r#"foo = "bar""#.parse().unwrap();

        {
            let foo = value.lookup_mut("foo").unwrap();
            assert_eq!(foo.as_str().unwrap(), "bar");
        }

        let foo = value.lookup_mut("").unwrap();
        assert!(foo.as_table().is_some());

        let baz = foo.lookup_mut("foo").unwrap();
        assert_eq!(baz.as_str().unwrap(), "bar");
    }

    #[test]
    fn lookup_valid() {
        let toml = r#"
              [test]
              foo = "bar"

              [[values]]
              foo = "baz"

              [[values]]
              foo = "qux"
        "#;

        let value: Value = toml.parse().unwrap();

        let test_foo = value.lookup("test.foo").unwrap();
        assert_eq!(test_foo.as_str().unwrap(), "bar");

        let foo1 = value.lookup("values.1.foo").unwrap();
        assert_eq!(foo1.as_str().unwrap(), "qux");

        assert!(value.lookup("test.bar").is_none());
        assert!(value.lookup("test.foo.bar").is_none());
    }

    #[test]
    fn lookup_invalid_index() {
        let toml = r#"
            [[values]]
            foo = "baz"
        "#;

        let value: Value = toml.parse().unwrap();

        let foo = value.lookup("test.foo");
        assert!(foo.is_none());

        let foo = value.lookup("values.100.foo");
        assert!(foo.is_none());

        let foo = value.lookup("values.str.foo");
        assert!(foo.is_none());
    }

    #[test]
    fn lookup_self() {
        let value: Value = r#"foo = "bar""#.parse().unwrap();

        let foo = value.lookup("foo").unwrap();
        assert_eq!(foo.as_str().unwrap(), "bar");

        let foo = value.lookup("").unwrap();
        assert!(foo.as_table().is_some());

        let baz = foo.lookup("foo").unwrap();
        assert_eq!(baz.as_str().unwrap(), "bar");
    }
}
<|endoftext|>


<commit_before>#![feature(libc)]
#![feature(collections)]
#![feature(convert)]
#![feature(path_ext)]
extern crate libc;

pub mod groonga;
pub mod commandapi;
<commit_msg>Follow Rust 1.3.0-dev(HEAD) change<commit_after>#![feature(libc)]
#![feature(map_in_place)]
#![feature(convert)]
#![feature(path_ext)]
extern crate libc;

pub mod groonga;
pub mod commandapi;
<|endoftext|>