<commit_before>//! `harfbuzz_rs` is a high-level interface to HarfBuzz, exposing its most important functionality
//! in a safe manner using Rust.
//!
//! # What is HarfBuzz?
//! HarfBuzz is a library for performing complex text layout. It does not perform any drawing. This
//! is quite a low-level operation. If you want to simply draw some text on the screen choose
//! another library. However if you want to build a library for drawing text on some canvas or
//! need a lot of control on advanced text layout then this is the right library to use.
//!
//! # Getting Started
//!
//! To shape a simple string of text you just create a `Font` from a font file, fill a `Buffer`
//! with some text and call the `shape` function.
//!
//! ```
//! use harfbuzz_rs::*;
//!
//! # fn try_main() -> Result<(), std::io::Error> {
//!
//! let path = "path/to/some/font_file.otf";
//! let index = 0; //< face index in the font file
//! # let path = "testfiles/SourceSansVariable-Roman.ttf";
//! let face = Face::from_file(path, index)?;
//! let mut font = Font::new(face);
//!
//! let buffer = UnicodeBuffer::new().add_str("Hello World!");
//! let output = shape(&font, buffer, &[]);
//!
//! // The results of the shaping operation are stored in the `output` buffer.
//!
//! let positions = output.get_glyph_positions();
//! let infos = output.get_glyph_infos();
//!
//! # assert_eq!(positions.len(), 12);
//! assert_eq!(positions.len(), infos.len());
//!
//! // iterate over the shaped glyphs
//! for (position, info) in positions.iter().zip(infos) {
//!     let gid = info.codepoint;
//!     let cluster = info.cluster;
//!     let x_advance = position.x_advance;
//!     let x_offset = position.x_offset;
//!     let y_offset = position.y_offset;
//!
//!     // Here you would usually draw the glyphs.
//!     println!("gid{:?}={:?}@{:?},{:?}+{:?}", gid, cluster, x_advance, x_offset, y_offset);
//! }
//!
//! # Ok(())
//! # }
//! #
//! # try_main().unwrap();
//! ```
//! This should print out something similar to the following:
//!
//! ```text
//! gid41=0@741,0+0
//! gid70=1@421,0+0
//! gid77=2@258,0+0
//! gid77=3@253,0+0
//! gid80=4@510,0+0
//! gid1=5@227,0+0
//! gid56=6@874,0+0
//! gid80=7@498,0+0
//! gid83=8@367,0+0
//! gid77=9@253,0+0
//! gid69=10@528,0+0
//! gid2=11@276,0+0
//! ```
#![deny(missing_debug_implementations)]

/// Reexported `harfbuzz_sys` crate to directly access the C API whenever no
/// adequate wrapper is provided.
// This will hopefully not cause backwards compability concerns since harfbuzz
// tries to be backwards compatible.
use harfbuzz_sys as hb;
#[macro_use]
extern crate bitflags;

mod blob;
mod buffer;
mod common;
mod face;
mod font;
pub mod font_funcs;

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

pub use crate::blob::*;
pub use crate::buffer::*;
pub use crate::common::*;
pub use crate::face::*;
pub use crate::font::*;

use std::ops::{Bound, RangeBounds};
use std::os::raw::c_uint;

pub(crate) fn start_end_range(range: impl RangeBounds<usize>) -> (c_uint, c_uint) {
    // We have to do careful bounds checking since c_uint may be of
    // different sizes on different platforms. We do assume that
    // sizeof(usize) >= sizeof(c_uint).
    const MAX_UINT: usize = c_uint::max_value() as usize;
    let start = match range.start_bound() {
        Bound::Included(&included) => included.min(MAX_UINT) as c_uint,
        Bound::Excluded(&excluded) => excluded.min(MAX_UINT - 1) as c_uint + 1,
        Bound::Unbounded => 0,
    };
    let end = match range.end_bound() {
        Bound::Included(&included) => included.saturating_add(1).min(MAX_UINT) as c_uint,
        Bound::Excluded(&excluded) => excluded.min(MAX_UINT) as c_uint,
        Bound::Unbounded => c_uint::max_value(),
    };
    (start, end)
}
/// A feature tag with an accompanying range specifying on which subslice of
/// `shape`s input it should be applied.
///
/// You can pass a slice of `Feature`s to `shape` that will be activated for the
/// corresponding slices of input.
///
/// # Examples
///
/// Shape some text using the `calt` (Contextual Alternatives) feature.
///
/// ```
/// use harfbuzz_rs::{Face, Font, UnicodeBuffer, shape, Feature, Tag};
///
/// let path = "testfiles/SourceSansVariable-Roman.ttf";
/// let face = Face::from_file(path, 0).expect("could not load face");
/// let font = Font::new(face);
///
/// let buffer = UnicodeBuffer::new().add_str("Hello World!");
///
/// // contextual alternatives feature
/// let feature_tag = b"calt";
///
/// // use the feature on the entire input
/// let feature_range = 0..;
/// let feature = Feature::new(feature_tag, 0, feature_range);
///
/// let output = shape(&font, buffer, &[feature]);
/// ```
///
///
    /// Create a new `variation` struct.
    ///
    ///
    /// # Arguments
    ///
    /// - `tag`: The OpenType variation tag to use.
    /// - `value`: Some OpenType variant accept different values to change
    ///   their behaviour.
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct Variation(hb::hb_variation_t);

impl Variation{
    pub fn new(tag: impl Into<Tag>, value: f32) -> Variation {
        Variation(hb::hb_variation_t {
            tag: tag.into().0,
            value,

        })
    }

    pub fn tag(&self) -> Tag {
        Tag(self.0.tag)
    }

    pub fn value(&self) -> f32 {
        self.0.value
    }
}

#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct Feature(hb::hb_feature_t);

impl Feature {
    /// Create a new `Feature` struct.
    ///
    /// The feature will be applied with the given value to all glyphs which are
    /// in clusters contained in `range`.
    ///
    /// # Arguments
    ///
    /// - `tag`: The OpenType feature tag to use.
    /// - `value`: Some OpenType features accept different values to change
    ///   their behaviour.
    /// - `range`: The cluster range that should be affected by this feature.
    pub fn new(tag: impl Into<Tag>, value: u32, range: impl RangeBounds<usize>) -> Feature {
        let (start, end) = start_end_range(range);
        Feature(hb::hb_feature_t {
            tag: tag.into().0,
            value,
            start,
            end,
        })
    }

    pub fn tag(&self) -> Tag {
        Tag(self.0.tag)
    }

    pub fn value(&self) -> u32 {
        self.0.value
    }

    pub fn start(&self) -> usize {
        self.0.start as usize
    }

    pub fn end(&self) -> usize {
        self.0.end as usize
    }
}

/// Shape the contents of the buffer using the provided font and activating all
/// OpenType features given in `features`.
///
/// This function consumes the `buffer` and returns a `GlyphBuffer` containing
/// the resulting glyph indices and the corresponding positioning information.
/// Once all the information from the `GlyphBuffer` has been processed as
/// necessary you can reuse the `GlyphBuffer` as an `UnicodeBuffer` (using
/// `GlyphBuffer::clear_contents`) and use that to call `shape` again with new
/// data.
///
/// By default some basic OpenType features are enabled according to the
/// language and the script set in the buffer.
///
/// # Arguments
/// - `font` – a reference to the harfbuzz font used to shape the text.
/// - `buffer` – a `UnicodeBuffer` that is filled with the text to be shaped and
/// also contains metadata about the text in the form of segment properties.
/// - `features` – a slice of additional features to activate
pub fn shape(font: &Font<'_>, buffer: UnicodeBuffer, features: &[Feature]) -> GlyphBuffer {
    let buffer = buffer.guess_segment_properties();
    unsafe {
        hb::hb_shape(
            font.as_raw(),
            buffer.0.as_raw(),
            features.as_ptr() as *mut _,
            features.len() as u32,
        )
    };
    GlyphBuffer(buffer.0)
}

#[cfg(test)]
mod tests {
    use std::mem::{align_of, size_of};

    pub(crate) fn assert_memory_layout_equal<T, U>() {
        assert_eq!(size_of::<T>(), size_of::<U>());
        assert_eq!(align_of::<T>(), align_of::<U>());
    }

    #[test]
    fn it_works() {}

    fn assert_feature(feat: Feature, tag: Tag, value: u32, start: usize, end: usize) {
        assert_eq!(feat.tag(), tag);
        assert_eq!(feat.value(), value);
        assert_eq!(feat.start(), start);
        assert_eq!(feat.end(), end);
    }

