<commit_before>#![feature(std_misc)]

extern crate "libxdo-sys" as sys;
extern crate libc;

use std::ffi::{CString, NulError};
use std::error::FromError;
use libc::c_int;
use std::ptr::null;
use std::time::Duration;

pub struct XDo {
    handle: *mut sys::xdo
}

#[derive(Debug)]
pub enum XDoCreationError {
    NulError(NulError),
    Unknown
}

impl FromError<NulError> for XDoCreationError {
    fn from_error(err: NulError) -> XDoCreationError {
        XDoCreationError::NulError(err)
    }
}

#[derive(Debug)]
enum XDoOperationErrorKind {
    IntParamOutOfRange{value: i64, min: i64, max: i64},
    NulError(NulError),
    OperationFailed
}

#[derive(Debug)]
struct XDoOperationError {
    kind: XDoOperationErrorKind
}

impl FromError<NulError> for XDoOperationError {
    fn from_error(err: NulError) -> XDoOperationError {
        XDoOperationError {
            kind: XDoOperationErrorKind::NulError(err)
        }
    }
}

pub type OpResult = Result<(), XDoOperationError>;

macro_rules! xdo (
    ($fncall: expr) => {
        unsafe {
            match $fncall {
                0 => Ok(()),
                _ => Err(XDoOperationError{ kind: XDoOperationErrorKind::OperationFailed })
            }
        }
    }
);

macro_rules! try_microsecs (
    ($duration: expr) => {{
        let microsecs = match $duration.num_microseconds() {
            Some(msecs) => msecs,
            None => return Err(XDoOperationError{
                kind: XDoOperationErrorKind::IntParamOutOfRange{value: -1, min: 0, max: 1000000}
            })
        };
        if microsecs < 0 || microsecs > 1000000 {
            return Err(XDoOperationError{
                kind: XDoOperationErrorKind::IntParamOutOfRange{
                    value: microsecs, min: 0, max: 1000000
                }
            });
        }
        microsecs
    }}
);

impl XDo {
    pub fn new(display: Option<&str>) -> Result<XDo, XDoCreationError> {
        let display = match display {
            Some(display) => {
                let cstr = try!(CString::new(display));
                cstr.as_ptr()
            },
            None => null()
        };
        let handle = unsafe { sys::xdo_new(display) };
        if handle.is_null() {
            return Err(XDoCreationError::Unknown);
        }
        Ok(XDo {
            handle: handle
        })
    }
    pub fn move_mouse(&self, x: i32, y: i32, screen: i32) -> OpResult {
        xdo!(sys::xdo_mousemove(self.handle, x as c_int, y as c_int, screen as c_int))
    }
    pub fn move_mouse_relative(&self, x: i32, y: i32) -> OpResult {
        xdo!(sys::xdo_mousemove_relative(self.handle, x as c_int, y as c_int))
    }
    pub fn click(&self, button: i32) -> OpResult {
        xdo!(sys::xdo_click(self.handle, sys::CURRENTWINDOW, button as c_int))
    }
    pub fn mouse_down(&self, button: i32) -> OpResult {
        xdo!(sys::xdo_mousedown(self.handle, sys::CURRENTWINDOW, button as c_int))
    }
    pub fn mouse_up(&self, button: i32) -> OpResult {
        xdo!(sys::xdo_mouseup(self.handle, sys::CURRENTWINDOW, button as c_int))
    }
    pub fn type_text(&self, text: &str, delay: Duration) -> OpResult {
        let microsecs = try_microsecs!(delay);
        let string = try!(CString::new(text));
        xdo!(sys::xdo_type(self.handle, sys::CURRENTWINDOW, string.as_ptr(), microsecs as u32))
    }
    pub fn key_sequence(&self, sequence: &str, delay: Duration) -> OpResult {
        let microsecs = try_microsecs!(delay);
        let string = try!(CString::new(sequence));
        xdo!(sys::xdo_keysequence(self.handle, sys::CURRENTWINDOW, string.as_ptr(),
                                  microsecs as u32))
    }
    pub fn key_sequence_up(&self, sequence: &str, delay: Duration) -> OpResult {
        let microsecs = try_microsecs!(delay);
        let string = try!(CString::new(sequence));
        xdo!(sys::xdo_keysequence_up(self.handle, sys::CURRENTWINDOW, string.as_ptr(),
                                     microsecs as u32))
    }
    pub fn key_sequence_down(&self, sequence: &str, delay: Duration) -> OpResult {
        let microsecs = try_microsecs!(delay);
        let string = try!(CString::new(sequence));
        xdo!(sys::xdo_keysequence_down(self.handle, sys::CURRENTWINDOW, string.as_ptr(),
                                       microsecs as u32))
    }
}

impl Drop for XDo {
    fn drop(&mut self) {
        unsafe { sys::xdo_free(self.handle); }
    }
}
<commit_msg>Add rough documentation<commit_after>//! High level bindings to [libxdo](http://www.semicomplete.com/files/xdotool/docs/html/)

#![feature(std_misc)]
#![warn(missing_docs)]

extern crate "libxdo-sys" as sys;
extern crate libc;

use std::ffi::{CString, NulError};
use std::error::FromError;
use libc::c_int;
use std::ptr::null;
use std::time::Duration;

/// An XDo instance
pub struct XDo {
    handle: *mut sys::xdo
}

/// An error that can happen when trying to create an XDo instance.
#[derive(Debug)]
pub enum XDoCreationError {
    /// The parameter passed in contained a nul character.
    NulError(NulError),
    /// Unknown error
    Unknown
}

impl FromError<NulError> for XDoCreationError {
    fn from_error(err: NulError) -> XDoCreationError {
        XDoCreationError::NulError(err)
    }
}

#[derive(Debug)]
enum XDoOperationErrorKind {
    IntParamOutOfRange{value: i64, min: i64, max: i64},
    NulError(NulError),
    OperationFailed
}

/// An error originating from an XDo operation.
#[derive(Debug)]
struct XDoOperationError {
    kind: XDoOperationErrorKind
}

impl FromError<NulError> for XDoOperationError {
    fn from_error(err: NulError) -> XDoOperationError {
        XDoOperationError {
            kind: XDoOperationErrorKind::NulError(err)
        }
    }
}

/// Result of an XDo operation.
pub type OpResult = Result<(), XDoOperationError>;

macro_rules! xdo (
    ($fncall: expr) => {
        unsafe {
            match $fncall {
                0 => Ok(()),
                _ => Err(XDoOperationError{ kind: XDoOperationErrorKind::OperationFailed })
            }
        }
    }
);

macro_rules! try_microsecs (
    ($duration: expr) => {{
        let microsecs = match $duration.num_microseconds() {
            Some(msecs) => msecs,
            None => return Err(XDoOperationError{
                kind: XDoOperationErrorKind::IntParamOutOfRange{value: -1, min: 0, max: 1000000}
            })
        };
        if microsecs < 0 || microsecs > 1000000 {
            return Err(XDoOperationError{
                kind: XDoOperationErrorKind::IntParamOutOfRange{
                    value: microsecs, min: 0, max: 1000000
                }
            });
        }
        microsecs
    }}
);

impl XDo {
    /// Creates a new XDo instance.
    ///
    /// # Parameters
    ///
    /// display - An optional string display name, such as ":0". If None, uses the environment
    /// DISPLAY.
    ///
    /// # Returns
    ///
    /// Returns a new XDo instance, or an XDoCreationError on error.
    pub fn new(display: Option<&str>) -> Result<XDo, XDoCreationError> {
        let display = match display {
            Some(display) => {
                let cstr = try!(CString::new(display));
                cstr.as_ptr()
            },
            None => null()
        };
        let handle = unsafe { sys::xdo_new(display) };
        if handle.is_null() {
            return Err(XDoCreationError::Unknown);
        }
        Ok(XDo {
            handle: handle
        })
    }
    /// Moves the mouse to the specified position.
    pub fn move_mouse(&self, x: i32, y: i32, screen: i32) -> OpResult {
        xdo!(sys::xdo_mousemove(self.handle, x as c_int, y as c_int, screen as c_int))
    }
    /// Moves the mouse relative to the current position.
    pub fn move_mouse_relative(&self, x: i32, y: i32) -> OpResult {
        xdo!(sys::xdo_mousemove_relative(self.handle, x as c_int, y as c_int))
    }
    /// Does a mouse click.
    pub fn click(&self, button: i32) -> OpResult {
        xdo!(sys::xdo_click(self.handle, sys::CURRENTWINDOW, button as c_int))
    }
    /// Holds a mouse button down.
    pub fn mouse_down(&self, button: i32) -> OpResult {
        xdo!(sys::xdo_mousedown(self.handle, sys::CURRENTWINDOW, button as c_int))
    }
    /// Releases a mouse button.
    pub fn mouse_up(&self, button: i32) -> OpResult {
        xdo!(sys::xdo_mouseup(self.handle, sys::CURRENTWINDOW, button as c_int))
    }
    /// Types the specified text.
    pub fn type_text(&self, text: &str, delay: Duration) -> OpResult {
        let microsecs = try_microsecs!(delay);
        let string = try!(CString::new(text));
        xdo!(sys::xdo_type(self.handle, sys::CURRENTWINDOW, string.as_ptr(), microsecs as u32))
    }
    /// Does the specified key sequence.
    pub fn key_sequence(&self, sequence: &str, delay: Duration) -> OpResult {
        let microsecs = try_microsecs!(delay);
        let string = try!(CString::new(sequence));
        xdo!(sys::xdo_keysequence(self.handle, sys::CURRENTWINDOW, string.as_ptr(),
                                  microsecs as u32))
    }
    /// Releases the specified key sequence.
    pub fn key_sequence_up(&self, sequence: &str, delay: Duration) -> OpResult {
        let microsecs = try_microsecs!(delay);
        let string = try!(CString::new(sequence));
        xdo!(sys::xdo_keysequence_up(self.handle, sys::CURRENTWINDOW, string.as_ptr(),
                                     microsecs as u32))
    }
    /// Presses the specified key sequence down.
    pub fn key_sequence_down(&self, sequence: &str, delay: Duration) -> OpResult {
        let microsecs = try_microsecs!(delay);
        let string = try!(CString::new(sequence));
        xdo!(sys::xdo_keysequence_down(self.handle, sys::CURRENTWINDOW, string.as_ptr(),
                                       microsecs as u32))
    }
}

impl Drop for XDo {
    fn drop(&mut self) {
        unsafe { sys::xdo_free(self.handle); }
    }
}
<|endoftext|>


<commit_before>extern crate rand;
pub mod parse;
pub mod eval;

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

    struct Data;
    impl Eval for Data {
        fn eval (&self, lookup: &str) -> Option<VarKind> {
            match lookup {
                "some_item" => {
                    Some(false.into())
                },
                "some_weight" => {
                    Some(4.0 .into())
                },
                "other_weight" => {
                    Some(5.0 .into())
                },
                "name" => {
                    Some("Io".into())
                }
                _ => 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(VarKind::String("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 ev = Evaluator::new(&block[0], &data);
        let (vars,_node) = ev.block();

        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 ev = Evaluator::new(&block[0], &data);
        let (_vars,node) = ev.block();

        assert_eq!(node, Some("store".to_string()));
    }

    #[test]
    fn parse_return_varkind() {
        let src = "root\n
    weight some_weight < other_weight\n
    if weight `some_weight \"hi `name\"\n
;";

        let block = Parser::parse_blocks(src);
        let data = Data;

        let ev = Evaluator::new(&block[0], &data);
        let (vars,_) = ev.block();

        assert_eq!(vars[0], 4.0 .into());
        assert_eq!(vars[1], "hi Io" .into());
    }
}
<commit_msg>tweak tests, cleanup<commit_after>extern crate rand;
pub mod parse;
pub mod eval;

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

    struct Data;
    impl Eval for Data {
        fn eval (&self, lookup: &str) -> Option<VarKind> {
            match lookup {
                "some_item" => {
                    Some(false.into())
                },
                "some_weight" => {
                    Some(4.0 .into())
                },
                "other_weight" => {
                    Some(5.0 .into())
                },
                "name" => {
                    Some("Io".into())
                }
                _ => 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_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".into(), 5.0 .into())),
                          SrcKind::Composite("some_comp".to_owned(),
                                             ExpectKind::Any,
                                             vec!["unequipped".to_owned(),"has_weight".to_owned()]),
                          SrcKind::If(ExpectKind::Ref("unequipped".to_owned()),
                                      vec!["you're looking for something?".into()],
                                      None),
                          SrcKind::If(ExpectKind::All,
                                      vec!["welcome, \nlook around".into()],
                                      None)]
            })];

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

    #[test]
    fn parse_qsym_block() {
        let src = "root\n
    if '!some_item \"you're looking for something?\"\n
;";
        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 ev = Evaluator::new(&block[0], &data);
        let (vars,_node) = ev.block();

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

    #[test]
    fn parse_compare_env_block() {
        let src = "root\n
    weight some_weight < other_weight\n
    if weight next store\n
;";
        let block = Parser::parse_blocks(src);
        let data = Data;

        let ev = Evaluator::new(&block[0], &data);
        let (_vars,node) = ev.block();

        assert_eq!(node, Some("store".to_string()));
    }

    #[test]
    fn parse_return_varkind() {
        let src = "root\n
    weight some_weight < other_weight\n
    if weight `some_weight \"hi `name\"\n
;";

        let block = Parser::parse_blocks(src);
        let data = Data;

        let ev = Evaluator::new(&block[0], &data);
        let (vars,_) = ev.block();

        assert_eq!(vars[0], 4.0 .into());
        assert_eq!(vars[1], "hi Io" .into());
    }
}
<|endoftext|>


<commit_before>#![feature(phase, tuple_indexing)]

extern crate libc;
extern crate native;
#[cfg(test)]
extern crate quickcheck;
#[cfg(test)]
#[phase(plugin)]
extern crate quickcheck_macros;

use native::io::file::FileDesc;
use std::io::{FileAccess, IoError, IoResult, OtherIoError, Read, ReadWrite, Write};

use termios::{FAILURE, Termios, SUCCESS};

mod termios;
#[cfg(test)]
mod socat;
#[cfg(test)]
mod test;

static O_NOCTTY: libc::c_int = 0x0100;

#[deriving(PartialEq)]
pub struct BlockingMode {
    /// The device will block until `bytes` are received
    pub bytes: u8,
    /// The device will block for at least `deciseconds` after each `read()` call
    pub deciseconds: u8,
}

pub struct SerialPort {
    fd: libc::c_int,
    file: FileDesc,
    termios: Termios,
}

impl SerialPort {
    /// Opens a serial `device` in "raw" mode
    pub fn open(device: &Path, access: FileAccess) -> IoResult<SerialPort> {
        let flags = match access {
            Read => libc::O_RDONLY,
            ReadWrite => libc::O_RDWR,
            Write => libc::O_WRONLY,
        } | O_NOCTTY;

        let fd = match device.with_c_str(|s| unsafe { libc::open(s, flags, 0) }) {
            FAILURE => return Err(IoError::last_error()),
            fd => fd,
        };

        let file = FileDesc::new(fd, true);

        let mut termios = Termios::new();

        match unsafe { termios::tcgetattr(fd, &mut termios) } {
            FAILURE => return Err(IoError::last_error()),
            SUCCESS => {},
            _ => unreachable!(),
        }

        unsafe { termios::cfmakeraw(&mut termios) };

        let sp = SerialPort { fd: fd, file: file, termios: termios };

        try!(sp.update());

        Ok(sp)
    }

    /// Returns the input and output baud rates
    pub fn baud_rate(&self) -> IoResult<(BaudRate, BaudRate)> {
        let termios = try!(self.fetch());

        let input = termios.c_ispeed;
        let input = match FromPrimitive::from_u32(input) {
            None => fail!("unrecognized BaudRate value: {}", input),
            Some(input) => input,
        };

        let output = termios.c_ospeed;
        let output = match FromPrimitive::from_u32(output) {
            None => fail!("unrecognized BaudRate value: {}", output),
            Some(output) => output,
        };

        Ok((input, output))
    }

    /// Returns the blocking mode used by the device
    pub fn blocking_mode(&self) -> IoResult<BlockingMode> {
        use termios::{VMIN, VTIME};

        Ok(BlockingMode {
            bytes: self.termios.c_cc[VMIN as uint],
            deciseconds: self.termios.c_cc[VTIME as uint],
        })
    }

    /// Returns the number of data bits used per character
    pub fn data_bits(&self) -> IoResult<DataBits> {
        use termios::CSIZE;

        let bits = try!(self.fetch()).c_cflag & CSIZE;

        match FromPrimitive::from_u32(bits) {
            None => fail!("unrecognized DataBits value: {}", bits),
            Some(bits) => Ok(bits),
        }
    }

    /// Returns the flow control used by the device
    pub fn flow_control(&self) -> IoResult<FlowControl> {
        use termios::{CRTSCTS, IXANY, IXOFF, IXON};

        let termios = try!(self.fetch());

        if termios.c_cflag & CRTSCTS != 0 {
            Ok(HardwareControl)
        } else if termios.c_iflag & (IXANY | IXOFF | IXON) == 0 {
            Ok(NoFlowControl)
        } else {
            Ok(SoftwareControl)
        }
    }

    /// Returns the bit parity used by the device
    pub fn parity(&self) -> IoResult<Parity> {
        use termios::{PARENB, PARODD};

        let termios = try!(self.fetch());

        match (termios.c_cflag & PARENB != 0, termios.c_cflag & PARODD != 0) {
            (true, true) => Ok(OddParity),
            (true, false) => Ok(EvenParity),
            (false, _) => Ok(NoParity),
        }
    }

    /// Changes the baud rate of the input/output or both directions
    pub fn set_baud_rate(&mut self, direction: Direction, rate: BaudRate) -> IoResult<()> {
        use termios::speed_t;

        match unsafe { match direction {
            BothDirections => termios::cfsetspeed(&mut self.termios, rate as speed_t),
            Input => termios::cfsetispeed(&mut self.termios, rate as speed_t),
            Output => termios::cfsetospeed(&mut self.termios, rate as speed_t),
        } } {
            FAILURE => Err(IoError::last_error()),
            SUCCESS => self.update(),
            _ => unreachable!(),
        }
    }

    /// Changes the blocking mode used by the device
    pub fn set_blocking_mode(&mut self, mode: BlockingMode) -> IoResult<()> {
        use termios::{VMIN, VTIME};

        self.termios.c_cc[VMIN as uint] = mode.bytes;
        self.termios.c_cc[VTIME as uint] = mode.deciseconds;

        self.update()
    }

    /// Changes the number of data bits per character
    pub fn set_data_bits(&mut self, bits: DataBits) -> IoResult<()> {
        use termios::CSIZE;

        self.termios.c_cflag &= !CSIZE;
        self.termios.c_cflag |= bits as u32;

        self.update()
    }

    /// Changes the flow control used by the device
    pub fn set_flow_control(&mut self, flow: FlowControl) -> IoResult<()> {
        use termios::{CRTSCTS, IXANY, IXOFF, IXON};

        match flow {
            HardwareControl => {
                self.termios.c_cflag |= CRTSCTS;
                self.termios.c_iflag &= !(IXANY | IXOFF | IXON);
            } NoFlowControl => {
                self.termios.c_cflag &= !CRTSCTS;
                self.termios.c_iflag &= !(IXANY | IXOFF | IXON);
            } SoftwareControl => {
                self.termios.c_cflag &= !CRTSCTS;
                self.termios.c_iflag |= IXANY | IXOFF | IXON;
            }
        }

        self.update()
    }

    /// Changes the bit parity used by the device
    pub fn set_parity(&mut self, parity: Parity) -> IoResult<()> {
        use termios::{PARENB, PARODD};

        match parity {
            EvenParity => {
                self.termios.c_cflag |= PARENB;
                self.termios.c_cflag &= !PARODD;
            },
            NoParity => self.termios.c_cflag &= !PARENB,
            OddParity => self.termios.c_cflag |= PARENB | PARODD,
        }

        self.update()
    }

    /// Changes the number of stop bits per character
    pub fn set_stop_bits(&mut self, bits: StopBits) -> IoResult<()> {
        use termios::CSTOPB;

        match bits {
            Stop1 => self.termios.c_cflag &= !CSTOPB,
            Stop2 => self.termios.c_cflag |= CSTOPB,
        }

        self.update()
    }

    /// Returns the number of stop bits per character
    pub fn stop_bits(&self) -> IoResult<StopBits> {
        use termios::CSTOPB;

        if try!(self.fetch()).c_cflag & CSTOPB == 0 {
            Ok(Stop1)
        } else {
            Ok(Stop2)
        }
    }

    /// Fetches the current state of the termios structure
    fn fetch(&self) -> IoResult<Termios> {
        let mut termios = Termios::new();

        match unsafe { termios::tcgetattr(self.fd, &mut termios) } {
            FAILURE => Err(IoError::last_error()),
            SUCCESS => Ok(termios),
            _ => unreachable!(),
        }
    }

    /// Updates the underlying termios structure
    fn update(&self) -> IoResult<()> {
        use termios::TCSANOW;

        match unsafe { termios::tcsetattr(self.fd, TCSANOW, &self.termios) } {
            FAILURE => Err(IoError::last_error()),
            SUCCESS => Ok(()),
            _ => unreachable!(),
        }
    }
}

impl Reader for SerialPort {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match self.file.inner_read(buf) {
            Err(err) => Err(IoError {
                // FIXME How to convert rtio::IoError to io::IoError?
                desc: "",
                detail: err.detail,
                kind: OtherIoError,
            }),
            Ok(ret) => Ok(ret),
        }
    }
}

impl Writer for SerialPort {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match self.file.inner_write(buf) {
            Err(err) => Err(IoError {
                // FIXME How to convert rtio::IoError to io::IoError?
                desc: "",
                detail: err.detail,
                kind: OtherIoError,
            }),
            Ok(_) => Ok(()),
        }
    }
}