    use super::{Feature, Tag};
    #[test]
    fn feature_new() {
        let tag = b"abcd".into();
        const UINT_MAX: usize = std::os::raw::c_uint::max_value() as usize;

        let feature = Feature::new(tag, 100, 2..100);
        assert_feature(feature, tag, 100, 2, 100);

        let feature = Feature::new(tag, 100, 2..=100);
        assert_feature(feature, tag, 100, 2, 101);

        let feature = Feature::new(tag, 100, 2..);
        assert_feature(feature, tag, 100, 2, UINT_MAX);

        let feature = Feature::new(tag, 100, ..100);
        assert_feature(feature, tag, 100, 0, 100);

        let feature = Feature::new(tag, 100, ..=100);
        assert_feature(feature, tag, 100, 0, 101);

        let feature = Feature::new(tag, 100, ..);
        assert_feature(feature, tag, 100, 0, UINT_MAX);
    }
}
<commit_msg>add newlines to make it prettier.<commit_after>//! `harfbuzz_rs` is a high-level interface to HarfBuzz, exposing its most important functionality
//! in a safe manner using Rust.
//!
//! # What is HarfBuzz?
//! HarfBuzz is a library for performing complex text layout. It does not perform any drawing. This
//! is quite a low-level operation. If you want to simply draw some text on the screen choose
//! another library. However if you want to build a library for drawing text on some canvas or
//! need a lot of control on advanced text layout then this is the right library to use.
//!
//! # Getting Started
//!
//! To shape a simple string of text you just create a `Font` from a font file, fill a `Buffer`
//! with some text and call the `shape` function.
//!
//! ```
//! use harfbuzz_rs::*;
//!
//! # fn try_main() -> Result<(), std::io::Error> {
//!
//! let path = "path/to/some/font_file.otf";
//! let index = 0; //< face index in the font file
//! # let path = "testfiles/SourceSansVariable-Roman.ttf";
//! let face = Face::from_file(path, index)?;
//! let mut font = Font::new(face);
//!
//! let buffer = UnicodeBuffer::new().add_str("Hello World!");
//! let output = shape(&font, buffer, &[]);
//!
//! // The results of the shaping operation are stored in the `output` buffer.
//!
//! let positions = output.get_glyph_positions();
//! let infos = output.get_glyph_infos();
//!
//! # assert_eq!(positions.len(), 12);
//! assert_eq!(positions.len(), infos.len());
//!
//! // iterate over the shaped glyphs
//! for (position, info) in positions.iter().zip(infos) {
//!     let gid = info.codepoint;
//!     let cluster = info.cluster;
//!     let x_advance = position.x_advance;
//!     let x_offset = position.x_offset;
//!     let y_offset = position.y_offset;
//!
//!     // Here you would usually draw the glyphs.
//!     println!("gid{:?}={:?}@{:?},{:?}+{:?}", gid, cluster, x_advance, x_offset, y_offset);
//! }
//!
//! # Ok(())
//! # }
//! #
//! # try_main().unwrap();
//! ```
//! This should print out something similar to the following:
//!
//! ```text
//! gid41=0@741,0+0
//! gid70=1@421,0+0
//! gid77=2@258,0+0
//! gid77=3@253,0+0
//! gid80=4@510,0+0
//! gid1=5@227,0+0
//! gid56=6@874,0+0
//! gid80=7@498,0+0
//! gid83=8@367,0+0
//! gid77=9@253,0+0
//! gid69=10@528,0+0
//! gid2=11@276,0+0
//! ```
#![deny(missing_debug_implementations)]

/// Reexported `harfbuzz_sys` crate to directly access the C API whenever no
/// adequate wrapper is provided.
// This will hopefully not cause backwards compability concerns since harfbuzz
// tries to be backwards compatible.
use harfbuzz_sys as hb;
#[macro_use]
extern crate bitflags;

mod blob;
mod buffer;
mod common;
mod face;
mod font;
pub mod font_funcs;

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

pub use crate::blob::*;
pub use crate::buffer::*;
pub use crate::common::*;
pub use crate::face::*;
pub use crate::font::*;

use std::ops::{Bound, RangeBounds};
use std::os::raw::c_uint;

pub(crate) fn start_end_range(range: impl RangeBounds<usize>) -> (c_uint, c_uint) {
    // We have to do careful bounds checking since c_uint may be of
    // different sizes on different platforms. We do assume that
    // sizeof(usize) >= sizeof(c_uint).
    const MAX_UINT: usize = c_uint::max_value() as usize;
    let start = match range.start_bound() {
        Bound::Included(&included) => included.min(MAX_UINT) as c_uint,
        Bound::Excluded(&excluded) => excluded.min(MAX_UINT - 1) as c_uint + 1,
        Bound::Unbounded => 0,
    };
    let end = match range.end_bound() {
        Bound::Included(&included) => included.saturating_add(1).min(MAX_UINT) as c_uint,
        Bound::Excluded(&excluded) => excluded.min(MAX_UINT) as c_uint,
        Bound::Unbounded => c_uint::max_value(),
    };
    (start, end)
}
/// A feature tag with an accompanying range specifying on which subslice of
/// `shape`s input it should be applied.
///
/// You can pass a slice of `Feature`s to `shape` that will be activated for the
/// corresponding slices of input.
///
/// # Examples
///
/// Shape some text using the `calt` (Contextual Alternatives) feature.
///
/// ```
/// use harfbuzz_rs::{Face, Font, UnicodeBuffer, shape, Feature, Tag};
///
/// let path = "testfiles/SourceSansVariable-Roman.ttf";
/// let face = Face::from_file(path, 0).expect("could not load face");
/// let font = Font::new(face);
///
/// let buffer = UnicodeBuffer::new().add_str("Hello World!");
///
/// // contextual alternatives feature
/// let feature_tag = b"calt";
///
/// // use the feature on the entire input
/// let feature_range = 0..;
/// let feature = Feature::new(feature_tag, 0, feature_range);
///
/// let output = shape(&font, buffer, &[feature]);
/// ```
///
///

    /// Create a new `variation` struct.
    ///
    ///
    /// # Arguments
    ///
    /// - `tag`: The OpenType variation tag to use.
    /// - `value`: Some OpenType variant accept different values to change
    ///   their behaviour.
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct Variation(hb::hb_variation_t);

impl Variation{
    pub fn new(tag: impl Into<Tag>, value: f32) -> Variation {
        Variation(hb::hb_variation_t {
            tag: tag.into().0,
            value,

        })
    }

    pub fn tag(&self) -> Tag {
        Tag(self.0.tag)
    }

    pub fn value(&self) -> f32 {
        self.0.value
    }
}

#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct Feature(hb::hb_feature_t);

impl Feature {
    /// Create a new `Feature` struct.
    ///
    /// The feature will be applied with the given value to all glyphs which are
    /// in clusters contained in `range`.
    ///
    /// # Arguments
    ///
    /// - `tag`: The OpenType feature tag to use.
    /// - `value`: Some OpenType features accept different values to change
    ///   their behaviour.
    /// - `range`: The cluster range that should be affected by this feature.
    pub fn new(tag: impl Into<Tag>, value: u32, range: impl RangeBounds<usize>) -> Feature {
        let (start, end) = start_end_range(range);
        Feature(hb::hb_feature_t {
            tag: tag.into().0,
            value,
            start,
            end,
        })
    }

    pub fn tag(&self) -> Tag {
        Tag(self.0.tag)
    }

    pub fn value(&self) -> u32 {
        self.0.value
    }

    pub fn start(&self) -> usize {
        self.0.start as usize
    }

    pub fn end(&self) -> usize {
        self.0.end as usize
    }
}

/// Shape the contents of the buffer using the provided font and activating all
/// OpenType features given in `features`.
///
/// This function consumes the `buffer` and returns a `GlyphBuffer` containing
/// the resulting glyph indices and the corresponding positioning information.
/// Once all the information from the `GlyphBuffer` has been processed as
/// necessary you can reuse the `GlyphBuffer` as an `UnicodeBuffer` (using
/// `GlyphBuffer::clear_contents`) and use that to call `shape` again with new
/// data.
///
/// By default some basic OpenType features are enabled according to the
/// language and the script set in the buffer.
///
/// # Arguments
/// - `font` – a reference to the harfbuzz font used to shape the text.
/// - `buffer` – a `UnicodeBuffer` that is filled with the text to be shaped and
/// also contains metadata about the text in the form of segment properties.
/// - `features` – a slice of additional features to activate
pub fn shape(font: &Font<'_>, buffer: UnicodeBuffer, features: &[Feature]) -> GlyphBuffer {
    let buffer = buffer.guess_segment_properties();
    unsafe {
        hb::hb_shape(
            font.as_raw(),
            buffer.0.as_raw(),
            features.as_ptr() as *mut _,
            features.len() as u32,
        )
    };
    GlyphBuffer(buffer.0)
}

#[cfg(test)]
mod tests {
    use std::mem::{align_of, size_of};

    pub(crate) fn assert_memory_layout_equal<T, U>() {
        assert_eq!(size_of::<T>(), size_of::<U>());
        assert_eq!(align_of::<T>(), align_of::<U>());
    }

    #[test]
    fn it_works() {}

    fn assert_feature(feat: Feature, tag: Tag, value: u32, start: usize, end: usize) {
        assert_eq!(feat.tag(), tag);
        assert_eq!(feat.value(), value);
        assert_eq!(feat.start(), start);
        assert_eq!(feat.end(), end);
    }

    use super::{Feature, Tag};
    #[test]
    fn feature_new() {
        let tag = b"abcd".into();
        const UINT_MAX: usize = std::os::raw::c_uint::max_value() as usize;

        let feature = Feature::new(tag, 100, 2..100);
        assert_feature(feature, tag, 100, 2, 100);

        let feature = Feature::new(tag, 100, 2..=100);
        assert_feature(feature, tag, 100, 2, 101);

        let feature = Feature::new(tag, 100, 2..);
        assert_feature(feature, tag, 100, 2, UINT_MAX);

        let feature = Feature::new(tag, 100, ..100);
        assert_feature(feature, tag, 100, 0, 100);

        let feature = Feature::new(tag, 100, ..=100);
        assert_feature(feature, tag, 100, 0, 101);

        let feature = Feature::new(tag, 100, ..);
        assert_feature(feature, tag, 100, 0, UINT_MAX);
    }
}
<|endoftext|>


<commit_before>extern crate rand;
pub mod parse;

#[cfg(test)]
mod tests {
    use ::parse::{Parser,BlockKind,SrcBlock,
                  LogicKind,SrcKind,VarKind,ExpectKind,
                  Eval};

    struct Data;
    impl Eval for Data {
        fn eval (&self, data: &str) -> Option<VarKind> {
            match data {
                "some_item" => {
                    Some(VarKind::Bool(false))
                },
                "some_weight" => {
                    Some(VarKind::Num(4.0f32))
                },
                "name" => {
                    Some(VarKind::String("Io".to_owned()))
                }
                _ => None
            }
        }
    }