#[deriving(FromPrimitive, PartialEq, Show)]
pub enum BaudRate {
    B0 = 0x00,
    B50 = 0x01,
    B75 = 0x02,
    B110 = 0x03,
    B134 = 0x04,
    B150 = 0x05,
    B200 = 0x06,
    B300 = 0x07,
    B600 = 0x08,
    B1K2 = 0x09,
    B1K8 = 0x0A,
    B2K4 = 0x0B,
    B4K8 = 0x0C,
    B9K6 = 0x0D,
    B19K2 = 0x0E,
    B38K4 = 0x0F,
    B57K6 = 0x1001,
    B115K2 = 0x1002,
    B230K4 = 0x1003,
    B460K8 = 0x1004,
    B500K = 0x1005,
    B576K = 0x1006,
    B921K6 = 0x1007,
    B1M = 0x1008,
    B1M152 = 0x1009,
    B1M5 = 0x100A,
    B2M = 0x100B,
    B2M5 = 0x100C,
    B3M = 0x100D,
    B3M5 = 0x100E,
    B4M = 0x100F,
}

#[deriving(FromPrimitive, PartialEq, Show)]
pub enum DataBits {
    Data5 = 0x00,
    Data6 = 0x10,
    Data7 = 0x20,
    Data8 = 0x30,
}

pub enum Direction {
    BothDirections,
    Input,
    Output,
}

#[deriving(FromPrimitive, PartialEq, Show)]
pub enum FlowControl {
    HardwareControl,
    NoFlowControl,
    SoftwareControl,
}

#[deriving(FromPrimitive, PartialEq, Show)]
pub enum Parity {
    EvenParity,
    NoParity,
    OddParity,
}

#[deriving(FromPrimitive, PartialEq, Show)]
#[repr(u32)]
pub enum StopBits {
    Stop1,
    Stop2,
}
<commit_msg>Losslessly convert from `rtio::IoError` to `io::IoError`<commit_after>#![feature(phase, tuple_indexing)]

extern crate libc;
extern crate native;
#[cfg(test)]
extern crate quickcheck;
#[cfg(test)]
#[phase(plugin)]
extern crate quickcheck_macros;

use native::io::file::FileDesc;
use std::io::{FileAccess, IoError, IoResult, Read, ReadWrite, Write};

use termios::{FAILURE, Termios, SUCCESS};

mod termios;
#[cfg(test)]
mod socat;
#[cfg(test)]
mod test;

static O_NOCTTY: libc::c_int = 0x0100;

#[deriving(PartialEq)]
pub struct BlockingMode {
    /// The device will block until `bytes` are received
    pub bytes: u8,
    /// The device will block for at least `deciseconds` after each `read()` call
    pub deciseconds: u8,
}

pub struct SerialPort {
    fd: libc::c_int,
    file: FileDesc,
    termios: Termios,
}

impl SerialPort {
    /// Opens a serial `device` in "raw" mode
    pub fn open(device: &Path, access: FileAccess) -> IoResult<SerialPort> {
        let flags = match access {
            Read => libc::O_RDONLY,
            ReadWrite => libc::O_RDWR,
            Write => libc::O_WRONLY,
        } | O_NOCTTY;

        let fd = match device.with_c_str(|s| unsafe { libc::open(s, flags, 0) }) {
            FAILURE => return Err(IoError::last_error()),
            fd => fd,
        };

        let file = FileDesc::new(fd, true);

        let mut termios = Termios::new();

        match unsafe { termios::tcgetattr(fd, &mut termios) } {
            FAILURE => return Err(IoError::last_error()),
            SUCCESS => {},
            _ => unreachable!(),
        }

        unsafe { termios::cfmakeraw(&mut termios) };

        let sp = SerialPort { fd: fd, file: file, termios: termios };

        try!(sp.update());

        Ok(sp)
    }

    /// Returns the input and output baud rates
    pub fn baud_rate(&self) -> IoResult<(BaudRate, BaudRate)> {
        let termios = try!(self.fetch());

        let input = termios.c_ispeed;
        let input = match FromPrimitive::from_u32(input) {
            None => fail!("unrecognized BaudRate value: {}", input),
            Some(input) => input,
        };

        let output = termios.c_ospeed;
        let output = match FromPrimitive::from_u32(output) {
            None => fail!("unrecognized BaudRate value: {}", output),
            Some(output) => output,
        };

        Ok((input, output))
    }

    /// Returns the blocking mode used by the device
    pub fn blocking_mode(&self) -> IoResult<BlockingMode> {
        use termios::{VMIN, VTIME};

        Ok(BlockingMode {
            bytes: self.termios.c_cc[VMIN as uint],
            deciseconds: self.termios.c_cc[VTIME as uint],
        })
    }

    /// Returns the number of data bits used per character
    pub fn data_bits(&self) -> IoResult<DataBits> {
        use termios::CSIZE;

        let bits = try!(self.fetch()).c_cflag & CSIZE;

        match FromPrimitive::from_u32(bits) {
            None => fail!("unrecognized DataBits value: {}", bits),
            Some(bits) => Ok(bits),
        }
    }

    /// Returns the flow control used by the device
    pub fn flow_control(&self) -> IoResult<FlowControl> {
        use termios::{CRTSCTS, IXANY, IXOFF, IXON};

        let termios = try!(self.fetch());

        if termios.c_cflag & CRTSCTS != 0 {
            Ok(HardwareControl)
        } else if termios.c_iflag & (IXANY | IXOFF | IXON) == 0 {
            Ok(NoFlowControl)
        } else {
            Ok(SoftwareControl)
        }
    }

    /// Returns the bit parity used by the device
    pub fn parity(&self) -> IoResult<Parity> {
        use termios::{PARENB, PARODD};

        let termios = try!(self.fetch());

        match (termios.c_cflag & PARENB != 0, termios.c_cflag & PARODD != 0) {
            (true, true) => Ok(OddParity),
            (true, false) => Ok(EvenParity),
            (false, _) => Ok(NoParity),
        }
    }

    /// Changes the baud rate of the input/output or both directions
    pub fn set_baud_rate(&mut self, direction: Direction, rate: BaudRate) -> IoResult<()> {
        use termios::speed_t;

        match unsafe { match direction {
            BothDirections => termios::cfsetspeed(&mut self.termios, rate as speed_t),
            Input => termios::cfsetispeed(&mut self.termios, rate as speed_t),
            Output => termios::cfsetospeed(&mut self.termios, rate as speed_t),
        } } {
            FAILURE => Err(IoError::last_error()),
            SUCCESS => self.update(),
            _ => unreachable!(),
        }
    }

    /// Changes the blocking mode used by the device
    pub fn set_blocking_mode(&mut self, mode: BlockingMode) -> IoResult<()> {
        use termios::{VMIN, VTIME};

        self.termios.c_cc[VMIN as uint] = mode.bytes;
        self.termios.c_cc[VTIME as uint] = mode.deciseconds;

        self.update()
    }

    /// Changes the number of data bits per character
    pub fn set_data_bits(&mut self, bits: DataBits) -> IoResult<()> {
        use termios::CSIZE;

        self.termios.c_cflag &= !CSIZE;
        self.termios.c_cflag |= bits as u32;

        self.update()
    }

    /// Changes the flow control used by the device
    pub fn set_flow_control(&mut self, flow: FlowControl) -> IoResult<()> {
        use termios::{CRTSCTS, IXANY, IXOFF, IXON};

        match flow {
            HardwareControl => {
                self.termios.c_cflag |= CRTSCTS;
                self.termios.c_iflag &= !(IXANY | IXOFF | IXON);
            } NoFlowControl => {
                self.termios.c_cflag &= !CRTSCTS;
                self.termios.c_iflag &= !(IXANY | IXOFF | IXON);
            } SoftwareControl => {
                self.termios.c_cflag &= !CRTSCTS;
                self.termios.c_iflag |= IXANY | IXOFF | IXON;
            }
        }

        self.update()
    }

    /// Changes the bit parity used by the device
    pub fn set_parity(&mut self, parity: Parity) -> IoResult<()> {
        use termios::{PARENB, PARODD};

        match parity {
            EvenParity => {
                self.termios.c_cflag |= PARENB;
                self.termios.c_cflag &= !PARODD;
            },
            NoParity => self.termios.c_cflag &= !PARENB,
            OddParity => self.termios.c_cflag |= PARENB | PARODD,
        }

        self.update()
    }

    /// Changes the number of stop bits per character
    pub fn set_stop_bits(&mut self, bits: StopBits) -> IoResult<()> {
        use termios::CSTOPB;

        match bits {
            Stop1 => self.termios.c_cflag &= !CSTOPB,
            Stop2 => self.termios.c_cflag |= CSTOPB,
        }

        self.update()
    }