    fn test_block () -> &'static str {
        "root\n
    unequipped !some_item\n
    has_weight some_weight < 5.0\n
    some_comp:any [\nunequipped \nhas_weight\n]\n
\n
    if unequipped \"you're looking for something?\"\n
\n
    if all \"welcome, \nlook around\"\n
;"
    }

    fn qsym_block () -> &'static str {
        "root\n
    if '!some_item \"you're looking for something?\"\n
;"
    }

    fn qsym_comp_block () -> &'static str {
        "root\n
    has_weight some_weight < 5.0\n
    some_comp:any [has_weight '!some_item ]\n
    ;"
    }

    fn if_vec_block () -> &'static str {
        "root\n
    if '!some_item [\n
        \"you're looking for something?\"\n
        \"welcome, \nlook around\"\n
        next store]\n
;"
    }

    fn eval_str_block () -> &'static str {
        "root\n
        has_weight some_weight < 5.0\n
        some_comp:all [has_weight '!some_item ]\n
    if some_comp \"looks like you are `some_weight kgs heavy, `name\"\n
;"
    }

    #[test]
    fn parse_block() {
        let src = test_block();
        let block = Parser::parse_blocks(src);

        let block_ = [BlockKind::Src(
            SrcBlock {
                name: "root".to_owned(),
                src: vec![SrcKind::Logic("unequipped".to_owned(),
                                         LogicKind::IsNot("some_item".to_owned())),

                          SrcKind::Logic("has_weight".to_owned(),
                                         LogicKind::LT("some_weight".to_owned(), VarKind::Num(5.0f32))),
                          SrcKind::Composite("some_comp".to_owned(),
                                             ExpectKind::Any,
                                             vec!["unequipped".to_owned(),"has_weight".to_owned()]),
                          SrcKind::If(ExpectKind::Ref("unequipped".to_owned()),
                                      vec![VarKind::String("you're looking for something?".to_owned())],
                                      None),
                          SrcKind::If(ExpectKind::All,
                                      vec![VarKind::String("welcome, \nlook around".to_owned())],
                                      None)]
            })];

        for (n,n_) in block.iter().zip(block_.iter()) {
            assert_eq!(n,n_);
        }
    }

    #[test]
    fn parse_qsym_block() {
        let src = qsym_block();
        let block = Parser::parse_blocks(src);
        match &block[0] {
            &BlockKind::Src(ref b) => {
                let r;
                match b.src[0] {
                    SrcKind::Logic(ref qsym,_) => { r = qsym; },
                    _ => panic!("unknown source found")
                }

                match b.src[1] {
                    SrcKind::If(ref x,_,_) => {
                        match x {
                            &ExpectKind::Ref(ref r_) => {
                                assert_eq!(r,r_);
                            },
                            _ => panic!("unknown expect found")
                        }
                    },
                    _ => panic!("unknown source found")
                }
            },
            _ => panic!("unknown block found")
        }
    }

    #[test]
    fn parse_qsym_comp_block() {
        let src = qsym_comp_block();
        let block = Parser::parse_blocks(src);

        match &block[0] {
            &BlockKind::Src(ref b) => {
                let r;
                match b.src[1] {
                    SrcKind::Logic(ref qsym,_) => { r = qsym; },
                    _ => panic!("unknown source found")
                }

                match b.src[2] {
                    SrcKind::Composite(_,_,ref x) => {
                        assert_eq!(r,&x[1]);
                    },
                    _ => panic!("unknown source found")
                }
            },
            _ => panic!("unknown block found")
        }
    }

    #[test]
    fn parse_if_vec_block() {
        let src = if_vec_block();
        let block = Parser::parse_blocks(src);

        match &block[0] {
            &BlockKind::Src(ref b) => {
                match b.src[1] {
                    SrcKind::If(_,_, ref next) => {
                        assert!(next.is_some());
                        assert_eq!(next,&Some("store".to_owned()));
                    },
                    _ => panic!("unknown source found")
                }
            },
            _ => panic!("unknown block found")
        }
    }

    #[test]
    fn parse_eval_str_block() {
        let src = eval_str_block();
        let block = Parser::parse_blocks(src);
        let data = Data;
        let (vars,_node) = Parser::eval_block(&block[0], &data);

        assert_eq!(vars[0], VarKind::String("looks like you are 4 kgs heavy, Io".to_owned()));
    }
}
<commit_msg>test case for two vars comparison<commit_after>extern crate rand;
pub mod parse;

#[cfg(test)]
mod tests {
    use ::parse::{Parser,BlockKind,SrcBlock,
                  LogicKind,SrcKind,VarKind,ExpectKind,
                  Eval};

    struct Data;
    impl Eval for Data {
        fn eval (&self, data: &str) -> Option<VarKind> {
            match data {
                "some_item" => {
                    Some(VarKind::Bool(false))
                },
                "some_weight" => {
                    Some(VarKind::Num(4.0f32))
                },
                "other_weight" => {
                    Some(VarKind::Num(5.0f32))
                },
                "name" => {
                    Some(VarKind::String("Io".to_owned()))
                }
                _ => None
            }
        }
    }

    fn test_block () -> &'static str {
        "root\n
    unequipped !some_item\n
    has_weight some_weight < 5.0\n
    some_comp:any [\nunequipped \nhas_weight\n]\n
\n
    if unequipped \"you're looking for something?\"\n
\n
    if all \"welcome, \nlook around\"\n
;"
    }

    fn qsym_block () -> &'static str {
        "root\n
    if '!some_item \"you're looking for something?\"\n
;"
    }

    fn qsym_comp_block () -> &'static str {
        "root\n
    has_weight some_weight < 5.0\n
    some_comp:any [has_weight '!some_item ]\n
    ;"
    }

    fn if_vec_block () -> &'static str {
        "root\n
    if '!some_item [\n
        \"you're looking for something?\"\n
        \"welcome, \nlook around\"\n
        next store]\n
;"
    }

    fn eval_str_block () -> &'static str {
        "root\n
        has_weight some_weight < 5.0\n
        some_comp:all [has_weight '!some_item ]\n
    if some_comp \"looks like you are `some_weight kgs heavy, `name\"\n
;"
    }

    fn compare_env_block () -> &'static str {
        "root\n
    weight some_weight < other_weight\n
    if weight next store\n
;"
    }

    #[test]
    fn parse_block() {
        let src = test_block();
        let block = Parser::parse_blocks(src);

        let block_ = [BlockKind::Src(
            SrcBlock {
                name: "root".to_owned(),
                src: vec![SrcKind::Logic("unequipped".to_owned(),
                                         LogicKind::IsNot("some_item".to_owned())),

                          SrcKind::Logic("has_weight".to_owned(),
                                         LogicKind::LT("some_weight".to_owned(), VarKind::Num(5.0f32))),
                          SrcKind::Composite("some_comp".to_owned(),
                                             ExpectKind::Any,
                                             vec!["unequipped".to_owned(),"has_weight".to_owned()]),
                          SrcKind::If(ExpectKind::Ref("unequipped".to_owned()),
                                      vec![VarKind::String("you're looking for something?".to_owned())],
                                      None),
                          SrcKind::If(ExpectKind::All,
                                      vec![VarKind::String("welcome, \nlook around".to_owned())],
                                      None)]
            })];

        for (n,n_) in block.iter().zip(block_.iter()) {
            assert_eq!(n,n_);
        }
    }

    #[test]
    fn parse_qsym_block() {
        let src = qsym_block();
        let block = Parser::parse_blocks(src);
        match &block[0] {
            &BlockKind::Src(ref b) => {
                let r;
                match b.src[0] {
                    SrcKind::Logic(ref qsym,_) => { r = qsym; },
                    _ => panic!("unknown source found")
                }

                match b.src[1] {
                    SrcKind::If(ref x,_,_) => {
                        match x {
                            &ExpectKind::Ref(ref r_) => {
                                assert_eq!(r,r_);
                            },
                            _ => panic!("unknown expect found")
                        }
                    },
                    _ => panic!("unknown source found")
                }
            },
            _ => panic!("unknown block found")
        }
    }

    #[test]
    fn parse_qsym_comp_block() {
        let src = qsym_comp_block();
        let block = Parser::parse_blocks(src);

        match &block[0] {
            &BlockKind::Src(ref b) => {
                let r;
                match b.src[1] {
                    SrcKind::Logic(ref qsym,_) => { r = qsym; },
                    _ => panic!("unknown source found")
                }

                match b.src[2] {
                    SrcKind::Composite(_,_,ref x) => {
                        assert_eq!(r,&x[1]);
                    },
                    _ => panic!("unknown source found")
                }
            },
            _ => panic!("unknown block found")
        }
    }

    #[test]
    fn parse_if_vec_block() {
        let src = if_vec_block();
        let block = Parser::parse_blocks(src);

        match &block[0] {
            &BlockKind::Src(ref b) => {
                match b.src[1] {
                    SrcKind::If(_,_, ref next) => {
                        assert!(next.is_some());
                        assert_eq!(next,&Some("store".to_owned()));
                    },
                    _ => panic!("unknown source found")
                }
            },
            _ => panic!("unknown block found")
        }
    }

    #[test]
    fn parse_eval_str_block() {
        let src = eval_str_block();
        let block = Parser::parse_blocks(src);
        let data = Data;
        let (vars,_node) = Parser::eval_block(&block[0], &data);

        assert_eq!(vars[0], VarKind::String("looks like you are 4 kgs heavy, Io".to_owned()));
    }

    #[test]
    fn parse_compare_env_block() {
        let src = compare_env_block();
        let block = Parser::parse_blocks(src);
        let data = Data;
        let (_vars,node) = Parser::eval_block(&block[0], &data);

        assert_eq!(node, Some("store".to_string()));
    }
}
<|endoftext|>