    /// Returns the number of stop bits per character
    pub fn stop_bits(&self) -> IoResult<StopBits> {
        use termios::CSTOPB;

        if try!(self.fetch()).c_cflag & CSTOPB == 0 {
            Ok(Stop1)
        } else {
            Ok(Stop2)
        }
    }

    /// Fetches the current state of the termios structure
    fn fetch(&self) -> IoResult<Termios> {
        let mut termios = Termios::new();

        match unsafe { termios::tcgetattr(self.fd, &mut termios) } {
            FAILURE => Err(IoError::last_error()),
            SUCCESS => Ok(termios),
            _ => unreachable!(),
        }
    }

    /// Updates the underlying termios structure
    fn update(&self) -> IoResult<()> {
        use termios::TCSANOW;

        match unsafe { termios::tcsetattr(self.fd, TCSANOW, &self.termios) } {
            FAILURE => Err(IoError::last_error()),
            SUCCESS => Ok(()),
            _ => unreachable!(),
        }
    }
}

impl Reader for SerialPort {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match self.file.inner_read(buf) {
            Err(err) => Err(IoError::from_errno(err.code, true)),
            Ok(ret) => Ok(ret),
        }
    }
}

impl Writer for SerialPort {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match self.file.inner_write(buf) {
            Err(err) => Err(IoError::from_errno(err.code, true)),
            Ok(_) => Ok(()),
        }
    }
}

#[deriving(FromPrimitive, PartialEq, Show)]
pub enum BaudRate {
    B0 = 0x00,
    B50 = 0x01,
    B75 = 0x02,
    B110 = 0x03,
    B134 = 0x04,
    B150 = 0x05,
    B200 = 0x06,
    B300 = 0x07,
    B600 = 0x08,
    B1K2 = 0x09,
    B1K8 = 0x0A,
    B2K4 = 0x0B,
    B4K8 = 0x0C,
    B9K6 = 0x0D,
    B19K2 = 0x0E,
    B38K4 = 0x0F,
    B57K6 = 0x1001,
    B115K2 = 0x1002,
    B230K4 = 0x1003,
    B460K8 = 0x1004,
    B500K = 0x1005,
    B576K = 0x1006,
    B921K6 = 0x1007,
    B1M = 0x1008,
    B1M152 = 0x1009,
    B1M5 = 0x100A,
    B2M = 0x100B,
    B2M5 = 0x100C,
    B3M = 0x100D,
    B3M5 = 0x100E,
    B4M = 0x100F,
}

#[deriving(FromPrimitive, PartialEq, Show)]
pub enum DataBits {
    Data5 = 0x00,
    Data6 = 0x10,
    Data7 = 0x20,
    Data8 = 0x30,
}

pub enum Direction {
    BothDirections,
    Input,
    Output,
}

#[deriving(FromPrimitive, PartialEq, Show)]
pub enum FlowControl {
    HardwareControl,
    NoFlowControl,
    SoftwareControl,
}

#[deriving(FromPrimitive, PartialEq, Show)]
pub enum Parity {
    EvenParity,
    NoParity,
    OddParity,
}

#[deriving(FromPrimitive, PartialEq, Show)]
#[repr(u32)]
pub enum StopBits {
    Stop1,
    Stop2,
}
<|endoftext|>


<commit_before>#![feature(globs)]

extern crate semver;
extern crate conduit;

use std::io::net::ip::{IpAddr, Ipv4Addr};
use std::io::MemReader;
use std::any::Any;
use std::collections::HashMap;
use std::fmt::Show;

use conduit::{Method, Scheme, Host, Extensions, Headers};

pub struct MockRequest {
    path: String,
    method: Method,
    query_string: Option<String>,
    string_body: Option<String>,
    build_headers: HashMap<String, String>,
    headers: MockHeaders,
    extensions: HashMap<&'static str, Box<Any>>,
    reader: Option<MemReader>
}

impl MockRequest {
    pub fn new(method: Method, path: &'static str) -> MockRequest {
        let headers = HashMap::new();

        MockRequest {
            path: path.to_string(),
            extensions: HashMap::new(),
            query_string: None,
            string_body: None,
            build_headers: headers,
            headers: MockHeaders { headers: HashMap::new() },
            method: method,
            reader: None
        }
    }

    pub fn with_query<'a, S: Show>(&'a mut self, string: S) -> &'a mut MockRequest {
        self.query_string = Some(string.to_string());
        self
    }

    pub fn with_body<'a, S: Show>(&'a mut self, string: S) -> &'a mut MockRequest {
        self.string_body = Some(string.to_string());
        self
    }

    pub fn header<'a, S1: Show, S2: Show>(&'a mut self, name: S1, value: S2) -> &'a mut MockRequest {
        self.build_headers.insert(name.to_string(), value.to_string());
        let headers = MockHeaders { headers: self.build_headers.clone() };
        self.headers = headers;

        self
    }
}

pub struct MockHeaders {
    headers: HashMap<String, String>
}

impl Headers for MockHeaders {
    fn find<'a>(&'a self, key: &str) -> Option<Vec<&'a str>> {
        self.headers.find_equiv(&key).map(|v| vec!(v.as_slice()))
    }

    fn has(&self, key: &str) -> bool {
        self.headers.contains_key_equiv(&key)
    }

    fn iter<'a>(&'a self) -> conduit::HeaderEntries<'a> {
        box self.headers.iter().map(|(k,v)| (k.as_slice(), vec!(v.as_slice()))) as conduit::HeaderEntries<'a>
    }
}

impl<'a> conduit::Request for MockRequest {
    fn http_version(&self) -> semver::Version {
        semver::parse("1.1.0").unwrap()
    }

    fn conduit_version(&self) -> semver::Version {
        semver::parse("0.1.0").unwrap()
    }

    fn method(&self) -> Method { self.method }
    fn scheme(&self) -> Scheme { conduit::Http }
    fn host<'a>(&'a self) -> Host<'a> { conduit::HostName("example.com") }
    fn virtual_root<'a>(&'a self) -> Option<&'a str> { None }

    fn path<'a>(&'a self) -> &'a str {
        self.path.as_slice()
    }

    fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.query_string.as_ref().map(|s| s.as_slice())
    }

    fn remote_ip(&self) -> IpAddr {
        Ipv4Addr(127, 0, 0, 1)
    }

    fn content_length(&self) -> Option<uint> {
        self.string_body.as_ref().map(|b| b.len())
    }

    fn headers<'a>(&'a self) -> &'a Headers {
        &self.headers as &Headers
    }

    fn body<'a>(&'a mut self) -> &'a mut Reader {
        let body = self.string_body.clone().unwrap_or("".to_string());
        self.reader = Some(MemReader::new(Vec::from_slice(body.as_bytes())));

        self.reader.get_mut_ref() as &mut Reader
    }

    fn extensions<'a>(&'a self) -> &'a Extensions {
        &self.extensions
    }
    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
        &mut self.extensions
    }
}

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

    use std::io::net::ip::Ipv4Addr;

    use conduit::Request;

    #[test]
    fn simple_request_test() {
        let mut req = MockRequest::new(conduit::Get, "/");

        assert_eq!(req.http_version(), semver::parse("1.1.0").unwrap());
        assert_eq!(req.conduit_version(), semver::parse("0.1.0").unwrap());
        assert_eq!(req.method(), conduit::Get);
        assert_eq!(req.scheme(), conduit::Http);
        assert_eq!(req.host(), conduit::HostName("example.com"));
        assert_eq!(req.virtual_root(), None);
        assert_eq!(req.path(), "/");
        assert_eq!(req.query_string(), None);
        assert_eq!(req.remote_ip(), Ipv4Addr(127, 0, 0, 1));
        assert_eq!(req.content_length(), None);
        assert_eq!(req.headers().iter().count(), 0);
        assert_eq!(req.body().read_to_string().ok().expect("No body"),
                   "".to_string());
    }

    #[test]
    fn request_body_test() {
        let mut req = MockRequest::new(conduit::Post, "/articles");
        req.with_body("Hello world");

        assert_eq!(req.method(), conduit::Post);
        assert_eq!(req.path(), "/articles");
        assert_eq!(req.body().read_to_string().ok().expect("No body"),
                   "Hello world".to_string());
        assert_eq!(req.content_length(), Some(11));
    }

    #[test]
    fn request_query_test() {
        let mut req = MockRequest::new(conduit::Post, "/articles");
        req.with_query("foo=bar");

        assert_eq!(req.query_string().expect("No query string"), "foo=bar");
    }

    #[test]
    fn request_headers() {
        let mut req = MockRequest::new(conduit::Post, "/articles");
        req.header("User-Agent", "lulz");
        req.header("DNT", "1");

        assert_eq!(req.headers().iter().count(), 2);
        assert_eq!(req.headers().find("User-Agent").unwrap(), vec!("lulz"));
        assert_eq!(req.headers().find("DNT").unwrap(), vec!("1"));
    }
}
<commit_msg>Update to conduit master<commit_after>#![feature(globs)]

extern crate semver;
extern crate conduit;

use std::io::net::ip::{IpAddr, Ipv4Addr};
use std::io::MemReader;
use std::collections::HashMap;
use std::fmt::Show;

use conduit::{Method, Scheme, Host, Extensions, Headers, TypeMap};

pub struct MockRequest {
    path: String,
    method: Method,
    query_string: Option<String>,
    string_body: Option<String>,
    build_headers: HashMap<String, String>,
    headers: MockHeaders,
    extensions: TypeMap,
    reader: Option<MemReader>
}

impl MockRequest {
    pub fn new(method: Method, path: &'static str) -> MockRequest {
        let headers = HashMap::new();

        MockRequest {
            path: path.to_string(),
            extensions: TypeMap::new(),
            query_string: None,
            string_body: None,
            build_headers: headers,
            headers: MockHeaders { headers: HashMap::new() },
            method: method,
            reader: None
        }
    }

    pub fn with_query<'a, S: Show>(&'a mut self, string: S) -> &'a mut MockRequest {
        self.query_string = Some(string.to_string());
        self
    }

    pub fn with_body<'a, S: Show>(&'a mut self, string: S) -> &'a mut MockRequest {
        self.string_body = Some(string.to_string());
        self
    }

    pub fn header<'a, S1: Show, S2: Show>(&'a mut self, name: S1, value: S2) -> &'a mut MockRequest {
        self.build_headers.insert(name.to_string(), value.to_string());
        let headers = MockHeaders { headers: self.build_headers.clone() };
        self.headers = headers;

        self
    }
}

pub struct MockHeaders {
    headers: HashMap<String, String>
}

impl Headers for MockHeaders {
    fn find<'a>(&'a self, key: &str) -> Option<Vec<&'a str>> {
        self.headers.find_equiv(&key).map(|v| vec!(v.as_slice()))
    }

    fn has(&self, key: &str) -> bool {
        self.headers.contains_key_equiv(&key)
    }

    fn iter<'a>(&'a self) -> conduit::HeaderEntries<'a> {
        box self.headers.iter().map(|(k,v)| (k.as_slice(), vec!(v.as_slice()))) as conduit::HeaderEntries<'a>
    }
}

impl<'a> conduit::Request for MockRequest {
    fn http_version(&self) -> semver::Version {
        semver::parse("1.1.0").unwrap()
    }

    fn conduit_version(&self) -> semver::Version {
        semver::parse("0.1.0").unwrap()
    }

    fn method(&self) -> Method { self.method }
    fn scheme(&self) -> Scheme { conduit::Http }
    fn host<'a>(&'a self) -> Host<'a> { conduit::HostName("example.com") }
    fn virtual_root<'a>(&'a self) -> Option<&'a str> { None }

    fn path<'a>(&'a self) -> &'a str {
        self.path.as_slice()
    }

    fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.query_string.as_ref().map(|s| s.as_slice())
    }

    fn remote_ip(&self) -> IpAddr {
        Ipv4Addr(127, 0, 0, 1)
    }

    fn content_length(&self) -> Option<uint> {
        self.string_body.as_ref().map(|b| b.len())
    }

    fn headers<'a>(&'a self) -> &'a Headers {
        &self.headers as &Headers
    }

    fn body<'a>(&'a mut self) -> &'a mut Reader {
        let body = self.string_body.clone().unwrap_or("".to_string());
        self.reader = Some(MemReader::new(Vec::from_slice(body.as_bytes())));

        self.reader.get_mut_ref() as &mut Reader
    }

    fn extensions<'a>(&'a self) -> &'a Extensions {
        &self.extensions
    }
    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
        &mut self.extensions
    }
}

#[cfg(test)]
mod tests {
    use super::MockRequest;
    use conduit;
    use semver;

    use std::io::net::ip::Ipv4Addr;

    use conduit::Request;

    #[test]
    fn simple_request_test() {
        let mut req = MockRequest::new(conduit::Get, "/");

        assert_eq!(req.http_version(), semver::parse("1.1.0").unwrap());
        assert_eq!(req.conduit_version(), semver::parse("0.1.0").unwrap());
        assert_eq!(req.method(), conduit::Get);
        assert_eq!(req.scheme(), conduit::Http);
        assert_eq!(req.host(), conduit::HostName("example.com"));
        assert_eq!(req.virtual_root(), None);
        assert_eq!(req.path(), "/");
        assert_eq!(req.query_string(), None);
        assert_eq!(req.remote_ip(), Ipv4Addr(127, 0, 0, 1));
        assert_eq!(req.content_length(), None);
        assert_eq!(req.headers().iter().count(), 0);
        assert_eq!(req.body().read_to_string().ok().expect("No body"),
                   "".to_string());
    }

    #[test]
    fn request_body_test() {
        let mut req = MockRequest::new(conduit::Post, "/articles");
        req.with_body("Hello world");

        assert_eq!(req.method(), conduit::Post);
        assert_eq!(req.path(), "/articles");
        assert_eq!(req.body().read_to_string().ok().expect("No body"),
                   "Hello world".to_string());
        assert_eq!(req.content_length(), Some(11));
    }

    #[test]
    fn request_query_test() {
        let mut req = MockRequest::new(conduit::Post, "/articles");
        req.with_query("foo=bar");

        assert_eq!(req.query_string().expect("No query string"), "foo=bar");
    }

    #[test]
    fn request_headers() {
        let mut req = MockRequest::new(conduit::Post, "/articles");
        req.header("User-Agent", "lulz");
        req.header("DNT", "1");

        assert_eq!(req.headers().iter().count(), 2);
        assert_eq!(req.headers().find("User-Agent").unwrap(), vec!("lulz"));
        assert_eq!(req.headers().find("DNT").unwrap(), vec!("1"));
    }
}
<|endoftext|>


<commit_before>//! Simple resampling library in pure Rust.
//!
//! # Examples
//!
//! ```
//! use resize::Pixel::RGB24;
//! use resize::Type::Lanczos3;
//!
//! // Downscale by 2x.
//! let (w1, h1) = (640, 480);
//! let (w2, h2) = (320, 240);
//! // Don't forget to fill `src` with image data (RGB24).
//! let src = vec![0;w1*h1*3];
//! // Destination buffer. Must be mutable.
//! let mut dst = vec![0;w2*h2*3];
//! // Create reusable instance.
//! let mut resizer = resize::new(w1, h1, w2, h2, RGB24, Lanczos3);
//! // Do resize without heap allocations.
//! // Might be executed multiple times for different `src` or `dst`.
//! resizer.resize(&src, &mut dst);
//! ```
// Current implementation is based on:
// * https://github.com/sekrit-twc/zimg/tree/master/src/zimg/resize
// * https://github.com/PistonDevelopers/image/blob/master/src/imageops/sample.rs
#![deny(missing_docs)]

use std::f32;

/// Resizing type to use.
pub enum Type {
    /// Point resizing.
    Point,
    /// Triangle (bilinear) resizing.
    Triangle,
    /// Catmull-Rom (bicubic) resizing.
    Catrom,
    /// Resize using Mitchell-Netravali filter.
    Mitchell,
    /// Resize using Sinc-windowed Sinc with radius of 3.
    Lanczos3,
    /// Resize with custom filter.
    Custom(Filter),
}

/// Resampling filter.
pub struct Filter {
    kernel: Box<Fn(f32) -> f32>,
    support: f32,
}

impl Filter {
    /// Create a new filter.
    ///
    /// # Examples
    ///
    /// ```
    /// use resize::Filter;
    /// fn kernel(x: f32) -> f32 { f32::max(1.0 - x.abs(), 0.0) }
    /// let filter = Filter::new(Box::new(kernel), 1.0);
    /// ```
    pub fn new(kernel: Box<Fn(f32) -> f32>, support: f32) -> Filter {
        Filter {kernel: kernel, support: support}
    }

    /// Helper to create Cubic filter with custom B and C parameters.
    pub fn new_cubic(b: f32, c: f32) -> Filter {
        Filter::new(Box::new(move |x| cubic_bc(b, c, x)), 2.0)
    }

    /// Helper to create Lanczos filter with custom radius.
    pub fn new_lanczos(radius: f32) -> Filter {
        Filter::new(Box::new(move |x| lanczos(radius, x)), radius)
    }
}

#[inline]
fn point_kernel(_: f32) -> f32 {
    1.0
}

#[inline]
fn triangle_kernel(x: f32) -> f32 {
    f32::max(1.0 - x.abs(), 0.0)
}

// Taken from
// https://github.com/PistonDevelopers/image/blob/2921cd7/src/imageops/sample.rs#L68
// TODO(Kagami): Could be optimized for known B and C, see e.g.
// https://github.com/sekrit-twc/zimg/blob/1a606c0/src/zimg/resize/filter.cpp#L149
#[inline]
fn cubic_bc(b: f32, c: f32, x: f32) -> f32 {
    let a = x.abs();
    let k = if a < 1.0 {
        (12.0 - 9.0 * b - 6.0 * c) * a.powi(3) +
        (-18.0 + 12.0 * b + 6.0 * c) * a.powi(2) +
        (6.0 - 2.0 * b)
    } else if a < 2.0 {
        (-b - 6.0 * c) * a.powi(3) +
        (6.0 * b + 30.0 * c) * a.powi(2) +
        (-12.0 * b - 48.0 * c) * a +
        (8.0 * b + 24.0 * c)
    } else {
        0.0
    };
    k / 6.0
}

#[inline]
fn sinc(x: f32) -> f32 {
    if x == 0.0 {
        1.0
    } else {
        let a = x * f32::consts::PI;
        a.sin() / a
    }
}

#[inline]
fn lanczos(taps: f32, x: f32) -> f32 {
    if x.abs() < taps {
        sinc(x) * sinc(x / taps)
    } else {
        0.0
    }
}

/// Supported pixel formats.
// TODO(Kagami): >8-bit formats.
#[derive(Debug, Clone, Copy)]
pub enum Pixel {
    /// Grayscale, 8-bit.
    Gray8,
    /// RGB, 8-bit per component.
    RGB24,
    /// RGBA, 8-bit per component.
    RGBA,
}

impl Pixel {
    /// Size of one pixel in that format in bytes.
    #[inline]
    pub fn get_size(&self) -> usize {
        match *self {
            Pixel::Gray8 => 1,
            Pixel::RGB24 => 3,
            Pixel::RGBA => 4,
        }
    }

    /// Return number of components of that format.
    #[inline]
    pub fn get_ncomponents(&self) -> usize {
        match *self {
            Pixel::Gray8 => 1,
            Pixel::RGB24 => 3,
            Pixel::RGBA => 4,
        }
    }
}

/// Resampler with preallocated buffers and coeffecients for the given
/// dimensions and filter type.
#[derive(Debug)]
pub struct Resizer {
    // Source/target dimensions.
    w1: usize,
    h1: usize,
    w2: usize,
    h2: usize,
    pix_fmt: Pixel,
    // Temporary/preallocated stuff.
    tmp: Vec<f32>,
    accum: Vec<f32>,
    coeffs_w: Vec<CoeffsLine>,
    coeffs_h: Vec<CoeffsLine>,
}

#[derive(Debug)]
struct CoeffsLine {
    left: usize,
    data: Vec<f32>,
}