<commit_before>use std::f64::consts::PI;

/// Calculates the volume of the n-sphere.
pub fn sphere_volume(radius: f64, dim: u64) -> f64 {
    let gamma = if dim % 2 == 0 {
        // This works because dim / 2 is a whole number.
        fact(dim / 2) as f64
    } else {
        // This works because the function is gamma(1/2 + n) where n = dim / 2 + 1
        let n = dim / 2 + 1;
        (fact(2 * n) as f64 / (4u64.pow(n as u32) * fact(n)) as f64) * PI.sqrt()
    };
    (PI.powf(0.5 * dim as f64) * radius.powf(dim as f64)) / gamma
}

#[test]
fn volume_of_1_sphere_works() {
    for radius in (0..1000000).map(|n| n as f64 / 1000.) {
        let expected = PI * radius.powi(2);
        let actual = sphere_volume(radius, 2);
        assert!(equals(expected, actual, 0.0001, 10), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[test]
fn volume_of_2_sphere_works() {
    for radius in (0..1000000).map(|n| n as f64 / 1000.) {
        let expected = (4. / 3.) * PI * radius.powi(3);
        let actual = sphere_volume(radius, 3);
        assert!(equals(expected, actual, 0.0001, 10), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[test]
fn volume_of_3_sphere_works() {
    for radius in (0..1000000).map(|n| n as f64 / 1000.) {
        let expected = (1. / 2.) * PI.powi(2) * radius.powi(4);
        let actual = sphere_volume(radius, 4);
        assert!(equals(expected, actual, 0.0001, 10), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[cfg(test)]
fn equals(a: f64, b: f64, max_diff: f64, max_ulps_diff: i64) -> bool {
    let diff = f64::abs(a - b);
    if diff <= max_diff {
        return true;
    }
    if a.is_sign_positive() && !b.is_sign_positive() {
        return false;
    }
    let a_i64 = unsafe{::std::mem::transmute::<_, i64>(a)};
    let b_i64 = unsafe{::std::mem::transmute::<_, i64>(b)};
    let ulps_diff = i64::abs(a_i64 - b_i64);
    return ulps_diff <= max_ulps_diff;
}

#[inline]
fn fact(n: u64) -> u64 {
    //TODO: This could be made faster with better algorithm, but it's called with low values so it doesn't matter much.
    if n < 2 {
        1
    } else {
        n * fact(n - 1)
    }
}

#[test]
fn factorial_works() {
    assert_eq!(1, fact(0));
    let mut x = 1;
    for n in 1..21 {
        x *= n;
        assert_eq!(x, fact(n));
    }
}
<commit_msg>Made tests stricter.<commit_after>use std::f64::consts::PI;

/// Calculates the volume of the n-sphere.
pub fn sphere_volume(radius: f64, dim: u64) -> f64 {
    let gamma = if dim % 2 == 0 {
        // This works because dim / 2 is a whole number.
        fact(dim / 2) as f64
    } else {
        // This works because the function is gamma(1/2 + n) where n = dim / 2 + 1
        let n = dim / 2 + 1;
        (fact(2 * n) as f64 / (4u64.pow(n as u32) * fact(n)) as f64) * PI.sqrt()
    };
    (PI.powf(0.5 * dim as f64) * radius.powf(dim as f64)) / gamma
}

#[test]
fn volume_of_1_sphere_works() {
    for radius in (0..5000000).map(|n| n as f64 / 7000.) {
        let expected = PI * radius.powi(2);
        let actual = sphere_volume(radius, 2);
        assert!(equals(expected, actual, 0.0001, 5), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[test]
fn volume_of_2_sphere_works() {
    for radius in (0..5000000).map(|n| n as f64 / 7000.) {
        let expected = (4. / 3.) * PI * radius.powi(3);
        let actual = sphere_volume(radius, 3);
        assert!(equals(expected, actual, 0.0001, 5), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[test]
fn volume_of_3_sphere_works() {
    for radius in (0..5000000).map(|n| n as f64 / 7000.) {
        let expected = (1. / 2.) * PI.powi(2) * radius.powi(4);
        let actual = sphere_volume(radius, 4);
        assert!(equals(expected, actual, 0.0001, 5), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[cfg(test)]
fn equals(a: f64, b: f64, max_diff: f64, max_ulps_diff: i64) -> bool {
    let diff = f64::abs(a - b);
    if diff <= max_diff {
        return true;
    }
    if a.is_sign_positive() && !b.is_sign_positive() {
        return false;
    }
    let a_i64 = unsafe{::std::mem::transmute::<_, i64>(a)};
    let b_i64 = unsafe{::std::mem::transmute::<_, i64>(b)};
    let ulps_diff = i64::abs(a_i64 - b_i64);
    return ulps_diff <= max_ulps_diff;
}

#[inline]
fn fact(n: u64) -> u64 {
    //TODO: This could be made faster with better algorithm, but it's called with low values so it doesn't matter much.
    if n < 2 {
        1
    } else {
        n * fact(n - 1)
    }
}

#[test]
fn factorial_works() {
    assert_eq!(1, fact(0));
    let mut x = 1;
    for n in 1..21 {
        x *= n;
        assert_eq!(x, fact(n));
    }
}
<|endoftext|>


<commit_before>extern crate xz_embedded_sys as raw;

pub fn decompress(compressed_data: &[u8]) -> Vec<u8> {
    unsafe {
        raw::xz_crc32_init();
        raw::xz_crc64_init();
    }
    let state = unsafe {
        raw::xz_dec_init(raw::xz_mode::XZ_DYNALLOC, 1 << 26)
    };
    if state.is_null() { panic!("failed to init") }

    let mut out_vec = Vec::new();

    let out_size = 4096;
    let mut out_buf = Vec::with_capacity(out_size);
    out_buf.resize(out_size, 0);

    let mut buf = raw::xz_buf {
        _in: compressed_data.as_ptr(),
        in_size: compressed_data.len() as u64,
        in_pos:0,

        out: out_buf.as_mut_ptr(),
        out_pos: 0,
        out_size: out_size as u64,
    };

    loop {
        let ret = unsafe { raw::xz_dec_run(state, &mut buf) };
        //println!("Decomp returned {:?}", ret);
        if ret == raw::xz_ret::XZ_OK {
            out_vec.extend_from_slice(&out_buf[0..(buf.out_pos as usize)]);
            buf.out_pos = 0;
        } else if ret == raw::xz_ret::XZ_STREAM_END {
            out_vec.extend_from_slice(&out_buf[0..(buf.out_pos as usize)]);
            break;
        } else {
            panic!("Decompressing error {:?}", ret);
        }
        if buf.in_pos == buf.in_size {
            println!("Reached end of in buffer");
            break;
        }
    }

    out_vec

}

#[test]
fn it_works() {

    unsafe {
        raw::xz_crc32_init();
        raw::xz_crc64_init();

        let state = raw::xz_dec_init(raw::xz_mode::XZ_DYNALLOC, 1 << 26);

        let mut out_buf: [u8; 32] = [0; 32];
        let in_buf = include_bytes!("/storage/home/achin/devel/xz-embedded/userspace/hello.xz");

        let mut buf = raw::xz_buf {
            _in: in_buf.as_ptr(),
            in_size: in_buf.len() as u64,
            in_pos:0,

            out: out_buf.as_mut_ptr(),
            out_pos: 0,
            out_size: 2,

        };

        let ret = raw::xz_dec_run(state, &mut buf);
        println!("ret={:?}", ret);
        println!("out_pos: {}", buf.out_pos);
        println!("out_size: {}", buf.out_size);
        let mut v = Vec::from(&out_buf[..]);
        v.truncate(buf.out_pos as usize);
        println!("{}", String::from_utf8(v).unwrap());
        println!("in_pos: {}", buf.in_pos);

    }

}
<commit_msg>Don't forget to call xz_dec_end to free memory<commit_after>extern crate xz_embedded_sys as raw;

pub fn decompress(compressed_data: &[u8]) -> Vec<u8> {
    unsafe {
        raw::xz_crc32_init();
        raw::xz_crc64_init();
    }
    let state = unsafe {
        raw::xz_dec_init(raw::xz_mode::XZ_DYNALLOC, 1 << 26)
    };
    if state.is_null() { panic!("failed to init") }

    let mut out_vec = Vec::new();

    let out_size = 4096;
    let mut out_buf = Vec::with_capacity(out_size);
    out_buf.resize(out_size, 0);

    let mut buf = raw::xz_buf {
        _in: compressed_data.as_ptr(),
        in_size: compressed_data.len() as u64,
        in_pos:0,

        out: out_buf.as_mut_ptr(),
        out_pos: 0,
        out_size: out_size as u64,
    };

    loop {
        let ret = unsafe { raw::xz_dec_run(state, &mut buf) };
        //println!("Decomp returned {:?}", ret);
        if ret == raw::xz_ret::XZ_OK {
            out_vec.extend_from_slice(&out_buf[0..(buf.out_pos as usize)]);
            buf.out_pos = 0;
        } else if ret == raw::xz_ret::XZ_STREAM_END {
            out_vec.extend_from_slice(&out_buf[0..(buf.out_pos as usize)]);
            break;
        } else {
            panic!("Decompressing error {:?}", ret);
        }
        if buf.in_pos == buf.in_size {
            println!("Reached end of in buffer");
            break;
        }
    }

    unsafe { raw::xz_dec_end(state) };

    out_vec

}

#[test]
fn it_works() {

    unsafe {
        raw::xz_crc32_init();
        raw::xz_crc64_init();

        let state = raw::xz_dec_init(raw::xz_mode::XZ_DYNALLOC, 1 << 26);

        let mut out_buf: [u8; 32] = [0; 32];
        let in_buf = include_bytes!("/storage/home/achin/devel/xz-embedded/userspace/hello.xz");

        let mut buf = raw::xz_buf {
            _in: in_buf.as_ptr(),
            in_size: in_buf.len() as u64,
            in_pos:0,

            out: out_buf.as_mut_ptr(),
            out_pos: 0,
            out_size: 2,

        };

        let ret = raw::xz_dec_run(state, &mut buf);
        println!("ret={:?}", ret);
        println!("out_pos: {}", buf.out_pos);
        println!("out_size: {}", buf.out_size);
        let mut v = Vec::from(&out_buf[..]);
        v.truncate(buf.out_pos as usize);
        println!("{}", String::from_utf8(v).unwrap());
        println!("in_pos: {}", buf.in_pos);

    }

}
<|endoftext|>


<commit_before>// Copyright 2016 oauth-client-rs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

//! OAuth 1.0 client library for Rust.
//!
//! Dependent on libcurl.
//!
//! [Repository](https://github.com/charlag/oauth-client-rs)
//!
//!# Examples
//!
//! Send request for request token.
//!
//! ```
//!let consumer = Token::new("key", "secret")
//!let bytes = oauth::get(api::REQUEST_TOKEN, consumer, None, None).unwrap();
//! ```

#![warn(bad_style)]
#![warn(missing_docs)]
#![warn(unused)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]

extern crate crypto;
extern crate curl;
#[macro_use]
extern crate log;
extern crate rand;
extern crate rustc_serialize;
extern crate time;
extern crate url;

use std::borrow::Cow;
use std::collections::HashMap;
use std::{error, fmt};
use rand::Rng;
use rustc_serialize::base64::{self, ToBase64};
use crypto::hmac::Hmac;
use crypto::mac::{Mac, MacResult};
use crypto::sha1::Sha1;
use curl::http::{self, Response};
use curl::http::handle::Method;
use url::percent_encoding;

/// The `Error` type
#[derive(Debug)]
pub enum Error {
    /// Curl error
    Curl(curl::ErrCode),
    /// Http status
    HttpStatus(Response),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Curl(ref err) => write!(f, "Curl error: {}", err),
            Error::HttpStatus(ref resp) => write!(f, "HTTP status error: {}", resp),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Curl(ref err) => err.description(),
            Error::HttpStatus(_) => "HTTP status error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Curl(ref err) => Some(err),
            Error::HttpStatus(_) => None,
        }
    }
}

impl From<curl::ErrCode> for Error {
    fn from(err: curl::ErrCode) -> Error {
        Error::Curl(err)
    }
}

/// Token structure for the OAuth
#[derive(Clone, Debug)]
pub struct Token<'a> {
    pub key: Cow<'a, str>,
    pub secret: Cow<'a, str>,
}

impl<'a> Token<'a> {
    /// Create new token from `key` and `secret`
    ///
    ///# Examples
    ///
    /// ```
    ///let consumer = Token::new("key", "secret");
    /// ```
    pub fn new<K, S>(key: K, secret: S) -> Token<'a>
        where K: Into<Cow<'a, str>>,
              S: Into<Cow<'a, str>>
    {
        Token {
            key: key.into(),
            secret: secret.into(),
        }
    }
}

/// Alias for `HashMap<Cow<'a, str>, Cow<'a, str>>`
pub type ParamList<'a> = HashMap<Cow<'a, str>, Cow<'a, str>>;

fn insert_param<'a, K, V>(param: &mut ParamList<'a>, key: K, value: V) -> Option<Cow<'a, str>>
    where K: Into<Cow<'a, str>>,
          V: Into<Cow<'a, str>>
{
    param.insert(key.into(), value.into())
}

fn join_query<'a>(param: &ParamList<'a>) -> String {
    let mut pairs = param.iter()
                         .map(|(k, v)| format!("{}={}", encode(&k), encode(&v)))
                         .collect::<Vec<_>>();
    pairs.sort();
    pairs.join("&")
}

/// Percent encode string
fn encode(s: &str) -> String {
    percent_encoding::utf8_percent_encode(s, percent_encoding::FORM_URLENCODED_ENCODE_SET)
}

/// Wrapper function around 'crypto::Hmac'
fn hmac_sha1(key: &[u8], data: &[u8]) -> MacResult {
    let mut hmac = Hmac::new(Sha1::new(), key);
    hmac.input(data);
    hmac.result()
}

/// Create signature. See https://dev.twitter.com/oauth/overview/creating-signatures
fn signature(method: &str,
             uri: &str,
             query: &str,
             consumer_secret: &str,
             token_secret: Option<&str>)
             -> String {
    let base = format!("{}&{}&{}", encode(method), encode(uri), encode(query));
    let key = format!("{}&{}",
                      encode(consumer_secret),
                      encode(token_secret.unwrap_or("")));
    let conf = base64::Config {
        char_set: base64::CharacterSet::Standard,
        newline: base64::Newline::LF,
        pad: true,
        line_length: None,
    };
    debug!("Signature base string: {}", base);
    debug!("Authorization header: Authorization: {}", base);
    hmac_sha1(key.as_bytes(), base.as_bytes()).code().to_base64(conf)
}

/// Constuct plain-text header
fn header(param: &ParamList) -> String {
    let mut pairs = param.iter()
                         .filter(|&(k, _)| k.starts_with("oauth_"))
                         .map(|(k, v)| format!("{}=\"{}\"", k, encode(&v)))
                         .collect::<Vec<_>>();
    pairs.sort();
    format!("OAuth {}", pairs.join(", "))
}

/// Construct plain-text body from 'PaaramList'
fn body(param: &ParamList) -> String {
    let mut pairs = param.iter()
                         .filter(|&(k, _)| !k.starts_with("oauth_"))
                         .map(|(k, v)| format!("{}={}", k, encode(&v)))
                         .collect::<Vec<_>>();
    pairs.sort();
    format!("{}", pairs.join("&"))
}

/// Create header and body
fn get_header(method: Method,
              uri: &str,
              consumer: &Token,
              token: Option<&Token>,
              other_param: Option<&ParamList>)
              -> (String, String) {
    let mut param = HashMap::new();
    let timestamp = format!("{}", time::now_utc().to_timespec().sec);
    let nonce = rand::thread_rng().gen_ascii_chars().take(32).collect::<String>();

    let _ = insert_param(&mut param, "oauth_consumer_key", consumer.key.to_string());
    let _ = insert_param(&mut param, "oauth_nonce", nonce);
    let _ = insert_param(&mut param, "oauth_signature_method", "HMAC-SHA1");
    let _ = insert_param(&mut param, "oauth_timestamp", timestamp);
    let _ = insert_param(&mut param, "oauth_version", "1.0");
    if let Some(tk) = token {
        let _ = insert_param(&mut param, "oauth_token", tk.key.as_ref());
    }

    if let Some(ps) = other_param {
        for (k, v) in ps.iter() {
            let _ = insert_param(&mut param, k.as_ref(), v.as_ref());
        }
    }

    let method_str = match method {
        Method::Options => "OPTIONS",
        Method::Get => "GET",
        Method::Head => "HEAD",
        Method::Post => "POST",
        Method::Put => "PUT",
        Method::Patch => "PATCH",
        Method::Delete => "DELETE",
        Method::Trace => "TRACE",
        Method::Connect => "CONNECT",
    };

    let sign = signature(method_str,
                         uri,
                         join_query(&param).as_ref(),
                         consumer.secret.as_ref(),
                         token.map(|t| t.secret.as_ref()));
    let _ = insert_param(&mut param, "oauth_signature", sign);

    (header(&param), body(&param))
}

/// Create an authorization header.
/// See https://dev.twitter.com/oauth/overview/authorizing-requests
///
///# Examples
///
///```
///let header = oauth::authorization_header(Method::Get, api::REQUEST_TOKEN, consumer, None, None);
///```
pub fn authorization_header(method: Method,
                            uri: &str,
                            consumer: &Token,
                            token: Option<&Token>,
                            other_param: Option<&ParamList>)
                            -> String {
    get_header(method, uri, consumer, token, other_param).0
}

/// Send authorized GET request to the specified URL.
/// `consumer` is a consumer token.
///
///# Examples
///
///```
///let REQUEST_TOKEN: &'static str = "http://oauthbin.com/v1/request-token"
///let bytes = oauth::get(REQUEST_TOKEN, consumer, None, None).unwrap();
///let resp = String::from_utf8(bytes).unwrap();
///```
pub fn get(uri: &str,
           consumer: &Token,
           token: Option<&Token>,
           other_param: Option<&ParamList>)
           -> Result<Vec<u8>, Error> {
    let (header, body) = get_header(Method::Get, uri, consumer, token, other_param);
    let req_uri = if body.len() > 0 {
        format!("{}?{}", uri, body)
    } else {
        format!("{}", uri)
    };
    let resp = try!(http::handle()
                        .get(req_uri)
                        .header("Authorization", header.as_ref())
                        .exec());
    debug!("{}", resp);
    if resp.get_code() != 200 {
        return Err(Error::HttpStatus(resp));
    }
    Ok(resp.move_body())
}

/// Send authorized POST request to the specified URL.
/// `consumer` is a consumer token.
///
///# Examples
///
///```
///let ACCESS_TOKEN: &'static str = "http://oauthbin.com/v1/access-token"
///let bytes = oauth::post(ACCESS_TOKEN, consumer, Some(request), None).unwrap();
///let resp = String::from_utf8(bytes).unwrap();
///```
pub fn post(uri: &str,
            consumer: &Token,
            token: Option<&Token>,
            other_param: Option<&ParamList>)
            -> Result<Vec<u8>, Error> {
    let (header, body) = get_header(Method::Post, uri, consumer, token, other_param);
    let resp = try!(http::handle()
                        .post(uri, &body)
                        .header("Authorization", header.as_ref())
                        .content_type("application/x-www-form-urlencoded")
                        .exec());
    debug!("{}", resp);
    if resp.get_code() != 200 {
        return Err(Error::HttpStatus(resp));
    }
    Ok(resp.move_body())
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;

    #[test]
    fn query() {
        let mut map = HashMap::new();
        let _ = map.insert("aaa".into(), "AAA".into());
        let _ = map.insert("bbbb".into(), "BBBB".into());
        let query = super::join_query(&map);
        assert_eq!("aaa=AAA&bbbb=BBBB", query);
    }
}
<commit_msg>Fix docs so it passes tests<commit_after>// Copyright 2016 oauth-client-rs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

//! OAuth 1.0 client library for Rust.
//!
//! Dependent on libcurl.
//!
//! [Repository](https://github.com/charlag/oauth-client-rs)
//!
//!# Examples
//!
//! Send request for request token.
//!
//! ```
//!const REQUEST_TOKEN: &'static str = "http://oauthbin.com/v1/request-token";
//!let consumer = oauth_client::Token::new("key", "secret");
//!let bytes = oauth_client::get(REQUEST_TOKEN, &consumer, None, None).unwrap();
//! ```

#![warn(bad_style)]
#![warn(missing_docs)]
#![warn(unused)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]

extern crate crypto;
extern crate curl;
#[macro_use]
extern crate log;
extern crate rand;
extern crate rustc_serialize;
extern crate time;
extern crate url;

use std::borrow::Cow;
use std::collections::HashMap;
use std::{error, fmt};
use rand::Rng;
use rustc_serialize::base64::{self, ToBase64};
use crypto::hmac::Hmac;
use crypto::mac::{Mac, MacResult};
use crypto::sha1::Sha1;
use curl::http::{self, Response};
use curl::http::handle::Method;
use url::percent_encoding;

/// The `Error` type
#[derive(Debug)]
pub enum Error {
    /// Curl error
    Curl(curl::ErrCode),
    /// Http status
    HttpStatus(Response),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Curl(ref err) => write!(f, "Curl error: {}", err),
            Error::HttpStatus(ref resp) => write!(f, "HTTP status error: {}", resp),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Curl(ref err) => err.description(),
            Error::HttpStatus(_) => "HTTP status error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Curl(ref err) => Some(err),
            Error::HttpStatus(_) => None,
        }
    }
}

impl From<curl::ErrCode> for Error {
    fn from(err: curl::ErrCode) -> Error {
        Error::Curl(err)
    }
}

/// Token structure for the OAuth
#[derive(Clone, Debug)]
pub struct Token<'a> {
    /// 'key' field of the token
    pub key: Cow<'a, str>,
    /// 'secret' part of the token
    pub secret: Cow<'a, str>,
}

impl<'a> Token<'a> {
    /// Create new token from `key` and `secret`
    ///
    ///# Examples
    ///
    /// ```
    ///let consumer = oauth_client::Token::new("key", "secret");
    /// ```
    pub fn new<K, S>(key: K, secret: S) -> Token<'a>
        where K: Into<Cow<'a, str>>,
              S: Into<Cow<'a, str>>
    {
        Token {
            key: key.into(),
            secret: secret.into(),
        }
    }
}

/// Alias for `HashMap<Cow<'a, str>, Cow<'a, str>>`
pub type ParamList<'a> = HashMap<Cow<'a, str>, Cow<'a, str>>;

fn insert_param<'a, K, V>(param: &mut ParamList<'a>, key: K, value: V) -> Option<Cow<'a, str>>
    where K: Into<Cow<'a, str>>,
          V: Into<Cow<'a, str>>
{
    param.insert(key.into(), value.into())
}

fn join_query<'a>(param: &ParamList<'a>) -> String {
    let mut pairs = param.iter()
                         .map(|(k, v)| format!("{}={}", encode(&k), encode(&v)))
                         .collect::<Vec<_>>();
    pairs.sort();
    pairs.join("&")
}

/// Percent encode string
fn encode(s: &str) -> String {
    percent_encoding::utf8_percent_encode(s, percent_encoding::FORM_URLENCODED_ENCODE_SET)
}

/// Wrapper function around 'crypto::Hmac'
fn hmac_sha1(key: &[u8], data: &[u8]) -> MacResult {
    let mut hmac = Hmac::new(Sha1::new(), key);
    hmac.input(data);
    hmac.result()
}

/// Create signature. See https://dev.twitter.com/oauth/overview/creating-signatures
fn signature(method: &str,
             uri: &str,
             query: &str,
             consumer_secret: &str,
             token_secret: Option<&str>)
             -> String {
    let base = format!("{}&{}&{}", encode(method), encode(uri), encode(query));
    let key = format!("{}&{}",
                      encode(consumer_secret),
                      encode(token_secret.unwrap_or("")));
    let conf = base64::Config {
        char_set: base64::CharacterSet::Standard,
        newline: base64::Newline::LF,
        pad: true,
        line_length: None,
    };
    debug!("Signature base string: {}", base);
    debug!("Authorization header: Authorization: {}", base);
    hmac_sha1(key.as_bytes(), base.as_bytes()).code().to_base64(conf)
}

/// Constuct plain-text header
fn header(param: &ParamList) -> String {
    let mut pairs = param.iter()
                         .filter(|&(k, _)| k.starts_with("oauth_"))
                         .map(|(k, v)| format!("{}=\"{}\"", k, encode(&v)))
                         .collect::<Vec<_>>();
    pairs.sort();
    format!("OAuth {}", pairs.join(", "))
}

/// Construct plain-text body from 'PaaramList'
fn body(param: &ParamList) -> String {
    let mut pairs = param.iter()
                         .filter(|&(k, _)| !k.starts_with("oauth_"))
                         .map(|(k, v)| format!("{}={}", k, encode(&v)))
                         .collect::<Vec<_>>();
    pairs.sort();
    format!("{}", pairs.join("&"))
}

/// Create header and body
fn get_header(method: Method,
              uri: &str,
              consumer: &Token,
              token: Option<&Token>,
              other_param: Option<&ParamList>)
              -> (String, String) {
    let mut param = HashMap::new();
    let timestamp = format!("{}", time::now_utc().to_timespec().sec);
    let nonce = rand::thread_rng().gen_ascii_chars().take(32).collect::<String>();

    let _ = insert_param(&mut param, "oauth_consumer_key", consumer.key.to_string());
    let _ = insert_param(&mut param, "oauth_nonce", nonce);
    let _ = insert_param(&mut param, "oauth_signature_method", "HMAC-SHA1");
    let _ = insert_param(&mut param, "oauth_timestamp", timestamp);
    let _ = insert_param(&mut param, "oauth_version", "1.0");
    if let Some(tk) = token {
        let _ = insert_param(&mut param, "oauth_token", tk.key.as_ref());
    }

    if let Some(ps) = other_param {
        for (k, v) in ps.iter() {
            let _ = insert_param(&mut param, k.as_ref(), v.as_ref());
        }
    }

    let method_str = match method {
        Method::Options => "OPTIONS",
        Method::Get => "GET",
        Method::Head => "HEAD",
        Method::Post => "POST",
        Method::Put => "PUT",
        Method::Patch => "PATCH",
        Method::Delete => "DELETE",
        Method::Trace => "TRACE",
        Method::Connect => "CONNECT",
    };

    let sign = signature(method_str,
                         uri,
                         join_query(&param).as_ref(),
                         consumer.secret.as_ref(),
                         token.map(|t| t.secret.as_ref()));
    let _ = insert_param(&mut param, "oauth_signature", sign);

    (header(&param), body(&param))
}

/// Create an authorization header.
/// See https://dev.twitter.com/oauth/overview/authorizing-requests
///
///# Examples
///
///```
///# extern crate curl;
///# extern crate oauth_client;
/// use curl::http::handle::Method;
///# fn main() {
///const REQUEST_TOKEN: &'static str = "http://oauthbin.com/v1/request-token";
///let consumer = oauth_client::Token::new("key", "secret");
///let header = oauth_client::authorization_header(Method::Get, REQUEST_TOKEN, &consumer, None, None);
///# }
///```
pub fn authorization_header(method: Method,
                            uri: &str,
                            consumer: &Token,
                            token: Option<&Token>,
                            other_param: Option<&ParamList>)
                            -> String {
    get_header(method, uri, consumer, token, other_param).0
}

/// Send authorized GET request to the specified URL.
/// `consumer` is a consumer token.
///
///# Examples
///
///```
///let REQUEST_TOKEN: &'static str = "http://oauthbin.com/v1/request-token";
///let consumer = oauth_client::Token::new("key", "secret");
///let bytes = oauth_client::get(REQUEST_TOKEN, &consumer, None, None).unwrap();
///let resp = String::from_utf8(bytes).unwrap();
///```
pub fn get(uri: &str,
           consumer: &Token,
           token: Option<&Token>,
           other_param: Option<&ParamList>)
           -> Result<Vec<u8>, Error> {
    let (header, body) = get_header(Method::Get, uri, consumer, token, other_param);
    let req_uri = if body.len() > 0 {
        format!("{}?{}", uri, body)
    } else {
        format!("{}", uri)
    };
    let resp = try!(http::handle()
                        .get(req_uri)
                        .header("Authorization", header.as_ref())
                        .exec());
    debug!("{}", resp);
    if resp.get_code() != 200 {
        return Err(Error::HttpStatus(resp));
    }
    Ok(resp.move_body())
}

/// Send authorized POST request to the specified URL.
/// `consumer` is a consumer token.
///
///# Examples
///
///```
///# let request = oauth_client::Token::new("key", "secret");
///let ACCESS_TOKEN: &'static str = "http://oauthbin.com/v1/access-token";
///let consumer = oauth_client::Token::new("key", "secret");
///let bytes = oauth_client::post(ACCESS_TOKEN, &consumer, Some(&request), None).unwrap();
///let resp = String::from_utf8(bytes).unwrap();
///```
pub fn post(uri: &str,
            consumer: &Token,
            token: Option<&Token>,
            other_param: Option<&ParamList>)
            -> Result<Vec<u8>, Error> {
    let (header, body) = get_header(Method::Post, uri, consumer, token, other_param);
    let resp = try!(http::handle()
                        .post(uri, &body)
                        .header("Authorization", header.as_ref())
                        .content_type("application/x-www-form-urlencoded")
                        .exec());
    debug!("{}", resp);
    if resp.get_code() != 200 {
        return Err(Error::HttpStatus(resp));
    }
    Ok(resp.move_body())
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;

    #[test]
    fn query() {
        let mut map = HashMap::new();
        let _ = map.insert("aaa".into(), "AAA".into());
        let _ = map.insert("bbbb".into(), "BBBB".into());
        let query = super::join_query(&map);
        assert_eq!("aaa=AAA&bbbb=BBBB", query);
    }
}
<|endoftext|>


<commit_before>#[deny(missing_docs)]

extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;
mod rebind;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::hash::Hash;
use viewport::Viewport;

pub use rebind::InputRebind;
pub use builder::InputTranslatorBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone)]
pub struct InputTranslator<A: Action> {
    keymap: KeyTranslator<A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {

    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: KeyTranslator::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.translate($but_var) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    pub fn add_binding(&mut self, but: Button, act: A) {
        self.keymap.add_mapping(but, act);
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslator {
    pub x_axis_motion_inverted: bool,
    pub y_axis_motion_inverted: bool,
    pub x_axis_scroll_inverted: bool,
    pub y_axis_scroll_inverted: bool,
    pub viewport_size: Size
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

#[derive(Clone, Debug)]
struct KeyTranslator<A: Action> {
    btn_map: HashMap<ButtonTuple, A>
}

impl<A: Action> KeyTranslator<A> {
    fn new() -> Self {
        KeyTranslator {
            btn_map: HashMap::new()
        }
    }

    fn add_mapping(&mut self, button: Button, action: A) {
        let mut bt = self.get_bindings_for_action(action).unwrap_or(ButtonTuple::new());
        let bt = if bt.insert_inplace(button) {bt} else {ButtonTuple::new()};
        self.btn_map.insert(bt, action);
    }

    fn get_bindings_for_action(&self, action: A) -> Option<ButtonTuple> {
        self.btn_map.iter().find(|&(_, &a)| a == action).map(|(&bt, _)| bt)
    }

    #[allow(dead_code)]
    fn get_ref_bindings_for_action(&self, action: A) -> Option<&ButtonTuple> {
        self.btn_map.iter().find(|&(_, &a)| a == action).map(|(bt, _)| bt)
    }

    #[cfg(unimplemented)] // This gives a compile error
    fn get_ref_bindings_for_action_mut(&mut self, action: A) -> Option<&mut ButtonTuple> {
        self.btn_map.iter_mut().find(|&(_, &mut a)| a == action).as_mut().map(|&mut (bt, _)| bt)
    }

    fn translate(&self, button: Button) -> Option<A> {
        self.btn_map.iter().find(|&(&bt, _)| bt.contains(button)).map(|(_, &a)| a)
    }
}

/// A three-element tuple of Option<Button>. Used as the key of an InputTranslator
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    fn new() -> Self { Default::default() }

    fn contains(&self, btn: Button) -> bool {
        let sbtn = Some(btn);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    #[allow(dead_code)]
    fn remove_inplace(&mut self, btn: Button) {
        let sbtn = Some(btn);
        if self.0 == sbtn {self.0 = None}
        if self.1 == sbtn {self.1 = None}
        if self.2 == sbtn {self.2 = None}
    }

    #[allow(dead_code)]
    fn replace_inplace(&mut self, btn_idx: u32, btn: Button) -> bool {
        match btn_idx {
            0 => {self.0 = Some(btn); true},
            1 => {self.1 = Some(btn); true},
            2 => {self.2 = Some(btn); true},
            _ => false
        }
    }

    fn insert_inplace(&mut self, btn: Button) -> bool {
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(Some(btn), b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, Some(btn), c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, Some(btn)); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    fn default() -> Self { ButtonTuple(None, None, None) }
}
<commit_msg>Remove unnecessary methods subsumed by InputRebind<commit_after>#[deny(missing_docs)]

extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;
mod rebind;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::hash::Hash;
use viewport::Viewport;

pub use rebind::InputRebind;
pub use builder::InputTranslatorBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone)]
pub struct InputTranslator<A: Action> {
    keymap: KeyTranslator<A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {

    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: KeyTranslator::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.translate($but_var) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    pub fn add_binding(&mut self, but: Button, act: A) {
        self.keymap.add_mapping(but, act);
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslator {
    pub x_axis_motion_inverted: bool,
    pub y_axis_motion_inverted: bool,
    pub x_axis_scroll_inverted: bool,
    pub y_axis_scroll_inverted: bool,
    pub viewport_size: Size
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

#[derive(Clone, Debug)]
struct KeyTranslator<A: Action> {
    btn_map: HashMap<ButtonTuple, A>
}

impl<A: Action> KeyTranslator<A> {
    fn new() -> Self {
        KeyTranslator {
            btn_map: HashMap::new()
        }
    }

    fn add_mapping(&mut self, button: Button, action: A) {
        let mut bt = self.get_bindings_for_action(action).unwrap_or(ButtonTuple::new());
        let bt = if bt.insert_inplace(button) {bt} else {ButtonTuple::new()};
        self.btn_map.insert(bt, action);
    }

    fn get_bindings_for_action(&self, action: A) -> Option<ButtonTuple> {
        self.btn_map.iter().find(|&(_, &a)| a == action).map(|(&bt, _)| bt)
    }

    fn translate(&self, button: Button) -> Option<A> {
        self.btn_map.iter().find(|&(&bt, _)| bt.contains(button)).map(|(_, &a)| a)
    }
}

/// A three-element tuple of Option<Button>. Used as the key of an InputTranslator
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    fn new() -> Self { Default::default() }

    fn contains(&self, btn: Button) -> bool {
        let sbtn = Some(btn);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    #[allow(dead_code)]
    fn remove_inplace(&mut self, btn: Button) {
        let sbtn = Some(btn);
        if self.0 == sbtn {self.0 = None}
        if self.1 == sbtn {self.1 = None}
        if self.2 == sbtn {self.2 = None}
    }

    #[allow(dead_code)]
    fn replace_inplace(&mut self, btn_idx: u32, btn: Button) -> bool {
        match btn_idx {
            0 => {self.0 = Some(btn); true},
            1 => {self.1 = Some(btn); true},
            2 => {self.2 = Some(btn); true},
            _ => false
        }
    }

    fn insert_inplace(&mut self, btn: Button) -> bool {
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(Some(btn), b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, Some(btn), c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, Some(btn)); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    fn default() -> Self { ButtonTuple(None, None, None) }
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate url;
extern crate serde;
extern crate serde_json;

use std::io::{Read, Write};
use std::io::Error as IoError;

use serde::de::Deserialize;
use hyper::client::Request as HyperRequest;
use hyper::client::Response as HyperResponse;
use hyper::method::Method;
use hyper::net::Fresh;

#[doc(no_inline)]
pub use hyper::header::{Headers, Header, HeaderFormat, UserAgent};
#[doc(no_inline)]
pub use url::Url;
#[doc(no_inline)]
pub use hyper::error::Error as HyperError;
#[doc(no_inline)]
pub use hyper::status::StatusCode;

#[derive(Debug)]
pub enum Error {
    UnsuccessfulResponse(Response),
    Json(serde_json::error::Error),
    Hyper(HyperError)
}

impl From<HyperError> for Error {
    fn from(h: HyperError) -> Error {
        Error::Hyper(h)
    }
}

impl From<IoError> for Error {
    fn from(i: IoError) -> Error {
        Error::Hyper(HyperError::Io(i))
    }
}

#[derive(Debug)]
pub struct Response {
    pub hyper_response: HyperResponse,
    pub body: String
}

impl Response {
    fn from_hyper_response(mut hyper_response: HyperResponse) -> Result<Response, IoError> {
        let mut body = String::new();
        hyper_response.read_to_string(&mut body).map(|_| Response{ hyper_response: hyper_response, body: body })
    }

    /// Deserializes the body of the response from JSON into
    /// a `T`.
    pub fn from_json<T: Deserialize>(&self) -> Result<T, Error> {
        serde_json::from_str(&*self.body).map_err(|e| Error::Json(e))
    }
}

#[derive(Clone)]
pub struct Request<'a> {
    url: Url,
    params: Option<Vec<(&'a str, &'a str)>>,
    body: Option<String>,
    headers: Option<Headers>,
}

impl<'a> Request<'a> {
    pub fn new(url: Url) -> Request<'a> {
        Request { url: url, params: None, body: None, headers: None }
    }

    /// Sets one parameter. On a GET or DELETE request, this parameter will
    /// be stored in the URL. On a POST or PUT request, it is stored in the
    /// body of the request. Hence, if you call this method on a POST or
    /// PUT request, you cannot also call `body`.
    pub fn param(&mut self, key: &'a str, value: &'a str) -> &mut Request<'a> {
        if let Some(ref mut p) = self.params {
            p.push((key, value));
        } else {
            let mut v = Vec::new();
            v.push((key, value));
            self.params = Some(v);
        }
        self
    }

    /// Sets many parameters. On a GET or DELETE request, these parameters will
    /// be stored in the URL. On a POST or PUT request, they are stored in the
    /// body of the request. Hence, if you call this method on a POST or
    /// PUT request, you cannot also call `body`.
    pub fn params<T>(&mut self, values: T) -> &mut Request<'a>
        where T: IntoIterator<Item = (&'a str, &'a str)>
    {
        if let Some(ref mut p) = self.params {
            for value in values {
                p.push(value);
            }
        } else {
            let mut v = Vec::new();
            for value in values {
                v.push(value);
            }
            self.params = Some(v);
        }
        self
    }

    /// Writes a `String` to the body of the request. Don't call this
    /// method if you also call `param` on a PUT or POST request.
    pub fn body(&mut self, body: String) -> &mut Request<'a> {
        self.body = Some(body);
        self
    }

    /// Sets a header for the request.
    pub fn header<H: Header + HeaderFormat>(&mut self, header: H) -> &mut Request<'a> {
        if let Some(ref mut h) = self.headers {
            h.set(header);
        } else {
            let mut v = Headers::new();
            v.set(header);
            self.headers = Some(v);
        }
        self
    }

    fn send_request(&mut self, mut req: HyperRequest<Fresh>) -> Result<Response, Error> {
        if let Some(headers) = self.headers.as_ref() {
            req.headers_mut().extend(headers.iter());
        }

        let mut req = try!(req.start());

        if let Some(body) = self.body.as_ref() {
            try!(req.write_all(body.as_bytes()));
        }

        let resp = try!(req.send());
        let resp = try!(Response::from_hyper_response(resp));

        if resp.hyper_response.status.is_success() {
            Ok(resp)
        } else {
            Err(Error::UnsuccessfulResponse(resp))
        }
    }

    /// Sends a GET request and returns either an error
    /// or a `String` of the response.
    pub fn get(&mut self) -> Result<Response, Error> {
        let mut url = self.url.clone();

        if let Some(ref params) = self.params {
            url.set_query_from_pairs(params.into_iter().map(|&x| x));
        }

        let req = try!(HyperRequest::new(Method::Get, url));
        self.send_request(req)
    }

    /// Sends a DELETE request and returns either an error
    /// or a `String` of the response.
    pub fn delete(&mut self) -> Result<Response, Error> {
        let mut url = self.url.clone();

        if let Some(ref params) = self.params {
            url.set_query_from_pairs(params.into_iter().map(|&x| x));
        }

        let req = try!(HyperRequest::new(Method::Delete, url));
        self.send_request(req)
    }

    /// Sends a POST request and returns either an error
    /// or a `String` of the response.
    pub fn post(&mut self) -> Result<Response, Error> {
        let url = self.url.clone();

        if let Some(ref params) = self.params {
            self.body = Some(url::form_urlencoded::serialize(params.into_iter()));
        }

        let req = try!(HyperRequest::new(Method::Post, url));
        self.send_request(req)
    }

    /// Sends a PUT request and returns either an error
    /// or a `String` of the response.
    pub fn put(&mut self) -> Result<Response, Error> {
        let url = self.url.clone();

        if let Some(ref params) = self.params {
            self.body = Some(url::form_urlencoded::serialize(params.into_iter()));
        }

        let req = try!(HyperRequest::new(Method::Put, url));
        self.send_request(req)
    }
}
<commit_msg>Add read timeout.<commit_after>extern crate hyper;
extern crate url;
extern crate serde;
extern crate serde_json;

use std::io::{Read, Write};
use std::io::Error as IoError;
use std::time::Duration;

use serde::de::Deserialize;
use hyper::client::Request as HyperRequest;
use hyper::client::Response as HyperResponse;
use hyper::method::Method;
use hyper::net::Fresh;

#[doc(no_inline)]
pub use hyper::header::{Headers, Header, HeaderFormat, UserAgent};
#[doc(no_inline)]
pub use url::Url;
#[doc(no_inline)]
pub use hyper::error::Error as HyperError;
#[doc(no_inline)]
pub use hyper::status::StatusCode;

#[derive(Debug)]
pub enum Error {
    UnsuccessfulResponse(Response),
    Json(serde_json::error::Error),
    Hyper(HyperError),
}

impl From<HyperError> for Error {
    fn from(h: HyperError) -> Error {
        Error::Hyper(h)
    }
}

impl From<IoError> for Error {
    fn from(i: IoError) -> Error {
        Error::Hyper(HyperError::Io(i))
    }
}

#[derive(Debug)]
pub struct Response {
    pub hyper_response: HyperResponse,
    pub body: String,
}

impl Response {
    fn from_hyper_response(mut hyper_response: HyperResponse) -> Result<Response, IoError> {
        let mut body = String::new();
        hyper_response.read_to_string(&mut body).map(|_| {
            Response {
                hyper_response: hyper_response,
                body: body,
            }
        })
    }

    /// Deserializes the body of the response from JSON into
    /// a `T`.
    pub fn from_json<T: Deserialize>(&self) -> Result<T, Error> {
        serde_json::from_str(&*self.body).map_err(|e| Error::Json(e))
    }
}

#[derive(Clone)]
pub struct Request<'a> {
    url: Url,
    params: Option<Vec<(&'a str, &'a str)>>,
    body: Option<String>,
    read_timeout: Option<Duration>,
    headers: Option<Headers>,
}

impl<'a> Request<'a> {
    pub fn new(url: Url) -> Request<'a> {
        Request {
            url: url,
            params: None,
            body: None,
            read_timeout: None,
            headers: None,
        }
    }

    /// Sets one parameter. On a GET or DELETE request, this parameter will
    /// be stored in the URL. On a POST or PUT request, it is stored in the
    /// body of the request. Hence, if you call this method on a POST or
    /// PUT request, you cannot also call `body`.
    pub fn param(&mut self, key: &'a str, value: &'a str) -> &mut Request<'a> {
        if let Some(ref mut p) = self.params {
            p.push((key, value));
        } else {
            let mut v = Vec::new();
            v.push((key, value));
            self.params = Some(v);
        }
        self
    }

    /// Sets many parameters. On a GET or DELETE request, these parameters will
    /// be stored in the URL. On a POST or PUT request, they are stored in the
    /// body of the request. Hence, if you call this method on a POST or
    /// PUT request, you cannot also call `body`.
    pub fn params<T>(&mut self, values: T) -> &mut Request<'a>
        where T: IntoIterator<Item = (&'a str, &'a str)>
    {
        if let Some(ref mut p) = self.params {
            for value in values {
                p.push(value);
            }
        } else {
            let mut v = Vec::new();
            for value in values {
                v.push(value);
            }
            self.params = Some(v);
        }
        self
    }

    /// Writes a `String` to the body of the request. Don't call this
    /// method if you also call `param` on a PUT or POST request.
    pub fn body(&mut self, body: String) -> &mut Request<'a> {
        self.body = Some(body);
        self
    }

    /// Sets a header for the request.
    pub fn header<H: Header + HeaderFormat>(&mut self, header: H) -> &mut Request<'a> {
        if let Some(ref mut h) = self.headers {
            h.set(header);
        } else {
            let mut v = Headers::new();
            v.set(header);
            self.headers = Some(v);
        }
        self
    }

    /// Sets a read timeout for the response.
    pub fn read_timeout(&mut self, timeout: Duration) -> &mut Request<'a> {
        self.read_timeout = Some(timeout);
        self
    }

    fn send_request(&mut self, mut req: HyperRequest<Fresh>) -> Result<Response, Error> {
        if let Some(headers) = self.headers.as_ref() {
            req.headers_mut().extend(headers.iter());
        }

        let _ = req.set_read_timeout(self.read_timeout);

        let mut req = try!(req.start());

        if let Some(body) = self.body.as_ref() {
            try!(req.write_all(body.as_bytes()));
        }

        let resp = try!(req.send());
        let resp = try!(Response::from_hyper_response(resp));

        if resp.hyper_response.status.is_success() {
            Ok(resp)
        } else {
            Err(Error::UnsuccessfulResponse(resp))
        }
    }

    /// Sends a GET request and returns either an error
    /// or a `String` of the response.
    pub fn get(&mut self) -> Result<Response, Error> {
        let mut url = self.url.clone();

        if let Some(ref params) = self.params {
            url.set_query_from_pairs(params.into_iter().map(|&x| x));
        }

        let req = try!(HyperRequest::new(Method::Get, url));
        self.send_request(req)
    }

    /// Sends a DELETE request and returns either an error
    /// or a `String` of the response.
    pub fn delete(&mut self) -> Result<Response, Error> {
        let mut url = self.url.clone();

        if let Some(ref params) = self.params {
            url.set_query_from_pairs(params.into_iter().map(|&x| x));
        }

        let req = try!(HyperRequest::new(Method::Delete, url));
        self.send_request(req)
    }

    /// Sends a POST request and returns either an error
    /// or a `String` of the response.
    pub fn post(&mut self) -> Result<Response, Error> {
        let url = self.url.clone();

        if let Some(ref params) = self.params {
            self.body = Some(url::form_urlencoded::serialize(params.into_iter()));
        }

        let req = try!(HyperRequest::new(Method::Post, url));
        self.send_request(req)
    }

    /// Sends a PUT request and returns either an error
    /// or a `String` of the response.
    pub fn put(&mut self) -> Result<Response, Error> {
        let url = self.url.clone();

        if let Some(ref params) = self.params {
            self.body = Some(url::form_urlencoded::serialize(params.into_iter()));
        }

        let req = try!(HyperRequest::new(Method::Put, url));
        self.send_request(req)
    }
}
<|endoftext|>