impl Resizer {
    /// Create a new resizer instance.
    pub fn new(w1: usize, h1: usize, w2: usize, h2: usize, p: Pixel, t: Type) -> Resizer {
        let filter = match t {
            Type::Point => Filter::new(Box::new(point_kernel), 0.0),
            Type::Triangle => Filter::new(Box::new(triangle_kernel), 1.0),
            Type::Catrom => Filter::new_cubic(0.0, 0.5),
            Type::Mitchell => Filter::new_cubic(1.0/3.0, 1.0/3.0),
            Type::Lanczos3 => Filter::new_lanczos(3.0),
            Type::Custom(f) => f,
        };
        Resizer {
            w1: w1,
            h1: h1,
            w2: w2,
            h2: h2,
            pix_fmt: p,
            tmp: vec![0.0;w1*h2*p.get_size()],
            accum: vec![0.0;p.get_ncomponents()],
            // TODO(Kagami): Use same coeffs if w1 = h1 = w2 = h2?
            coeffs_w: Self::calc_coeffs(w1, w2, &filter),
            coeffs_h: Self::calc_coeffs(h1, h2, &filter),
        }
    }

    fn calc_coeffs(s1: usize, s2: usize, f: &Filter) -> Vec<CoeffsLine> {
        let ratio = s1 as f32 / s2 as f32;
        // Scale the filter when downsampling.
        let filter_scale = if ratio > 1.0 { ratio } else { 1.0 };
        let filter_radius = (f.support * filter_scale).ceil();
        let mut coeffs = Vec::with_capacity(s2);
        for x2 in 0..s2 {
            let x1 = (x2 as f32 + 0.5) * ratio - 0.5;
            let left = (x1 - filter_radius).ceil() as isize;
            let left = Self::clamp(left, 0, s1 as isize - 1) as usize;
            let right = (x1 + filter_radius).floor() as isize;
            let right = Self::clamp(right, 0, s1 as isize - 1) as usize;
            let mut data = Vec::with_capacity(right - left + 1);
            let mut sum = 0.0;
            for i in left..right+1 {
                sum += (f.kernel)((i as f32 - x1) / filter_scale);
            }
            for i in left..right+1 {
                let v = (f.kernel)((i as f32 - x1) / filter_scale);
                data.push(v / sum);
            }
            coeffs.push(CoeffsLine {left: left, data: data});
        }
        coeffs
    }

    #[inline]
    fn clamp<N: PartialOrd>(v: N, min: N, max: N) -> N {
        if v <= min {
            min
        } else if v >= max {
            max
        } else {
            v
        }
    }

    #[inline]
    fn pack_u8(mut v: f32) -> u8 {
        v = v.round();
        v = f32::min(f32::max(v, 0.0), 255.0);
        v as u8
    }

    #[inline]
    fn clear_accum(&mut self) {
        for v in self.accum.iter_mut() {
            *v = 0.0;
        }
    }

    // Resample W1xH1 to W1xH2.
    fn sample_rows(&mut self, src: &[u8]) {
        let ncomp = self.pix_fmt.get_ncomponents();
        let mut offset = 0;
        for x1 in 0..self.w1 {
            for y2 in 0..self.h2 {
                self.clear_accum();
                let ref line = self.coeffs_h[y2];
                for (i, coeff) in line.data.iter().enumerate() {
                    let y0 = line.left + i;
                    let base = (y0 * self.w1 + x1) * ncomp;
                    for n in 0..ncomp {
                        let p = src[base + n] as f32;
                        self.accum[n] += p * coeff;
                    }
                }
                for &v in &self.accum {
                    self.tmp[offset] = v;
                    offset += 1;
                }
            }
        }
    }

    // Resample W1xH2 to W2xH2.
    fn sample_cols(&mut self, dst: &mut [u8]) {
        let ncomp = self.pix_fmt.get_ncomponents();
        let mut offset = 0;
        for y2 in 0..self.h2 {
            for x2 in 0..self.w2 {
                self.clear_accum();
                let ref line = self.coeffs_w[x2];
                for (i, coeff) in line.data.iter().enumerate() {
                    let x0 = line.left + i;
                    let base = (x0 * self.h2 + y2) * ncomp;
                    for n in 0..ncomp {
                        let p = self.tmp[base + n];
                        self.accum[n] += p * coeff;
                    }
                }
                for &v in &self.accum {
                    dst[offset] = Self::pack_u8(v);
                    offset += 1;
                }
            }
        }
    }

    /// Resize `src` image data into `dst`.
    pub fn resize(&mut self, src: &[u8], dst: &mut [u8]) {
        // TODO(Kagami):
        // * Multi-thread
        // * Bound checkings
        // * SIMD
        assert_eq!(src.len(), self.w1 * self.h1 * self.pix_fmt.get_size());
        assert_eq!(dst.len(), self.w2 * self.h2 * self.pix_fmt.get_size());
        self.sample_rows(src);
        self.sample_cols(dst)
    }
}

/// Create a new resizer instance. Alias for `Resizer::new`.
pub fn new(w1: usize, h1: usize, w2: usize, h2: usize, p: Pixel, t: Type) -> Resizer {
    Resizer::new(w1, h1, w2, h2, p, t)
}

/// Resize image data to the new dimension in a single step.
///
/// **NOTE:** If you need to resize to the same dimension multiple times,
/// consider creating an resizer instance since it's faster.
pub fn resize(
    w1: usize, h1: usize, w2: usize, h2: usize,
    p: Pixel, t: Type,
    src: &[u8], dst: &mut [u8],
) {
    Resizer::new(w1, h1, w2, h2, p, t).resize(src, dst)
}
<commit_msg>SSE-optimizable clamp<commit_after>//! Simple resampling library in pure Rust.
//!
//! # Examples
//!
//! ```
//! use resize::Pixel::RGB24;
//! use resize::Type::Lanczos3;
//!
//! // Downscale by 2x.
//! let (w1, h1) = (640, 480);
//! let (w2, h2) = (320, 240);
//! // Don't forget to fill `src` with image data (RGB24).
//! let src = vec![0;w1*h1*3];
//! // Destination buffer. Must be mutable.
//! let mut dst = vec![0;w2*h2*3];
//! // Create reusable instance.
//! let mut resizer = resize::new(w1, h1, w2, h2, RGB24, Lanczos3);
//! // Do resize without heap allocations.
//! // Might be executed multiple times for different `src` or `dst`.
//! resizer.resize(&src, &mut dst);
//! ```
// Current implementation is based on:
// * https://github.com/sekrit-twc/zimg/tree/master/src/zimg/resize
// * https://github.com/PistonDevelopers/image/blob/master/src/imageops/sample.rs
#![deny(missing_docs)]

use std::f32;

/// Resizing type to use.
pub enum Type {
    /// Point resizing.
    Point,
    /// Triangle (bilinear) resizing.
    Triangle,
    /// Catmull-Rom (bicubic) resizing.
    Catrom,
    /// Resize using Mitchell-Netravali filter.
    Mitchell,
    /// Resize using Sinc-windowed Sinc with radius of 3.
    Lanczos3,
    /// Resize with custom filter.
    Custom(Filter),
}

/// Resampling filter.
pub struct Filter {
    kernel: Box<Fn(f32) -> f32>,
    support: f32,
}

impl Filter {
    /// Create a new filter.
    ///
    /// # Examples
    ///
    /// ```
    /// use resize::Filter;
    /// fn kernel(x: f32) -> f32 { f32::max(1.0 - x.abs(), 0.0) }
    /// let filter = Filter::new(Box::new(kernel), 1.0);
    /// ```
    pub fn new(kernel: Box<Fn(f32) -> f32>, support: f32) -> Filter {
        Filter {kernel: kernel, support: support}
    }

    /// Helper to create Cubic filter with custom B and C parameters.
    pub fn new_cubic(b: f32, c: f32) -> Filter {
        Filter::new(Box::new(move |x| cubic_bc(b, c, x)), 2.0)
    }

    /// Helper to create Lanczos filter with custom radius.
    pub fn new_lanczos(radius: f32) -> Filter {
        Filter::new(Box::new(move |x| lanczos(radius, x)), radius)
    }
}

#[inline]
fn point_kernel(_: f32) -> f32 {
    1.0
}

#[inline]
fn triangle_kernel(x: f32) -> f32 {
    f32::max(1.0 - x.abs(), 0.0)
}

// Taken from
// https://github.com/PistonDevelopers/image/blob/2921cd7/src/imageops/sample.rs#L68
// TODO(Kagami): Could be optimized for known B and C, see e.g.
// https://github.com/sekrit-twc/zimg/blob/1a606c0/src/zimg/resize/filter.cpp#L149
#[inline]
fn cubic_bc(b: f32, c: f32, x: f32) -> f32 {
    let a = x.abs();
    let k = if a < 1.0 {
        (12.0 - 9.0 * b - 6.0 * c) * a.powi(3) +
        (-18.0 + 12.0 * b + 6.0 * c) * a.powi(2) +
        (6.0 - 2.0 * b)
    } else if a < 2.0 {
        (-b - 6.0 * c) * a.powi(3) +
        (6.0 * b + 30.0 * c) * a.powi(2) +
        (-12.0 * b - 48.0 * c) * a +
        (8.0 * b + 24.0 * c)
    } else {
        0.0
    };
    k / 6.0
}

#[inline]
fn sinc(x: f32) -> f32 {
    if x == 0.0 {
        1.0
    } else {
        let a = x * f32::consts::PI;
        a.sin() / a
    }
}

#[inline]
fn lanczos(taps: f32, x: f32) -> f32 {
    if x.abs() < taps {
        sinc(x) * sinc(x / taps)
    } else {
        0.0
    }
}

/// Supported pixel formats.
// TODO(Kagami): >8-bit formats.
#[derive(Debug, Clone, Copy)]
pub enum Pixel {
    /// Grayscale, 8-bit.
    Gray8,
    /// RGB, 8-bit per component.
    RGB24,
    /// RGBA, 8-bit per component.
    RGBA,
}

impl Pixel {
    /// Size of one pixel in that format in bytes.
    #[inline]
    pub fn get_size(&self) -> usize {
        match *self {
            Pixel::Gray8 => 1,
            Pixel::RGB24 => 3,
            Pixel::RGBA => 4,
        }
    }

    /// Return number of components of that format.
    #[inline]
    pub fn get_ncomponents(&self) -> usize {
        match *self {
            Pixel::Gray8 => 1,
            Pixel::RGB24 => 3,
            Pixel::RGBA => 4,
        }
    }
}

/// Resampler with preallocated buffers and coeffecients for the given
/// dimensions and filter type.
#[derive(Debug)]
pub struct Resizer {
    // Source/target dimensions.
    w1: usize,
    h1: usize,
    w2: usize,
    h2: usize,
    pix_fmt: Pixel,
    // Temporary/preallocated stuff.
    tmp: Vec<f32>,
    accum: Vec<f32>,
    coeffs_w: Vec<CoeffsLine>,
    coeffs_h: Vec<CoeffsLine>,
}

#[derive(Debug)]
struct CoeffsLine {
    left: usize,
    data: Vec<f32>,
}

impl Resizer {
    /// Create a new resizer instance.
    pub fn new(w1: usize, h1: usize, w2: usize, h2: usize, p: Pixel, t: Type) -> Resizer {
        let filter = match t {
            Type::Point => Filter::new(Box::new(point_kernel), 0.0),
            Type::Triangle => Filter::new(Box::new(triangle_kernel), 1.0),
            Type::Catrom => Filter::new_cubic(0.0, 0.5),
            Type::Mitchell => Filter::new_cubic(1.0/3.0, 1.0/3.0),
            Type::Lanczos3 => Filter::new_lanczos(3.0),
            Type::Custom(f) => f,
        };
        Resizer {
            w1: w1,
            h1: h1,
            w2: w2,
            h2: h2,
            pix_fmt: p,
            tmp: vec![0.0;w1*h2*p.get_size()],
            accum: vec![0.0;p.get_ncomponents()],
            // TODO(Kagami): Use same coeffs if w1 = h1 = w2 = h2?
            coeffs_w: Self::calc_coeffs(w1, w2, &filter),
            coeffs_h: Self::calc_coeffs(h1, h2, &filter),
        }
    }

    fn calc_coeffs(s1: usize, s2: usize, f: &Filter) -> Vec<CoeffsLine> {
        let ratio = s1 as f32 / s2 as f32;
        // Scale the filter when downsampling.
        let filter_scale = if ratio > 1.0 { ratio } else { 1.0 };
        let filter_radius = (f.support * filter_scale).ceil();
        let mut coeffs = Vec::with_capacity(s2);
        for x2 in 0..s2 {
            let x1 = (x2 as f32 + 0.5) * ratio - 0.5;
            let left = (x1 - filter_radius).ceil() as isize;
            let left = Self::clamp(left, 0, s1 as isize - 1) as usize;
            let right = (x1 + filter_radius).floor() as isize;
            let right = Self::clamp(right, 0, s1 as isize - 1) as usize;
            let mut data = Vec::with_capacity(right - left + 1);
            let mut sum = 0.0;
            for i in left..right+1 {
                sum += (f.kernel)((i as f32 - x1) / filter_scale);
            }
            for i in left..right+1 {
                let v = (f.kernel)((i as f32 - x1) / filter_scale);
                data.push(v / sum);
            }
            coeffs.push(CoeffsLine {left: left, data: data});
        }
        coeffs
    }

    #[inline]
    fn clamp<N: PartialOrd>(input: N, min: N, max: N) -> N {
        if input > max {
            return max;
        } else if input < min {
            return min;
        } else {
            return input;
        }
    }

    #[inline]
    fn pack_u8(v: f32) -> u8 {
        if v > 255.0 {
            return 255;
        } else if v < 0.0 {
            return 0;
        } else {
            return v.round() as u8;
        }
    }

    #[inline]
    fn clear_accum(&mut self) {
        for v in self.accum.iter_mut() {
            *v = 0.0;
        }
    }

    // Resample W1xH1 to W1xH2.
    fn sample_rows(&mut self, src: &[u8]) {
        let ncomp = self.pix_fmt.get_ncomponents();
        let mut offset = 0;
        for x1 in 0..self.w1 {
            for y2 in 0..self.h2 {
                self.clear_accum();
                let ref line = self.coeffs_h[y2];
                for (i, coeff) in line.data.iter().enumerate() {
                    let y0 = line.left + i;
                    let base = (y0 * self.w1 + x1) * ncomp;
                    for n in 0..ncomp {
                        let p = src[base + n] as f32;
                        self.accum[n] += p * coeff;
                    }
                }
                for &v in &self.accum {
                    self.tmp[offset] = v;
                    offset += 1;
                }
            }
        }
    }

    // Resample W1xH2 to W2xH2.
    fn sample_cols(&mut self, dst: &mut [u8]) {
        let ncomp = self.pix_fmt.get_ncomponents();
        let mut offset = 0;
        for y2 in 0..self.h2 {
            for x2 in 0..self.w2 {
                self.clear_accum();
                let ref line = self.coeffs_w[x2];
                for (i, coeff) in line.data.iter().enumerate() {
                    let x0 = line.left + i;
                    let base = (x0 * self.h2 + y2) * ncomp;
                    for n in 0..ncomp {
                        let p = self.tmp[base + n];
                        self.accum[n] += p * coeff;
                    }
                }
                for &v in &self.accum {
                    dst[offset] = Self::pack_u8(v);
                    offset += 1;
                }
            }
        }
    }

    /// Resize `src` image data into `dst`.
    pub fn resize(&mut self, src: &[u8], dst: &mut [u8]) {
        // TODO(Kagami):
        // * Multi-thread
        // * Bound checkings
        // * SIMD
        assert_eq!(src.len(), self.w1 * self.h1 * self.pix_fmt.get_size());
        assert_eq!(dst.len(), self.w2 * self.h2 * self.pix_fmt.get_size());
        self.sample_rows(src);
        self.sample_cols(dst)
    }
}

/// Create a new resizer instance. Alias for `Resizer::new`.
pub fn new(w1: usize, h1: usize, w2: usize, h2: usize, p: Pixel, t: Type) -> Resizer {
    Resizer::new(w1, h1, w2, h2, p, t)
}

/// Resize image data to the new dimension in a single step.
///
/// **NOTE:** If you need to resize to the same dimension multiple times,
/// consider creating an resizer instance since it's faster.
pub fn resize(
    w1: usize, h1: usize, w2: usize, h2: usize,
    p: Pixel, t: Type,
    src: &[u8], dst: &mut [u8],
) {
    Resizer::new(w1, h1, w2, h2, p, t).resize(src, dst)
}
<|endoftext|>


<commit_before>// Forsaken docs justly quibble the vexed programmer's waning zeal
//! Text hyphenation in a variety of languages.
//!
//!
//! ## Usage
//!
//! A typical import comprises the `Hyphenation` trait, the `Standard`
//! hyphenator, and the `Language` enum. This exposes the crate's core
//! functionality, and the set of available languages.
//!
//! ```ignore
//! extern crate hyphenation;
//
//! use hyphenation::{Hyphenation, Standard, Language};
//! ```
//!
//! To begin with, we must initiate the `Corpus` for our working language.
//!
//! ```ignore
//! let english_us = hyphenation::load(Language::English_US).unwrap();
//! ```
//!
//! Our English `Corpus` can now be used by `Hyphenation` methods.
//! Core functionality is provided by `opportunities()`, which returns the
//! byte indices of valid hyphenation points within a word.
//!
//! ```ignore
//! let indices = "hyphenation".opportunities(&english_us);
//! assert_eq!(indices, vec![2, 6]);
//! ```
//!
//! The same `Corpus` may also be used by *hyphenators*: iterators which
//! segment words in accordance with hyphenation practices, as described
//! by the corpus.
//!
//! The simplest (and, presently, only) hyphenator is `Standard`:
//!
//! ```ignore
//! let h: Standard = "hyphenation".hyphenate(&english_us);
//! ```
//!
//! The `Standard` hyphenator does not allocate new strings, returning
//! slices instead.
//!
//! ```ignore
//! let v: Vec<&str> = h.collect();
//! assert_eq!(v, vec!["hy", "phen", "ation"]);
//! ```
//!
//! ## Full-text Hyphenation
//! While hyphenation is always performed on a per-word basis, convenience
//! calls for a subtrait to provide methods to work with full text.
//!
//! ```ignore
//! use hyphenation::{FullTextHyphenation};
//!
//! let h2: Standard = "Word hyphenation by computer.".fulltext_hyphenate(&english_us);
//! let v2: Vec<&str> = h2.collect();
//! assert_eq!(v2, vec!["Word hy", "phen", "ation by com", "puter."]);
//! ```
//!
//! Hyphenators also expose some simple methods to render hyphenated text:
//! `punctuate()` and `punctuate_with(string)`, which mark hyphenation
//! opportunities respectively with soft hyphens (Unicode `U+00AD SOFT HYPHEN`)
//! and any given `string`.
//!
//! ```ignore
//! let h3 = "anfractuous".hyphenate(&english_us);
//! let s3: String = h2.clone().punctuate().collect();
//! assert_eq!(s3, "an\u{ad}frac\u{ad}tu\u{ad}ous".to_owned());
//!
//! let s4: String = h2.punctuate_with("-").collect()
//! assert_eq!(s4, "an-frac-tu-ous".to_owned());
//! ```

extern crate bincode;
extern crate fnv;
extern crate hyphenation_commons;
extern crate unicode_segmentation;

mod resources;
mod utilia;
pub mod hyphenator;
pub mod language;
pub mod load;

pub use hyphenation_commons::{KLPair, KLPTrie, Exceptions, Patterns};
pub use hyphenator::{Hyphenation, FullTextHyphenation, Standard};
pub use language::{Language, Corpus};

// Note: the name "load" is misleading, as we are merely accessing embedded tries.
// However, future versions of `hyphenation` should support both embedding
// and runtime loading of pattern data, with loading being the default;
// anticipating such changes, we keep `load` as a public export.
pub use load::{language as load};
<commit_msg>Review main docs for v0.6.0<commit_after>// Forsaken docs justly quibble the vexed programmer's waning zeal
//! Text hyphenation in a variety of languages.
//!
//!
//! ## Usage
//!
//! A typical import comprises the `Hyphenation` trait, the `Standard`
//! hyphenator, and the `Language` enum. This exposes the crate's core
//! functionality, and the set of available languages.
//!
//! ```ignore
//! extern crate hyphenation;
//
//! use hyphenation::{Hyphenation, Standard, Language};
//! ```
//!
//! To begin with, we must initiate the `Corpus` for our working language.
//!
//! ```ignore
//! let english_us = hyphenation::load(Language::English_US).unwrap();
//! ```
//!
//! Our English `Corpus` can now be used by `Hyphenation` methods.
//! Core functionality is provided by `opportunities()`, which returns the
//! byte indices of valid hyphenation points within a word.
//!
//! ```ignore
//! let indices = "hyphenation".opportunities(&english_us);
//! assert_eq!(indices, vec![2, 6]);
//! ```
//!
//! The same `Corpus` may also be used by *hyphenators*: iterators which
//! segment words in accordance with hyphenation practices, as described
//! by the corpus.
//!
//! The simplest (and, presently, only) hyphenator is `Standard`:
//!
//! ```ignore
//! let h: Standard = "hyphenation".hyphenate(&english_us);
//! ```
//!
//! The `Standard` hyphenator does not allocate new strings, returning
//! slices instead.
//!
//! ```ignore
//! let v: Vec<&str> = h.collect();
//! assert_eq!(v, vec!["hy", "phen", "ation"]);
//! ```
//!
//! An hyphenator always knows its exact length, which means that we can
//! retrieve the number of remaining word segments with `.len()`.
//!
//! ```ignore
//! let mut iter = "hyphenation".hyphenate(&english_us);
//! assert_eq!(iter.len(), 3);
//! iter.next();
//! assert_eq!(iter.len(), 2);
//! ```
//!
//!
//! ## Full-text Hyphenation
//!
//! While hyphenation is always performed on a per-word basis, convenience
//! calls for a subtrait to provide methods to work with full text.
//!
//! ```ignore
//! use hyphenation::{FullTextHyphenation};
//!
//! let h2: Standard = "Word hyphenation by computer.".fulltext_hyphenate(&english_us);
//! let v2: Vec<&str> = h2.collect();
//! assert_eq!(v2, vec!["Word hy", "phen", "ation by com", "puter."]);
//! ```
//!
//! Hyphenators also expose some simple methods to render hyphenated text:
//! `punctuate()` and `punctuate_with(string)`, which mark hyphenation
//! opportunities respectively with soft hyphens (Unicode `U+00AD SOFT HYPHEN`)
//! and any given `string`.
//!
//! ```ignore
//! let h3 = "anfractuous".hyphenate(&english_us);
//! let s3: String = h2.clone().punctuate().collect();
//! assert_eq!(s3, "an\u{ad}frac\u{ad}tu\u{ad}ous".to_owned());
//!
//! let s4: String = h2.punctuate_with("‧").collect()
//! assert_eq!(s4, "an‧frac‧tu‧ous".to_owned());
//! ```

extern crate bincode;
extern crate fnv;
extern crate hyphenation_commons;
extern crate unicode_segmentation;

mod resources;
mod utilia;
pub mod hyphenator;
pub mod language;
pub mod load;

pub use hyphenation_commons::{KLPair, KLPTrie, Exceptions, Patterns};
pub use hyphenator::{Hyphenation, FullTextHyphenation, Standard};
pub use language::{Language, Corpus};

// Note: the name "load" is misleading, as we are merely accessing embedded tries.
// However, future versions of `hyphenation` should support both embedding
// and runtime loading of pattern data, with loading being the default;
// anticipating such changes, we keep `load` as a public export.
pub use load::{language as load};
<|endoftext|>


<commit_before>#![feature(io)]

extern crate xml;

use std::ascii::AsciiExt;
use std::default::Default;
use std::iter::IteratorExt;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

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

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Self;
}

/// RSS version 2.0
#[derive(Default)]
pub struct Rss(pub Channel);

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

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

        rss
    }

    fn from_xml(element: Element) -> Self {
        if element.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", element.name);
        }

        let channel_element = element.get_child("channel", None).unwrap();
        let channel = ViaXml::from_xml(channel_element.clone());

        Rss(channel)
    }
}

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

    fn from_read(reader: &mut io::Read) -> Self {
        let mut rss_string = String::new();

        match reader.read_to_string(&mut rss_string) {
            Ok(..) => (),
            Err(..) => panic!("Error reading string from reader"),
        }

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

        let mut builder = ElementBuilder::new();

        for event in parser {
            match builder.push_event(event) {
                Ok(Some(element)) => return ViaXml::from_xml(element),
                _ => (),
            }
        }

        panic!("RSS read error")
    }
}

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

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

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

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

        channel
    }

    fn from_xml(element: Element) -> Self {
        let mut channel: Channel = Default::default();

        match element.get_child("title", None) {
            Some(element) => channel.title = element.content_str(),
            None => (),
        }

        match element.get_child("link", None) {
            Some(element) => channel.link = element.content_str(),
            None => (),
        }

        match element.get_child("description", None) {
            Some(element) => channel.description = element.content_str(),
            None => (),
        }

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

        channel
    }
}

#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    // pub author
    // pub category
    // pub comments
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

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

        if let Some(ref s) = self.title {
            item.tag(elem_with_text("title", s));
        }

        if let Some(ref s) = self.link {
            item.tag(elem_with_text("link", s));
        }

        if let Some(ref s) = self.description {
            item.tag(elem_with_text("description", s));
        }

        item
    }

    fn from_xml(element: Element) -> Self {
        let mut item: Item = Default::default();

        match element.get_child("title", None) {
            Some(element) => item.title = Some(element.content_str()),
            None => (),
        }

        match element.get_child("link", None) {
            Some(element) => item.link = Some(element.content_str()),
            None => (),
        }

        match element.get_child("description", None) {
            Some(element) => item.description = Some(element.content_str()),
            None => (),
        }

        item
    }
}

#[cfg(test)]
mod test {
    use super::{Rss, Item, Channel};

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

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

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

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let Rss(channel) = Rss::from_read(&mut file);
    }

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

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

    #[test]
    fn test_from_read_one_channel_with_title() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes);
        assert_eq!("Hello world!", channel.title);
    }
}
<commit_msg>Improve documentation for Rss<commit_after>#![feature(io)]

extern crate xml;

use std::ascii::AsciiExt;
use std::default::Default;
use std::iter::IteratorExt;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

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

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Self;
}

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

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

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

        rss
    }

    fn from_xml(element: Element) -> Self {
        if element.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", element.name);
        }

        let channel_element = element.get_child("channel", None).unwrap();
        let channel = ViaXml::from_xml(channel_element.clone());

        Rss(channel)
    }
}

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

    fn from_read(reader: &mut io::Read) -> Self {
        let mut rss_string = String::new();

        match reader.read_to_string(&mut rss_string) {
            Ok(..) => (),
            Err(..) => panic!("Error reading string from reader"),
        }

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

        let mut builder = ElementBuilder::new();

        for event in parser {
            match builder.push_event(event) {
                Ok(Some(element)) => return ViaXml::from_xml(element),
                _ => (),
            }
        }

        panic!("RSS read error")
    }
}

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

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

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

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

        channel
    }

    fn from_xml(element: Element) -> Self {
        let mut channel: Channel = Default::default();

        match element.get_child("title", None) {
            Some(element) => channel.title = element.content_str(),
            None => (),
        }

        match element.get_child("link", None) {
            Some(element) => channel.link = element.content_str(),
            None => (),
        }

        match element.get_child("description", None) {
            Some(element) => channel.description = element.content_str(),
            None => (),
        }

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

        channel
    }
}

#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    // pub author
    // pub category
    // pub comments
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

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

        if let Some(ref s) = self.title {
            item.tag(elem_with_text("title", s));
        }

        if let Some(ref s) = self.link {
            item.tag(elem_with_text("link", s));
        }

        if let Some(ref s) = self.description {
            item.tag(elem_with_text("description", s));
        }

        item
    }

    fn from_xml(element: Element) -> Self {
        let mut item: Item = Default::default();

        match element.get_child("title", None) {
            Some(element) => item.title = Some(element.content_str()),
            None => (),
        }

        match element.get_child("link", None) {
            Some(element) => item.link = Some(element.content_str()),
            None => (),
        }

        match element.get_child("description", None) {
            Some(element) => item.description = Some(element.content_str()),
            None => (),
        }

        item
    }
}

#[cfg(test)]
mod test {
    use super::{Rss, Item, Channel};

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

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

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

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let Rss(channel) = Rss::from_read(&mut file);
    }

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

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

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


<commit_before>extern crate curl;

use curl::easy::Easy;

const YAHOO_FINANCE_URL: &'static str = "http://download.finance.yahoo.com/d/quotes.csv?s=";

pub struct Stock {
    symbol: String,
    current: String,
}

impl Stock {
    pub fn update_current_price(&mut self) {
      let mut data = Vec::new();
      let mut curl = Easy::new();
      let url = format!("{}{}&f=l1", YAHOO_FINANCE_URL, self.symbol);
      curl.url(&url).unwrap();
      {
        let mut transfer = curl.transfer();
        transfer.write_function(|d| {
          data.extend_from_slice(d);
          Ok(d.len())
        }).unwrap();
        transfer.perform().unwrap()
      }
      self.current = String::from_utf8(data).unwrap();
    }
}

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

    #[test]
    fn can_update_a_stocks_current_price() {
      let mut stock = Stock { symbol: "IBM".to_string(), current: "0.0".to_string() };
      stock.update_current_price();
      assert!(stock.current != "0.0");
    }
}
<commit_msg>Add yahoo_finance namespace<commit_after>extern crate curl;

mod yahoo_finance {
  const YAHOO_FINANCE_URL: &'static str = "http://download.finance.yahoo.com/d/quotes.csv?s=";
  use curl::easy::Easy;

  pub struct Stock {
      pub symbol: String,
      pub current: String,
  }

  impl Stock {
      pub fn update_current_price(&mut self) {
        let mut data = Vec::new();
        let mut curl = Easy::new();
        let url = format!("{}{}&f=l1", YAHOO_FINANCE_URL, self.symbol);
        curl.url(&url).unwrap();
        {
          let mut transfer = curl.transfer();
          transfer.write_function(|d| {
            data.extend_from_slice(d);
            Ok(d.len())
          }).unwrap();
          transfer.perform().unwrap()
        }
        self.current = String::from_utf8(data).unwrap();
      }
  }
}

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

    #[test]
    fn can_update_a_stocks_current_price() {
      let mut stock = yahoo_finance::Stock { symbol: "IBM".to_string(), current: "0.0".to_string() };
      stock.update_current_price();
      assert!(stock.current != "0.0");
    }
}
<|endoftext|>