<commit_before>use libucl_sys::{
    ucl_parser,
    ucl_parser_new,
    ucl_parser_free,
    ucl_parser_add_file,
    ucl_parser_add_chunk,
    ucl_parser_get_error,
    ucl_parser_get_object,
};
use libc::size_t;

use super::utils;
use super::object::Object;

use std::path::Path;

bitflags! {
    flags ParserFlags: i32 {
        const DEFAULT            = 0x0,
        const LOWERCASE          = 0x1,
        const ZEROCOPY           = 0x2,
        const NO_TIME            = 0x4,
        const NO_IMPLICIT_ARRAYS = 0x8
    }
}

pub struct Parser {
    parser: *mut ucl_parser,
}

impl Parser {
    /// Create new parser instance with default options
    pub fn new() -> Self {
        Self::with_flags(DEFAULT)
    }

    /// Create new parser with given option flags
    ///
    /// Flags:
    ///
    /// - `DEFAULT` - default configuration
    /// - `LOWERCASE` - convert all keys to lower case
    /// - `ZEROCOPY` - parse input in zero-copy mode if possible (you must ensure that input memory
    ///   is not freed if an object is in use)
    /// - `NO_TIME` - do not parse time and treat it's value as string
    /// - `NO_IMPLICIT_ARRAYS` - create explicit arrays instead of implicit ones
    ///
    /// # Examples
    ///
    /// ```rust
    /// let parser = ucl::Parser::with_flags(ucl::parser::LOWERCASE);
    /// let doc = parser.parse("A = b").unwrap();
    ///
    /// assert!(doc.fetch("a").is_some());
    /// ```
    pub fn with_flags(flags: ParserFlags) -> Self {
        Parser {
            parser: unsafe { ucl_parser_new(flags.bits()) }
        }
    }

    /// Parse given string. Returns root object on success.
    ///
    /// It moves out `Parser`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// assert!(ucl::Parser::new().parse("a = b").is_ok());
    /// assert!(ucl::Parser::new().parse("a =").is_err());
    /// ```
    pub fn parse<T: AsRef<str>>(mut self, string: T) -> Result<Object, String> {
        let len = string.as_ref().len() as size_t;
        let result = unsafe { ucl_parser_add_chunk(self.parser, utils::to_c_str(string), len) };

        if result {
            Ok(self.get_object().unwrap())
        } else {
            Err(self.get_error().unwrap())
        }
    }

    /// Parse file at given `Path`.
    ///
    /// It moves out `Parser`.
    pub fn parse_file<T: AsRef<Path>>(mut self, path: T) -> Result<Object, String> {
        let filename = path.as_ref().to_str().unwrap();
        let result = unsafe { ucl_parser_add_file(self.parser, utils::to_c_str(filename)) };

        if result {
            Ok(self.get_object().unwrap())
        } else {
            Err(self.get_error().unwrap())
        }
    }

    fn get_object(&mut self) -> Option<Object> {
        Object::from_cptr(unsafe { ucl_parser_get_object(self.parser) })
    }

    fn get_error(&mut self) -> Option<String> {
        let err = unsafe { ucl_parser_get_error(self.parser) };

        utils::to_str(err)
    }
}

impl Drop for Parser {
    fn drop(&mut self) {
        unsafe { ucl_parser_free(self.parser) }
    }
}

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

    #[test]
    fn string_parsing() {
        let p = Parser::new();
        let s = r#"lol = "lol""#;

        assert!(p.parse(s).is_ok());
    }

    #[test]
    fn empty_string_parsing() {
        let p = Parser::new();
        let s = r#""#;

        assert!(p.parse(s).is_ok());
    }

    #[test]
    fn key_fetching() {
        let p = Parser::new();
        let s = r#"lol = 10"#;
        let res = p.parse(s).unwrap();

        assert_eq!(res.fetch("lol").unwrap().as_int(), Some(10));
    }

    #[test]
    fn flags() {
        let s = r#"LoL = 10"#;
        let p = Parser::with_flags(DEFAULT);
        let res = p.parse(s).unwrap();

        assert!(res.fetch("lol").is_none());

        let p = Parser::with_flags(LOWERCASE);
        let res = p.parse(s).unwrap();

        assert_eq!(res.fetch("lol").unwrap().as_int(), Some(10));
    }
}
<commit_msg>improv: add variables registration<commit_after>use libucl_sys::*;
use libc::size_t;

use super::utils;
use super::object::Object;

use std::path::Path;

bitflags! {
    flags ParserFlags: i32 {
        const DEFAULT            = 0x0,
        const LOWERCASE          = 0x1,
        const ZEROCOPY           = 0x2,
        const NO_TIME            = 0x4,
        const NO_IMPLICIT_ARRAYS = 0x8
    }
}

pub struct Parser {
    parser: *mut ucl_parser,
}

impl Parser {
    /// Create new parser instance with default options
    pub fn new() -> Self {
        Self::with_flags(DEFAULT)
    }

    /// Create new parser with given option flags
    ///
    /// Flags:
    ///
    /// - `DEFAULT` - default configuration
    /// - `LOWERCASE` - convert all keys to lower case
    /// - `ZEROCOPY` - parse input in zero-copy mode if possible (you must ensure that input memory
    ///   is not freed if an object is in use)
    /// - `NO_TIME` - do not parse time and treat it's value as string
    /// - `NO_IMPLICIT_ARRAYS` - create explicit arrays instead of implicit ones
    ///
    /// # Examples
    ///
    /// ```rust
    /// let parser = ucl::Parser::with_flags(ucl::parser::LOWERCASE);
    /// let doc = parser.parse("A = b").unwrap();
    ///
    /// assert!(doc.fetch("a").is_some());
    /// ```
    pub fn with_flags(flags: ParserFlags) -> Self {
        Parser {
            parser: unsafe { ucl_parser_new(flags.bits()) }
        }
    }

    /// Parse given string. Returns root object on success.
    ///
    /// It moves out `Parser`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// assert!(ucl::Parser::new().parse("a = b").is_ok());
    /// assert!(ucl::Parser::new().parse("a =").is_err());
    /// ```
    pub fn parse<T: AsRef<str>>(mut self, string: T) -> Result<Object, String> {
        let len = string.as_ref().len() as size_t;
        let result = unsafe { ucl_parser_add_chunk(self.parser, utils::to_c_str(string), len) };

        if result {
            Ok(self.get_object().unwrap())
        } else {
            Err(self.get_error().unwrap())
        }
    }

    /// Parse file at given `Path`.
    ///
    /// It moves out `Parser`.
    pub fn parse_file<T: AsRef<Path>>(mut self, path: T) -> Result<Object, String> {
        let filename = path.as_ref().to_str().unwrap();
        let result = unsafe { ucl_parser_add_file(self.parser, utils::to_c_str(filename)) };

        if result {
            Ok(self.get_object().unwrap())
        } else {
            Err(self.get_error().unwrap())
        }
    }

    /// Register new variable
    ///
    /// # Examples
    ///
    /// ```rust
    /// let p = Parser::new();
    /// p.register_var("LOL".to_string(), "test".to_string());
    /// let res = p.parse("lol = $LOL").unwrap();
    ///
    /// assert_eq!(res.fetch("lol").unwrap().as_string(), Some("test".to_string()));
    /// ```
    pub fn register_var(&self, name: String, value: String) {
        unsafe {
            ucl_parser_register_variable(self.parser, utils::to_c_str(name), utils::to_c_str(value))
        }
    }

    fn get_object(&mut self) -> Option<Object> {
        Object::from_cptr(unsafe { ucl_parser_get_object(self.parser) })
    }

    fn get_error(&mut self) -> Option<String> {
        let err = unsafe { ucl_parser_get_error(self.parser) };

        utils::to_str(err)
    }
}

impl Drop for Parser {
    fn drop(&mut self) {
        unsafe { ucl_parser_free(self.parser) }
    }
}

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

    #[test]
    fn string_parsing() {
        let p = Parser::new();
        let s = r#"lol = "lol""#;

        assert!(p.parse(s).is_ok());
    }

    #[test]
    fn empty_string_parsing() {
        let p = Parser::new();
        let s = r#""#;

        assert!(p.parse(s).is_ok());
    }

    #[test]
    fn key_fetching() {
        let p = Parser::new();
        let s = r#"lol = 10"#;
        let res = p.parse(s).unwrap();

        assert_eq!(res.fetch("lol").unwrap().as_int(), Some(10));
    }

    #[test]
    fn flags() {
        let s = r#"LoL = 10"#;
        let p = Parser::with_flags(DEFAULT);
        let res = p.parse(s).unwrap();

        assert!(res.fetch("lol").is_none());

        let p = Parser::with_flags(LOWERCASE);
        let res = p.parse(s).unwrap();

        assert_eq!(res.fetch("lol").unwrap().as_int(), Some(10));
    }

    #[test]
    fn variables() {
        let s = r#"lol = $LOL"#;
        let p = Parser::new();
        p.register_var("LOL".to_string(), "test".to_string());
        let res = p.parse(s).unwrap();

        assert_eq!(res.fetch("lol").unwrap().as_string(), Some("test".to_string()));
    }
}
<|endoftext|>


<commit_before>use std::str::from_utf8;
use nom::IResult;

#[derive(Debug,PartialEq,Eq)]
pub struct PosixHeader<'a> {
    pub name:     & 'a str,
    pub mode:     & 'a str,
    pub uid:      & 'a str,
    pub gid:      & 'a str,
    pub size:     & 'a str,
    pub mtime:    & 'a str,
    pub chksum:   & 'a str,
    pub typeflag: char,
    pub linkname: & 'a str,
    pub ustar:    Option<UStarHeader<'a>>
}

#[derive(Debug,PartialEq,Eq)]
pub struct UStarHeader<'a> {
    pub magic:    & 'a str,
    pub version:  & 'a str,
    pub uname:    & 'a str,
    pub gname:    & 'a str,
    pub devmajor: & 'a str,
    pub devminor: & 'a str,
    pub prefix:   & 'a str,
}

#[derive(Debug,PartialEq,Eq)]
pub struct TarEntry<'a> {
    pub header:   PosixHeader<'a>,
    pub contents: & 'a str
}

pub fn parse_header(i: &[u8]) -> IResult<&[u8], PosixHeader> {
    chain!(i,
        name:     map_res!(take!(100), from_utf8) ~
        mode:     map_res!(take!(8),   from_utf8) ~
        uid:      map_res!(take!(8),   from_utf8) ~
        gid:      map_res!(take!(8),   from_utf8) ~
        size:     map_res!(take!(12),  from_utf8) ~
        mtime:    map_res!(take!(12),  from_utf8) ~
        chksum:   map_res!(take!(8),   from_utf8) ~
        /* TODO: typeflag */
        linkname: map_res!(take!(100), from_utf8),
        /* TODO: ustar */
        ||{
            PosixHeader {
                name:     name,
                mode:     mode,
                uid:      uid,
                gid:      gid,
                size:     size,
                mtime:    mtime,
                chksum:   chksum,
                typeflag: '1',
                linkname: linkname,
                ustar:    None
            }
        }
    )
}

pub fn parse_entry(i: &[u8]) -> IResult<&[u8], TarEntry> {
    chain!(i,
        header: parse_header,
        /* TODO: contents */
        ||{
            TarEntry {
                header: header,
                contents: ""
            }
        }
    )
}

pub fn parse_tar(i: &[u8]) -> IResult<&[u8], Vec<TarEntry>> {
    many0!(i, parse_entry)
}
<commit_msg>correctly parse typeflag<commit_after>use std::str::from_utf8;
use nom::IResult;

#[derive(Debug,PartialEq,Eq)]
pub struct PosixHeader<'a> {
    pub name:     & 'a str,
    pub mode:     & 'a str,
    pub uid:      & 'a str,
    pub gid:      & 'a str,
    pub size:     & 'a str,
    pub mtime:    & 'a str,
    pub chksum:   & 'a str,
    pub typeflag: char,
    pub linkname: & 'a str,
    pub ustar:    Option<UStarHeader<'a>>
}

#[derive(Debug,PartialEq,Eq)]
pub struct UStarHeader<'a> {
    pub magic:    & 'a str,
    pub version:  & 'a str,
    pub uname:    & 'a str,
    pub gname:    & 'a str,
    pub devmajor: & 'a str,
    pub devminor: & 'a str,
    pub prefix:   & 'a str,
}

#[derive(Debug,PartialEq,Eq)]
pub struct TarEntry<'a> {
    pub header:   PosixHeader<'a>,
    pub contents: & 'a str
}

pub fn parse_header(i: &[u8]) -> IResult<&[u8], PosixHeader> {
    chain!(i,
        name:     map_res!(take!(100), from_utf8) ~
        mode:     map_res!(take!(8),   from_utf8) ~
        uid:      map_res!(take!(8),   from_utf8) ~
        gid:      map_res!(take!(8),   from_utf8) ~
        size:     map_res!(take!(12),  from_utf8) ~
        mtime:    map_res!(take!(12),  from_utf8) ~
        chksum:   map_res!(take!(8),   from_utf8) ~
        typeflag: take!(1)                        ~
        linkname: map_res!(take!(100), from_utf8),
        /* TODO: ustar */
        ||{
            PosixHeader {
                name:     name,
                mode:     mode,
                uid:      uid,
                gid:      gid,
                size:     size,
                mtime:    mtime,
                chksum:   chksum,
                typeflag: typeflag[0] as char,
                linkname: linkname,
                ustar:    None
            }
        }
    )
}

pub fn parse_entry(i: &[u8]) -> IResult<&[u8], TarEntry> {
    chain!(i,
        header: parse_header,
        /* TODO: contents */
        ||{
            TarEntry {
                header: header,
                contents: ""
            }
        }
    )
}

pub fn parse_tar(i: &[u8]) -> IResult<&[u8], Vec<TarEntry>> {
    many0!(i, parse_entry)
}
<|endoftext|>


<commit_before>use crate::i18n::LocalText;
use colored::{ColoredString, Colorize};
use git2::Repository;
use std::io::prelude::*;
use std::sync::{Arc, RwLock};
use std::{env, error, fs, result};
use subprocess::{Exec, NullFile, Redirection};

type Result<T> = result::Result<T, Box<dyn error::Error>>;

/// Dump what we know about the repo
pub fn run() -> Result<()> {
    crate::header("status-header");
    is_setup()?;
    Ok(())
}

/// Evaluate whether this project is pis_setup()?roperly configured
pub fn is_setup() -> Result<bool> {
    let results = Arc::new(RwLock::new(Vec::new()));
    // First round of tests, entirely independent
    rayon::scope(|s| {
        s.spawn(|_| {
            results.write().unwrap().push(is_repo().unwrap());
        });
        s.spawn(|_| {
            results.write().unwrap().push(is_make_exectuable().unwrap());
        });
    });
    let ret = results.read().unwrap().iter().all(|&v| v);
    // Second round of tests, dependent on first set
    if ret {
        rayon::scope(|s| {
            s.spawn(|_| {
                results.write().unwrap().push(is_writable().unwrap());
            });
            s.spawn(|_| {
                results.write().unwrap().push(is_make_gnu().unwrap());
            });
        });
    }
    let ret = results.read().unwrap().iter().all(|&v| v);
    let msg = LocalText::new(if ret { "status-good" } else { "status-bad" }).fmt();
    eprintln!(
        "{} {}",
        "┗━".cyan(),
        if ret { msg.green() } else { msg.red() }
    );
    Ok(ret)
}

/// Are we in a git repo?
pub fn is_repo() -> Result<bool> {
    let cwd = env::current_dir()?;
    let ret = Repository::discover(cwd).is_ok();
    display_check("status-is-repo", ret);
    Ok(ret)
}

/// Is the git repo we are in writable?
pub fn is_writable() -> Result<bool> {
    let cwd = env::current_dir()?;
    let repo = Repository::discover(cwd)?;
    let workdir = repo.workdir().unwrap();
    let testfile = workdir.join(".casile-write-test");
    let mut file = fs::File::create(&testfile)?;
    file.write_all(b"test")?;
    fs::remove_file(&testfile)?;
    let ret = true;
    display_check("status-is-writable", ret);
    Ok(true)
}

/// Check if we can execute the system's `make` utility
pub fn is_make_exectuable() -> Result<bool> {
    let ret = Exec::cmd("make")
        .arg("-v")
        .stdout(NullFile)
        .stderr(NullFile)
        .join()
        .is_ok();
    display_check("status-is-make-executable", ret);
    Ok(true)
}

/// Check that the system's `make` utility is GNU Make
pub fn is_make_gnu() -> Result<bool> {
    let out = Exec::cmd("make")
        .arg("-v")
        .stdout(Redirection::Pipe)
        .stderr(NullFile)
        .capture()?
        .stdout_str();
    let ret = out.starts_with("GNU Make 4.");
    display_check("status-is-make-gnu", ret);
    Ok(true)
}

fn display_check(key: &str, val: bool) {
    eprintln!(
        "{} {} {}",
        "┠─".cyan(),
        LocalText::new(key).fmt(),
        fmt_t_f(val)
    );
}

/// Format a localized string just for true / false status prints
fn fmt_t_f(val: bool) -> ColoredString {
    let key = if val { "status-true" } else { "status-false" };
    let text = LocalText::new(key).fmt();
    if val {
        text.green()
    } else {
        text.red()
    }
}
<commit_msg>fix(cli): Don't grab write lock in threads until results ready<commit_after>use crate::i18n::LocalText;
use colored::{ColoredString, Colorize};
use git2::Repository;
use std::io::prelude::*;
use std::sync::{Arc, RwLock};
use std::{env, error, fs, result};
use subprocess::{Exec, NullFile, Redirection};

type Result<T> = result::Result<T, Box<dyn error::Error>>;

/// Dump what we know about the repo
pub fn run() -> Result<()> {
    crate::header("status-header");
    is_setup()?;
    Ok(())
}

/// Evaluate whether this project is pis_setup()?roperly configured
pub fn is_setup() -> Result<bool> {
    let results = Arc::new(RwLock::new(Vec::new()));

    // First round of tests, entirely independent
    rayon::scope(|s| {
        s.spawn(|_| {
            let ret = is_repo().unwrap();
            results.write().unwrap().push(ret);
        });
        s.spawn(|_| {
            let ret = is_make_exectuable().unwrap();
            results.write().unwrap().push(ret);
        });
    });

    // Second round of tests, dependent on first set
    if results.read().unwrap().iter().all(|&v| v) {
        rayon::scope(|s| {
            s.spawn(|_| {
                let ret = is_writable().unwrap();
                results.write().unwrap().push(ret);
            });
            s.spawn(|_| {
                let ret = is_make_gnu().unwrap();
                results.write().unwrap().push(ret);
            });
        });
    }

    let ret = results.read().unwrap().iter().all(|&v| v);
    let msg = LocalText::new(if ret { "status-good" } else { "status-bad" }).fmt();
    eprintln!(
        "{} {}",
        "┗━".cyan(),
        if ret { msg.green() } else { msg.red() }
    );
    Ok(ret)
}

/// Are we in a git repo?
pub fn is_repo() -> Result<bool> {
    let cwd = env::current_dir()?;
    let ret = Repository::discover(cwd).is_ok();
    display_check("status-is-repo", ret);
    Ok(ret)
}

/// Is the git repo we are in writable?
pub fn is_writable() -> Result<bool> {
    let cwd = env::current_dir()?;
    let repo = Repository::discover(cwd)?;
    let workdir = repo.workdir().unwrap();
    let testfile = workdir.join(".casile-write-test");
    let mut file = fs::File::create(&testfile)?;
    file.write_all(b"test")?;
    fs::remove_file(&testfile)?;
    let ret = true;
    display_check("status-is-writable", ret);
    Ok(true)
}

/// Check if we can execute the system's `make` utility
pub fn is_make_exectuable() -> Result<bool> {
    let ret = Exec::cmd("make")
        .arg("-v")
        .stdout(NullFile)
        .stderr(NullFile)
        .join()
        .is_ok();
    display_check("status-is-make-executable", ret);
    Ok(true)
}

/// Check that the system's `make` utility is GNU Make
pub fn is_make_gnu() -> Result<bool> {
    let out = Exec::cmd("make")
        .arg("-v")
        .stdout(Redirection::Pipe)
        .stderr(NullFile)
        .capture()?
        .stdout_str();
    let ret = out.starts_with("GNU Make 4.");
    display_check("status-is-make-gnu", ret);
    Ok(true)
}

fn display_check(key: &str, val: bool) {
    eprintln!(
        "{} {} {}",
        "┠─".cyan(),
        LocalText::new(key).fmt(),
        fmt_t_f(val)
    );
}

/// Format a localized string just for true / false status prints
fn fmt_t_f(val: bool) -> ColoredString {
    let key = if val { "status-true" } else { "status-false" };
    let text = LocalText::new(key).fmt();
    if val {
        text.green()
    } else {
        text.red()
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2017, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

#[cfg(feature = "use_glib")]
use glib::translate::*;
use ffi::enums::RegionOverlap;
use RectangleInt;
use ffi;

use ffi::cairo_region_t;
use ffi::enums::Status;

pub struct Region(*mut cairo_region_t, bool);

#[cfg(feature = "use_glib")]
#[doc(hidden)]
impl<'a> ToGlibPtr<'a, *mut ffi::cairo_region_t> for &'a Region {
    type Storage = &'a Region;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *mut ffi::cairo_region_t, &'a Region> {
        Stash(self.0, *self)
    }

    #[inline]
    fn to_glib_full(&self) -> *mut ffi::cairo_region_t {
        unsafe {
            ffi::cairo_region_reference(self.0)
        }
    }
}

#[cfg(feature = "use_glib")]
#[doc(hidden)]
impl<'a> ToGlibPtrMut<'a, *mut ffi::cairo_region_t> for Region {
    type Storage = &'a mut Self;

    // FIXME: This is unsafe: regions are reference counted so we could get multiple mutable
    // references here
    #[inline]
    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::cairo_region_t, Self> {
        StashMut(self.0, self)
    }
}

#[cfg(feature = "use_glib")]
#[doc(hidden)]
impl FromGlibPtrNone<*mut ffi::cairo_region_t> for Region {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut ffi::cairo_region_t) -> Region {
        Self::from_raw_none(ptr)
    }
}

#[cfg(feature = "use_glib")]
#[doc(hidden)]
impl FromGlibPtrBorrow<*mut ffi::cairo_region_t> for Region {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_region_t) -> Region {
        Self::from_raw_borrow(ptr)
    }
}

#[cfg(feature = "use_glib")]
#[doc(hidden)]
impl FromGlibPtrFull<*mut ffi::cairo_region_t> for Region {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut ffi::cairo_region_t) -> Region {
        Self::from_raw_full(ptr)
    }
}

#[cfg(feature = "use_glib")]
gvalue_impl!(Region, ffi::cairo_region_t, ffi::gobject::cairo_gobject_region_get_type);

impl AsRef<Region> for Region {
    fn as_ref(&self) -> &Region {
        self
    }
}

impl Clone for Region {
    fn clone(&self) -> Region {
        unsafe { Self::from_raw_none(self.to_raw_none()) }
    }
}

impl Drop for Region {
    fn drop(&mut self) {
        if !self.1 {
            unsafe { ffi::cairo_region_destroy(self.0); }
        }
    }
}

impl PartialEq for Region {
    fn eq(&self, other: &Region) -> bool {
        unsafe {
            ffi::cairo_region_equal(self.0, other.0).as_bool()
        }
    }
}

impl Region {
    #[inline]
    unsafe fn from_raw_none(ptr: *mut ffi::cairo_region_t) -> Region {
        assert!(!ptr.is_null());
        ffi::cairo_region_reference(ptr);
        Region(ptr, false)
    }

    #[inline]
    unsafe fn from_raw_borrow(ptr: *mut ffi::cairo_region_t) -> Region {
        assert!(!ptr.is_null());
        Region(ptr, true)
    }

    #[inline]
    unsafe fn from_raw_full(ptr: *mut ffi::cairo_region_t) -> Region {
        assert!(!ptr.is_null());
        Region(ptr, false)
    }

    #[doc(hidden)]
    pub fn to_raw_none(&self) -> *mut ffi::cairo_region_t {
        self.0
    }

    pub fn create() -> Region {
        unsafe {
            Self::from_raw_full(ffi::cairo_region_create())
        }
    }

    pub fn create_rectangle(rectangle: &RectangleInt) -> Region {
        unsafe {
            Self::from_raw_full(ffi::cairo_region_create_rectangle(rectangle.to_raw_none()))
        }
    }

    // pub fn create_rectangles(rectangle: &[&RectangleInt]) -> Region {
    //     unsafe {
    //         Self::from_raw_full(ffi::cairo_region_create_rectangles(rectangle.to_raw_none()))
    //     }
    // }

    pub fn copy(&self) -> Region {
        unsafe {
            Self::from_raw_full(ffi::cairo_region_copy(self.0))
        }
    }

    pub fn status(&self) -> Status {
        unsafe {
            ffi::cairo_region_status(self.0)
        }
    }

    pub fn get_extents(&self, rectangle: &mut RectangleInt) {
        unsafe {
            ffi::cairo_region_get_extents(self.0, rectangle.to_raw_none())
        }
    }

    pub fn num_rectangles(&self) -> i32 {
        unsafe {
            ffi::cairo_region_num_rectangles(self.0)
        }
    }

    pub fn get_rectangle(&self, nth: i32) -> RectangleInt {
        unsafe {
            let rectangle: RectangleInt = ::std::mem::zeroed();
            ffi::cairo_region_get_rectangle(self.0, nth, rectangle.to_raw_none());
            rectangle
        }
    }

    pub fn is_empty(&self) -> bool {
        unsafe {
            ffi::cairo_region_is_empty(self.0).as_bool()
        }
    }

    pub fn contains_point(&self, x: i32, y: i32) -> bool {
        unsafe {
            ffi::cairo_region_contains_point(self.0, x, y).as_bool()
        }
    }

    pub fn contains_rectangle(&self, rectangle: &RectangleInt) -> RegionOverlap {
        unsafe {
            ffi::cairo_region_contains_rectangle(self.0, rectangle.to_raw_none())
        }
    }

    pub fn translate(&self, dx: i32, dy: i32) {
        unsafe {
            ffi::cairo_region_translate(self.0, dx, dy)
        }
    }

    pub fn intersect(&self, other: &Region) -> Status {
        unsafe {
            ffi::cairo_region_intersect(self.0, other.0)
        }
    }

    pub fn intersect_rectangle(&self, rectangle: &RectangleInt) -> Status {
        unsafe {
            ffi::cairo_region_intersect_rectangle(self.0, rectangle.to_raw_none())
        }
    }

    pub fn subtract(&self, other: &Region) -> Status {
        unsafe {
            ffi::cairo_region_subtract(self.0, other.0)
        }
    }

    pub fn subtract_rectangle(&self, rectangle: &RectangleInt) -> Status {
        unsafe {
            ffi::cairo_region_subtract_rectangle(self.0, rectangle.to_raw_none())
        }
    }

    pub fn union(&self, other: &Region) -> Status {
        unsafe {
            ffi::cairo_region_union(self.0, other.0)
        }
    }

    pub fn union_rectangle(&self, rectangle: &RectangleInt) -> Status {
        unsafe {
            ffi::cairo_region_union_rectangle(self.0, rectangle.to_raw_none())
        }
    }

    pub fn xor(&self, other: &Region) -> Status {
        unsafe {
            ffi::cairo_region_xor(self.0, other.0)
        }
    }

    pub fn xor_rectangle(&self, rectangle: &RectangleInt) -> Status {
        unsafe {
            ffi::cairo_region_xor_rectangle(self.0, rectangle.to_raw_none())
        }
    }
}
<commit_msg>Uncomment Region::create_rectangles()<commit_after>// Copyright 2013-2017, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

#[cfg(feature = "use_glib")]
use glib::translate::*;
use ffi::enums::RegionOverlap;
use RectangleInt;
use ffi;

use ffi::cairo_region_t;
use ffi::enums::Status;

pub struct Region(*mut cairo_region_t, bool);

#[cfg(feature = "use_glib")]
#[doc(hidden)]
impl<'a> ToGlibPtr<'a, *mut ffi::cairo_region_t> for &'a Region {
    type Storage = &'a Region;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *mut ffi::cairo_region_t, &'a Region> {
        Stash(self.0, *self)
    }

    #[inline]
    fn to_glib_full(&self) -> *mut ffi::cairo_region_t {
        unsafe {
            ffi::cairo_region_reference(self.0)
        }
    }
}

#[cfg(feature = "use_glib")]
#[doc(hidden)]
impl<'a> ToGlibPtrMut<'a, *mut ffi::cairo_region_t> for Region {
    type Storage = &'a mut Self;

    // FIXME: This is unsafe: regions are reference counted so we could get multiple mutable
    // references here
    #[inline]
    fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::cairo_region_t, Self> {
        StashMut(self.0, self)
    }
}

#[cfg(feature = "use_glib")]
#[doc(hidden)]
impl FromGlibPtrNone<*mut ffi::cairo_region_t> for Region {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut ffi::cairo_region_t) -> Region {
        Self::from_raw_none(ptr)
    }
}

#[cfg(feature = "use_glib")]
#[doc(hidden)]
impl FromGlibPtrBorrow<*mut ffi::cairo_region_t> for Region {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_region_t) -> Region {
        Self::from_raw_borrow(ptr)
    }
}

#[cfg(feature = "use_glib")]
#[doc(hidden)]
impl FromGlibPtrFull<*mut ffi::cairo_region_t> for Region {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut ffi::cairo_region_t) -> Region {
        Self::from_raw_full(ptr)
    }
}

#[cfg(feature = "use_glib")]
gvalue_impl!(Region, ffi::cairo_region_t, ffi::gobject::cairo_gobject_region_get_type);

impl AsRef<Region> for Region {
    fn as_ref(&self) -> &Region {
        self
    }
}

impl Clone for Region {
    fn clone(&self) -> Region {
        unsafe { Self::from_raw_none(self.to_raw_none()) }
    }
}

impl Drop for Region {
    fn drop(&mut self) {
        if !self.1 {
            unsafe { ffi::cairo_region_destroy(self.0); }
        }
    }
}

impl PartialEq for Region {
    fn eq(&self, other: &Region) -> bool {
        unsafe {
            ffi::cairo_region_equal(self.0, other.0).as_bool()
        }
    }
}

impl Region {
    #[inline]
    unsafe fn from_raw_none(ptr: *mut ffi::cairo_region_t) -> Region {
        assert!(!ptr.is_null());
        ffi::cairo_region_reference(ptr);
        Region(ptr, false)
    }

    #[inline]
    unsafe fn from_raw_borrow(ptr: *mut ffi::cairo_region_t) -> Region {
        assert!(!ptr.is_null());
        Region(ptr, true)
    }

    #[inline]
    unsafe fn from_raw_full(ptr: *mut ffi::cairo_region_t) -> Region {
        assert!(!ptr.is_null());
        Region(ptr, false)
    }

    #[doc(hidden)]
    pub fn to_raw_none(&self) -> *mut ffi::cairo_region_t {
        self.0
    }

    pub fn create() -> Region {
        unsafe {
            Self::from_raw_full(ffi::cairo_region_create())
        }
    }

    pub fn create_rectangle(rectangle: &RectangleInt) -> Region {
        unsafe {
            Self::from_raw_full(ffi::cairo_region_create_rectangle(rectangle.to_raw_none()))
        }
    }

    pub fn create_rectangles(rectangles: &[RectangleInt]) -> Region {
        unsafe {
            Self::from_raw_full(ffi::cairo_region_create_rectangles(rectangles.as_ptr() as *mut ffi::cairo_rectangle_int_t, rectangles.len() as i32))
        }
    }

    pub fn copy(&self) -> Region {
        unsafe {
            Self::from_raw_full(ffi::cairo_region_copy(self.0))
        }
    }

    pub fn status(&self) -> Status {
        unsafe {
            ffi::cairo_region_status(self.0)
        }
    }

    pub fn get_extents(&self, rectangle: &mut RectangleInt) {
        unsafe {
            ffi::cairo_region_get_extents(self.0, rectangle.to_raw_none())
        }
    }

    pub fn num_rectangles(&self) -> i32 {
        unsafe {
            ffi::cairo_region_num_rectangles(self.0)
        }
    }

    pub fn get_rectangle(&self, nth: i32) -> RectangleInt {
        unsafe {
            let rectangle: RectangleInt = ::std::mem::zeroed();
            ffi::cairo_region_get_rectangle(self.0, nth, rectangle.to_raw_none());
            rectangle
        }
    }

    pub fn is_empty(&self) -> bool {
        unsafe {
            ffi::cairo_region_is_empty(self.0).as_bool()
        }
    }

    pub fn contains_point(&self, x: i32, y: i32) -> bool {
        unsafe {
            ffi::cairo_region_contains_point(self.0, x, y).as_bool()
        }
    }

    pub fn contains_rectangle(&self, rectangle: &RectangleInt) -> RegionOverlap {
        unsafe {
            ffi::cairo_region_contains_rectangle(self.0, rectangle.to_raw_none())
        }
    }

    pub fn translate(&self, dx: i32, dy: i32) {
        unsafe {
            ffi::cairo_region_translate(self.0, dx, dy)
        }
    }

    pub fn intersect(&self, other: &Region) -> Status {
        unsafe {
            ffi::cairo_region_intersect(self.0, other.0)
        }
    }

    pub fn intersect_rectangle(&self, rectangle: &RectangleInt) -> Status {
        unsafe {
            ffi::cairo_region_intersect_rectangle(self.0, rectangle.to_raw_none())
        }
    }

    pub fn subtract(&self, other: &Region) -> Status {
        unsafe {
            ffi::cairo_region_subtract(self.0, other.0)
        }
    }

    pub fn subtract_rectangle(&self, rectangle: &RectangleInt) -> Status {
        unsafe {
            ffi::cairo_region_subtract_rectangle(self.0, rectangle.to_raw_none())
        }
    }

    pub fn union(&self, other: &Region) -> Status {
        unsafe {
            ffi::cairo_region_union(self.0, other.0)
        }
    }

    pub fn union_rectangle(&self, rectangle: &RectangleInt) -> Status {
        unsafe {
            ffi::cairo_region_union_rectangle(self.0, rectangle.to_raw_none())
        }
    }

    pub fn xor(&self, other: &Region) -> Status {
        unsafe {
            ffi::cairo_region_xor(self.0, other.0)
        }
    }

    pub fn xor_rectangle(&self, rectangle: &RectangleInt) -> Status {
        unsafe {
            ffi::cairo_region_xor_rectangle(self.0, rectangle.to_raw_none())
        }
    }
}
<|endoftext|>


<commit_before>use std::io:: { Error as IOError };
use std::convert::From;
use std::result:: { Result };
use lcov_parser::parser:: { LCOVParser, RecordParseError };
use lcov_parser::record:: { LCOVRecord };

pub enum ParseError {
    IOError(IOError),
    RecordParseError(RecordParseError)
}

impl From<IOError> for ParseError {
    fn from(error: IOError) -> Self {
        ParseError::IOError(error)
    }
}

impl From<RecordParseError> for ParseError {
    fn from(error: RecordParseError) -> Self {
        ParseError::RecordParseError(error)
    }
}

pub fn records_from_file(file: &str) -> Result<Vec<LCOVRecord>, ParseError> {
    let parser = try!(LCOVParser::from_file(file));
    Ok(try!(parser.parse()))
}
<commit_msg>add current test name<commit_after>use std::io:: { Error as IOError };
use std::convert::From;
use std::result:: { Result };
use lcov_parser::parser:: { LCOVParser, RecordParseError };
use lcov_parser::record:: { LCOVRecord };

pub enum ParseError {
    IOError(IOError),
    RecordParseError(RecordParseError)
}

impl From<IOError> for ParseError {
    fn from(error: IOError) -> Self {
        ParseError::IOError(error)
    }
}

impl From<RecordParseError> for ParseError {
    fn from(error: RecordParseError) -> Self {
        ParseError::RecordParseError(error)
    }
}

pub fn records_from_file(file: &str) -> Result<Vec<LCOVRecord>, ParseError> {
    let parser = try!(LCOVParser::from_file(file));
    Ok(try!(parser.parse()))
}

struct ReportParser {
    test_name: Option<String>
}

impl ReportParser {
    fn parse(&mut self, file: &str) -> Result<(), ParseError> {
        let records = try!(records_from_file(file));

        for record in records.iter() {
            match record {
                &LCOVRecord::TestName(ref name) => self.test_name = name.clone(),
                _ => { continue; }
            };
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::error::Error;
use std::fmt;

use iron::{Request, Response, Handler, IronResult, IronError};
use iron::{status, method, headers};
use iron::typemap::Key;
use iron::modifiers::Redirect;

use recognizer::Router as Recognizer;
use recognizer::{Match, Params};

/// `Router` provides an interface for creating complex routes as middleware
/// for the Iron framework.
pub struct Router {
    // The routers, specialized by method.
    routers: HashMap<method::Method, Recognizer<Box<Handler>>>
}

impl Router {
    /// Construct a new, empty `Router`.
    ///
    /// ```
    /// # use router::Router;
    /// let router = Router::new();
    /// ```
    pub fn new() -> Router {
        Router {
            routers: HashMap::new()
        }
    }

    /// Add a new route to a `Router`, matching both a method and glob pattern.
    ///
    /// `route` supports glob patterns: `*` for a single wildcard segment and
    /// `:param` for matching storing that segment of the request url in the `Params`
    /// object, which is stored in the request `extensions`.
    ///
    /// For instance, to route `Get` requests on any route matching
    /// `/users/:userid/:friend` and store `userid` and `friend` in
    /// the exposed Params object:
    ///
    /// ```ignore
    /// # use iron::method;
    /// router.route(method::Get, "/users/:userid/:friendid", controller);
    /// ```
    ///
    /// The controller provided to route can be any `Handler`, which allows
    /// extreme flexibility when handling routes. For instance, you could provide
    /// a `Chain`, a `Handler`, which contains an authorization middleware and
    /// a controller function, so that you can confirm that the request is
    /// authorized for this route before handling it.
    pub fn route<H, S>(&mut self, method: method::Method,
                       glob: S, handler: H) -> &mut Router
    where H: Handler, S: Str {
        match self.routers.entry(method) {
            Vacant(entry)   => entry.insert(Recognizer::new()),
            Occupied(entry) => entry.into_mut()
        }.add(glob.as_slice().trim_right_matches('/'),
              Box::new(handler) as Box<Handler>);
        self
    }

    /// Like route, but specialized to the `Get` method.
    pub fn get<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Get, glob, handler)
    }

    /// Like route, but specialized to the `Post` method.
    pub fn post<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Post, glob, handler)
    }

    /// Like route, but specialized to the `Put` method.
    pub fn put<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Put, glob, handler)
    }

    /// Like route, but specialized to the `Delete` method.
    pub fn delete<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Delete, glob, handler)
    }

    /// Like route, but specialized to the `Head` method.
    pub fn head<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Head, glob, handler)
    }

    /// Like route, but specialized to the `Patch` method.
    pub fn patch<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Patch, glob, handler)
    }

    /// Like route, but specialized to the `Options` method.
    pub fn options<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Options, glob, handler)
    }

    fn recognize<'a>(&'a self, method: &method::Method, path: &str)
                     -> Option<Match<&'a Box<Handler>>> {
        self.routers.get(method).and_then(|router| router.recognize(path).ok())
    }

    fn handle_options(&self, req: &mut Request, path: &str) -> IronResult<Response> {
        static METHODS: &'static [method::Method] =
            &[method::Get, method::Post, method::Post, method::Put,
              method::Delete, method::Head, method::Patch];

        // If there is an override, use it.
        if let Some(matched) = self.recognize(&method::Options, path) {
            req.extensions.insert::<Router>(matched.params);
            return matched.handler.handle(req);
        }

        // Else, get all the available methods and return them.
        let mut options = vec![];

        for method in METHODS.iter() {
            self.routers.get(method).map(|router| {
                if let Some(_) = router.recognize(path).ok() {
                    options.push(method.clone());
                }
            });
        }

        let mut res = Response::with(status::Ok);
        res.headers.set(headers::Allow(options));
        Ok(res)
    }

    fn handle_trailing_slash(&self, req: &mut Request) -> IronResult<Response> {
        let mut url_no_trailing_slash = req.url.clone();
        url_no_trailing_slash.path.pop();

        Err(IronError {
            error: Box::new(TrailingSlash),
            response: Response::with(
                (status::MovedPermanently, Redirect(url_no_trailing_slash))
            )
        })
    }

    fn handle_method(&self, req: &mut Request, path: &str) -> IronResult<Response> {
        let matched = match self.recognize(&req.method, path) {
            Some(matched) => matched,
            // No match.
            None => return Err(IronError {
                error: Box::new(NoRoute),
                response: Response::with(status::NotFound)
            })
        };

        req.extensions.insert::<Router>(matched.params);
        matched.handler.handle(req)
    }
}

impl Key for Router { type Value = Params; }

impl Handler for Router {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        if req.url.path.len() != 1 && Some(&String::new()) == req.url.path.last() {
            return self.handle_trailing_slash(req);
        }

        // No trailing slash
        let path = req.url.path.connect("/");

        if let method::Options = req.method {
            return self.handle_options(req, &*path);
        }

        self.handle_method(req, &*path)
    }
}

/// The error thrown by router if there is no matching route,
/// it is always accompanied by a NotFound response.
#[derive(Debug)]
pub struct NoRoute;

impl fmt::Display for NoRoute {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("No matching route found.")
    }
}

impl Error for NoRoute {
    fn description(&self) -> &str { "No Route" }
}

/// The error thrown by router if the request had a trailing slash,
/// it is always accompanied by a redirect.
#[derive(Debug)]
pub struct TrailingSlash;

impl fmt::Display for TrailingSlash {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("The request had a trailing slash.")
    }
}

impl Error for TrailingSlash {
    fn description(&self) -> &str { "Trailing Slash" }
}

<commit_msg>(chore) Code cleanup.<commit_after>use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::error::Error;
use std::fmt;

use iron::{Request, Response, Handler, IronResult, IronError};
use iron::{status, method, headers};
use iron::typemap::Key;
use iron::modifiers::Redirect;

use recognizer::Router as Recognizer;
use recognizer::{Match, Params};

/// `Router` provides an interface for creating complex routes as middleware
/// for the Iron framework.
pub struct Router {
    // The routers, specialized by method.
    routers: HashMap<method::Method, Recognizer<Box<Handler>>>
}

impl Router {
    /// Construct a new, empty `Router`.
    ///
    /// ```
    /// # use router::Router;
    /// let router = Router::new();
    /// ```
    pub fn new() -> Router {
        Router {
            routers: HashMap::new()
        }
    }

    /// Add a new route to a `Router`, matching both a method and glob pattern.
    ///
    /// `route` supports glob patterns: `*` for a single wildcard segment and
    /// `:param` for matching storing that segment of the request url in the `Params`
    /// object, which is stored in the request `extensions`.
    ///
    /// For instance, to route `Get` requests on any route matching
    /// `/users/:userid/:friend` and store `userid` and `friend` in
    /// the exposed Params object:
    ///
    /// ```ignore
    /// let mut router = Router::new();
    /// router.route(method::Get, "/users/:userid/:friendid", controller);
    /// ```
    ///
    /// The controller provided to route can be any `Handler`, which allows
    /// extreme flexibility when handling routes. For instance, you could provide
    /// a `Chain`, a `Handler`, which contains an authorization middleware and
    /// a controller function, so that you can confirm that the request is
    /// authorized for this route before handling it.
    pub fn route<H, S>(&mut self, method: method::Method,
                       glob: S, handler: H) -> &mut Router
    where H: Handler, S: Str {
        match self.routers.entry(method) {
            Vacant(entry)   => entry.insert(Recognizer::new()),
            Occupied(entry) => entry.into_mut()
        }.add(glob.as_slice().trim_right_matches('/'),
              Box::new(handler) as Box<Handler>);
        self
    }

    /// Like route, but specialized to the `Get` method.
    pub fn get<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Get, glob, handler)
    }

    /// Like route, but specialized to the `Post` method.
    pub fn post<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Post, glob, handler)
    }

    /// Like route, but specialized to the `Put` method.
    pub fn put<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Put, glob, handler)
    }

    /// Like route, but specialized to the `Delete` method.
    pub fn delete<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Delete, glob, handler)
    }

    /// Like route, but specialized to the `Head` method.
    pub fn head<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Head, glob, handler)
    }

    /// Like route, but specialized to the `Patch` method.
    pub fn patch<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Patch, glob, handler)
    }

    /// Like route, but specialized to the `Options` method.
    pub fn options<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Options, glob, handler)
    }

    fn recognize<'a>(&'a self, method: &method::Method, path: &str)
                     -> Option<Match<&'a Box<Handler>>> {
        self.routers.get(method).and_then(|router| router.recognize(path).ok())
    }

    fn handle_options(&self, req: &mut Request, path: &str) -> IronResult<Response> {
        static METHODS: &'static [method::Method] =
            &[method::Get, method::Post, method::Post, method::Put,
              method::Delete, method::Head, method::Patch];

        // If there is an override, use it.
        if let Some(matched) = self.recognize(&method::Options, path) {
            req.extensions.insert::<Router>(matched.params);
            return matched.handler.handle(req);
        }

        // Else, get all the available methods and return them.
        let mut options = vec![];

        for method in METHODS.iter() {
            self.routers.get(method).map(|router| {
                if let Some(_) = router.recognize(path).ok() {
                    options.push(method.clone());
                }
            });
        }

        let mut res = Response::with(status::Ok);
        res.headers.set(headers::Allow(options));
        Ok(res)
    }

    fn handle_trailing_slash(&self, req: &mut Request) -> IronResult<Response> {
        let mut url = req.url.clone();

        // Pull off as many trailing slashes as possible.
        while url.path.len() != 1 && url.path.last() == Some(&String::new()) {
            url.path.pop();
        }

        Err(IronError::new(TrailingSlash, (status::MovedPermanently, Redirect(url))))
    }

    fn handle_method(&self, req: &mut Request, path: &str) -> IronResult<Response> {
        let matched = match self.recognize(&req.method, path) {
            Some(matched) => matched,
            // No match.
            None => return Err(IronError::new(NoRoute, status::NotFound))
        };

        req.extensions.insert::<Router>(matched.params);
        matched.handler.handle(req)
    }
}

impl Key for Router { type Value = Params; }

impl Handler for Router {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        if req.url.path.len() != 1 && Some(&String::new()) == req.url.path.last() {
            return self.handle_trailing_slash(req);
        }

        // No trailing slash
        let path = req.url.path.connect("/");

        if let method::Options = req.method {
            return self.handle_options(req, &*path);
        }

        self.handle_method(req, &*path)
    }
}

/// The error thrown by router if there is no matching route,
/// it is always accompanied by a NotFound response.
#[derive(Debug)]
pub struct NoRoute;

impl fmt::Display for NoRoute {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("No matching route found.")
    }
}

impl Error for NoRoute {
    fn description(&self) -> &str { "No Route" }
}

/// The error thrown by router if the request had a trailing slash,
/// it is always accompanied by a redirect.
#[derive(Debug)]
pub struct TrailingSlash;

impl fmt::Display for TrailingSlash {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("The request had a trailing slash.")
    }
}

impl Error for TrailingSlash {
    fn description(&self) -> &str { "Trailing Slash" }
}

<|endoftext|>


<commit_before>use std::convert::From;
use std::env;
use std::error::Error;
use std::fmt;
use std::io::{Result as IoResult, Error as IoError};
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::process;
use mozprofile::profile::Profile;
use mozprofile::prefdata::FIREFOX_PREFERENCES;
use mozprofile::prefreader::PrefReaderError;

pub trait Runner {
    fn start(&mut self) -> Result<(), RunnerError>;

    fn args(&mut self) -> &mut Vec<String>;

    fn build_command(&self, &mut Command);

    fn is_running(&self) -> bool;

    fn stop(&mut self) -> IoResult<Option<process::ExitStatus>>;
}

#[derive(Debug)]
pub enum RunnerError {
    Io(IoError),
    PrefReader(PrefReaderError)
}

impl fmt::Display for RunnerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.description().fmt(f)
    }
}

impl Error for RunnerError {
    fn description(&self) -> &str {
        match *self {
            RunnerError::Io(ref err) => err.description().clone(),
            RunnerError::PrefReader(ref err) => err.description().clone(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            RunnerError::Io(ref err) => err.cause(),
            RunnerError::PrefReader(ref err) => err.cause(),
        }
    }
}

impl From<IoError> for RunnerError {
    fn from(value: IoError) -> RunnerError {
        RunnerError::Io(value)
    }
}

impl From<PrefReaderError> for RunnerError {
    fn from(value: PrefReaderError) -> RunnerError {
        RunnerError::PrefReader(value)
    }
}

pub struct FirefoxRunner {
    pub binary: PathBuf,
    args: Vec<String>,
    process: Option<process::Child>,
    pub ret_code: Option<process::ExitStatus>,
    pub profile: Profile
}

impl FirefoxRunner {
    pub fn new(binary: &Path, profile: Option<Profile>) -> IoResult<FirefoxRunner> {
        let prof = match profile {
            Some(p) => p,
            None => try!(Profile::new(None))
        };

        Ok(FirefoxRunner {
            binary: binary.to_path_buf(),
            process: None,
            ret_code: None,
            args: Vec::new(),
            profile: prof
        })
    }
}

impl Runner for FirefoxRunner {
    fn start(&mut self) -> Result<(), RunnerError> {
        let mut cmd = Command::new(&self.binary);
        self.build_command(&mut cmd);

        let mut prefs = try!(self.profile.user_prefs());
        prefs.insert_slice(&FIREFOX_PREFERENCES[..]);

        try!(prefs.write());

        let process = try!(cmd.spawn());
        self.process = Some(process);
        Ok(())
    }

    fn args(&mut self) -> &mut Vec<String> {
        &mut self.args
    }

    fn build_command(&self, command: &mut Command) {
        command.args(&self.args[..]).arg("--marionette").arg("--profile").arg(&self.profile.path)
            .stdout(Stdio::inherit()).stderr(Stdio::inherit())
            .env("MOZ_NO_REMOTE", "1").env("NO_EM_RESTART", "1");
    }

    fn is_running(&self) -> bool {
        self.process.is_some() && self.ret_code.is_none()
    }

    fn stop(&mut self) -> IoResult<Option<process::ExitStatus>> {
        match self.process.as_mut() {
            Some(p) => {
                try!(p.kill());
                let status = try!(p.wait());
                self.ret_code = Some(status);
            },
            None => {}
        };
        Ok(self.ret_code)
    }
}

fn find_binary(name: &str) -> Option<PathBuf> {
    env::var("PATH")
        .ok()
        .and_then(|path_env| {
            for mut path in env::split_paths(&*path_env) {
                path.push(name);
                if path.exists() {
                    return Some(path)
                }
            }
            None
        })
}

#[cfg(target_os = "linux")]
pub mod platform {
    use super::find_binary;
    use std::path::PathBuf;

    pub fn firefox_default_path() -> Option<PathBuf> {
        find_binary("firefox")
    }
}

#[cfg(target_os = "macos")]
pub mod platform {
    use super::find_binary;
    use std::env;
    use std::path::PathBuf;

    pub fn firefox_default_path() -> Option<PathBuf> {
        let home = env::home_dir();
        for &(prefix_home, trial_path) in [
            (false, "/Applications/Firefox.app/Contents/MacOS/firefox-bin"),
            (true, "Applications/Firefox.app/Contents/MacOS/firefox-bin")].iter() {
            let path = match (home.as_ref(), prefix_home) {
                (Some(ref home_dir), true) => home_dir.join(trial_path),
                (None, true) => continue,
                (_, false) => PathBuf::from(trial_path)
            };
            if path.exists() {
                return Some(path)
            }
        }
        find_binary("firefox-bin")
    }
}

#[cfg(target_os = "windows")]
pub mod platform {
    use super::find_binary;
    use std::io::Error;
    use std::path::PathBuf;
    use winreg::RegKey;
    use winreg::enums::*;

    pub fn firefox_default_path() -> Option<PathBuf> {
        let opt_path = firefox_registry_path().unwrap_or(None);
        if let Some(path) = opt_path {
            if path.exists() {
                return Some(path)
            }
        };
        find_binary("firefox.exe")
    }

    fn firefox_registry_path() -> Result<Option<PathBuf>, Error> {
        let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
        for subtree_key in ["SOFTWARE", "SOFTWARE\\WOW6432Node"].iter() {
            let subtree = try!(hklm.open_subkey_with_flags(subtree_key, KEY_READ));
            let mozilla_org = try!(subtree.open_subkey_with_flags("mozilla.org\\Mozilla", KEY_READ));
            let current_version: String = try!(mozilla_org.get_value("CurrentVersion"));
            let mozilla = try!(subtree.open_subkey_with_flags("Mozilla", KEY_READ));
            for key_res in mozilla.enum_keys() {
                let key = try!(key_res);
                let section_data = try!(mozilla.open_subkey_with_flags(&key, KEY_READ));
                let version: Result<String, _> = section_data.get_value("GeckoVer");
                if let Ok(ver) = version {
                    if ver == current_version {
                        let mut bin_key = key.to_owned();
                        bin_key.push_str("\\bin");
                        if let Ok(bin_subtree) = mozilla.open_subkey_with_flags(bin_key, KEY_READ) {
                            let path: Result<String, _> = bin_subtree.get_value("PathToExe");
                            if let Ok(path) = path {
                                return Ok(Some(PathBuf::from(path)))
                            }
                        }
                    }
                }
            }
        }
        Ok(None)
    }
}

#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
pub mod platform {
    use std::path::PathBuf;

    pub fn firefox_default_path() -> Option<PathBuf> {
        None
    }
}
<commit_msg>runner: improve description when entity is not found (#2)<commit_after>use mozprofile::prefdata::FIREFOX_PREFERENCES;
use mozprofile::prefreader::PrefReaderError;
use mozprofile::profile::Profile;
use std::convert::From;
use std::env;
use std::error::Error;
use std::fmt;
use std::io::{Result as IoResult, Error as IoError, ErrorKind};
use std::path::{Path, PathBuf};
use std::process;
use std::process::{Command, Stdio};

pub trait Runner {
    fn start(&mut self) -> Result<(), RunnerError>;

    fn args(&mut self) -> &mut Vec<String>;

    fn build_command(&self, &mut Command);

    fn is_running(&self) -> bool;

    fn stop(&mut self) -> IoResult<Option<process::ExitStatus>>;
}

#[derive(Debug)]
pub enum RunnerError {
    Io(IoError),
    PrefReader(PrefReaderError),
}

impl fmt::Display for RunnerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.description().fmt(f)
    }
}

impl Error for RunnerError {
    fn description(&self) -> &str {
        match *self {
            RunnerError::Io(ref err) => {
                match err.kind() {
                    ErrorKind::NotFound => "no such file or directory",
                    _ => err.description(),
                }
            }
            RunnerError::PrefReader(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        Some(match *self {
            RunnerError::Io(ref err) => err as &Error,
            RunnerError::PrefReader(ref err) => err as &Error,
        })
    }
}

impl From<IoError> for RunnerError {
    fn from(value: IoError) -> RunnerError {
        RunnerError::Io(value)
    }
}

impl From<PrefReaderError> for RunnerError {
    fn from(value: PrefReaderError) -> RunnerError {
        RunnerError::PrefReader(value)
    }
}

pub struct FirefoxRunner {
    pub binary: PathBuf,
    args: Vec<String>,
    process: Option<process::Child>,
    pub ret_code: Option<process::ExitStatus>,
    pub profile: Profile
}

impl FirefoxRunner {
    pub fn new(binary: &Path, profile: Option<Profile>) -> IoResult<FirefoxRunner> {
        let prof = match profile {
            Some(p) => p,
            None => try!(Profile::new(None))
        };

        Ok(FirefoxRunner {
            binary: binary.to_path_buf(),
            process: None,
            ret_code: None,
            args: Vec::new(),
            profile: prof
        })
    }
}

impl Runner for FirefoxRunner {
    fn start(&mut self) -> Result<(), RunnerError> {
        let mut cmd = Command::new(&self.binary);
        self.build_command(&mut cmd);

        let mut prefs = try!(self.profile.user_prefs());
        prefs.insert_slice(&FIREFOX_PREFERENCES[..]);

        try!(prefs.write());

        let process = try!(cmd.spawn());
        self.process = Some(process);
        Ok(())
    }

    fn args(&mut self) -> &mut Vec<String> {
        &mut self.args
    }

    fn build_command(&self, command: &mut Command) {
        command.args(&self.args[..]).arg("--marionette").arg("--profile").arg(&self.profile.path)
            .stdout(Stdio::inherit()).stderr(Stdio::inherit())
            .env("MOZ_NO_REMOTE", "1").env("NO_EM_RESTART", "1");
    }

    fn is_running(&self) -> bool {
        self.process.is_some() && self.ret_code.is_none()
    }

    fn stop(&mut self) -> IoResult<Option<process::ExitStatus>> {
        match self.process.as_mut() {
            Some(p) => {
                try!(p.kill());
                let status = try!(p.wait());
                self.ret_code = Some(status);
            },
            None => {}
        };
        Ok(self.ret_code)
    }
}

fn find_binary(name: &str) -> Option<PathBuf> {
    env::var("PATH")
        .ok()
        .and_then(|path_env| {
            for mut path in env::split_paths(&*path_env) {
                path.push(name);
                if path.exists() {
                    return Some(path)
                }
            }
            None
        })
}

#[cfg(target_os = "linux")]
pub mod platform {
    use super::find_binary;
    use std::path::PathBuf;

    pub fn firefox_default_path() -> Option<PathBuf> {
        find_binary("firefox")
    }
}

#[cfg(target_os = "macos")]
pub mod platform {
    use super::find_binary;
    use std::env;
    use std::path::PathBuf;

    pub fn firefox_default_path() -> Option<PathBuf> {
        let home = env::home_dir();
        for &(prefix_home, trial_path) in [
            (false, "/Applications/Firefox.app/Contents/MacOS/firefox-bin"),
            (true, "Applications/Firefox.app/Contents/MacOS/firefox-bin")].iter() {
            let path = match (home.as_ref(), prefix_home) {
                (Some(ref home_dir), true) => home_dir.join(trial_path),
                (None, true) => continue,
                (_, false) => PathBuf::from(trial_path)
            };
            if path.exists() {
                return Some(path)
            }
        }
        find_binary("firefox-bin")
    }
}

#[cfg(target_os = "windows")]
pub mod platform {
    use super::find_binary;
    use std::io::Error;
    use std::path::PathBuf;
    use winreg::RegKey;
    use winreg::enums::*;

    pub fn firefox_default_path() -> Option<PathBuf> {
        let opt_path = firefox_registry_path().unwrap_or(None);
        if let Some(path) = opt_path {
            if path.exists() {
                return Some(path)
            }
        };
        find_binary("firefox.exe")
    }

    fn firefox_registry_path() -> Result<Option<PathBuf>, Error> {
        let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
        for subtree_key in ["SOFTWARE", "SOFTWARE\\WOW6432Node"].iter() {
            let subtree = try!(hklm.open_subkey_with_flags(subtree_key, KEY_READ));
            let mozilla_org = try!(subtree.open_subkey_with_flags("mozilla.org\\Mozilla", KEY_READ));
            let current_version: String = try!(mozilla_org.get_value("CurrentVersion"));
            let mozilla = try!(subtree.open_subkey_with_flags("Mozilla", KEY_READ));
            for key_res in mozilla.enum_keys() {
                let key = try!(key_res);
                let section_data = try!(mozilla.open_subkey_with_flags(&key, KEY_READ));
                let version: Result<String, _> = section_data.get_value("GeckoVer");
                if let Ok(ver) = version {
                    if ver == current_version {
                        let mut bin_key = key.to_owned();
                        bin_key.push_str("\\bin");
                        if let Ok(bin_subtree) = mozilla.open_subkey_with_flags(bin_key, KEY_READ) {
                            let path: Result<String, _> = bin_subtree.get_value("PathToExe");
                            if let Ok(path) = path {
                                return Ok(Some(PathBuf::from(path)))
                            }
                        }
                    }
                }
            }
        }
        Ok(None)
    }
}

#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
pub mod platform {
    use std::path::PathBuf;

    pub fn firefox_default_path() -> Option<PathBuf> {
        None
    }
}
<|endoftext|>


<commit_before>use crate::{
    errors::{serialize::DeError, Error},
    events::{BytesEnd, BytesStart, Event},
    se::Serializer,
    writer::Writer,
};
use serde::ser::{self, Serialize};
use std::io::Write;

/// An implementation of `SerializeMap` for serializing to XML.
pub struct Map<'r, 'w, W>
where
    W: 'w + Write,
{
    parent: &'w mut Serializer<'r, W>,
}

impl<'r, 'w, W> Map<'r, 'w, W>
where
    W: 'w + Write,
{
    /// Create a new Map
    pub fn new(parent: &'w mut Serializer<'r, W>) -> Self {
        Map { parent }
    }
}

impl<'r, 'w, W> ser::SerializeMap for Map<'r, 'w, W>
where
    W: 'w + Write,
{
    type Ok = ();
    type Error = DeError;

    fn serialize_key<T: ?Sized + Serialize>(&mut self, _: &T) -> Result<(), DeError> {
        Err(DeError::Unsupported(
            "impossible to serialize the key on its own, please use serialize_entry()",
        ))
    }

    fn serialize_value<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<(), DeError> {
        value.serialize(&mut *self.parent)
    }

    fn end(self) -> Result<Self::Ok, DeError> {
        if let Some(tag) = self.parent.root_tag {
            self.parent
                .writer
                .write_event(Event::End(BytesEnd::borrowed(tag.as_bytes())))?;
        }
        Ok(())
    }

    fn serialize_entry<K: ?Sized + Serialize, V: ?Sized + Serialize>(
        &mut self,
        key: &K,
        value: &V,
    ) -> Result<(), DeError> {
        // TODO: Is it possible to ensure our key is never a composite type?
        // Anything which isn't a "primitive" would lead to malformed XML here...
        write!(self.parent.writer.inner(), "<").map_err(Error::Io)?;
        key.serialize(&mut *self.parent)?;
        write!(self.parent.writer.inner(), ">").map_err(Error::Io)?;

        value.serialize(&mut *self.parent)?;

        write!(self.parent.writer.inner(), "</").map_err(Error::Io)?;
        key.serialize(&mut *self.parent)?;
        write!(self.parent.writer.inner(), ">").map_err(Error::Io)?;
        Ok(())
    }
}

/// An implementation of `SerializeStruct` for serializing to XML.
pub struct Struct<'r, 'w, W>
where
    W: 'w + Write,
{
    parent: &'w mut Serializer<'r, W>,
    /// Buffer for holding fields, serialized as attributes. Doesn't allocate
    /// if there are no fields represented as attributes
    attrs: BytesStart<'w>,
    /// Buffer for holding fields, serialized as elements
    children: Vec<u8>,
    /// Buffer for serializing one field. Cleared after serialize each field
    buffer: Vec<u8>,
}

impl<'r, 'w, W> Struct<'r, 'w, W>
where
    W: 'w + Write,
{
    /// Create a new `Struct`
    pub fn new(parent: &'w mut Serializer<'r, W>, name: &'r str) -> Self {
        let name = name.as_bytes();
        Struct {
            parent,
            attrs: BytesStart::borrowed_name(name),
            children: Vec::new(),
            buffer: Vec::new(),
        }
    }
}

impl<'r, 'w, W> ser::SerializeStruct for Struct<'r, 'w, W>
where
    W: 'w + Write,
{
    type Ok = ();
    type Error = DeError;

    fn serialize_field<T: ?Sized + Serialize>(
        &mut self,
        key: &'static str,
        value: &T,
    ) -> Result<(), DeError> {
        // TODO: Inherit indentation state from self.parent.writer
        let writer = Writer::new(&mut self.buffer);
        let mut serializer = Serializer::with_root(writer, Some(key));
        value.serialize(&mut serializer)?;

        if !self.buffer.is_empty() {
            if self.buffer[0] == b'<' {
                // Drains buffer, moves it to children
                self.children.append(&mut self.buffer);
            } else {
                self.attrs.push_attribute((key.as_bytes(), self.buffer.as_ref()));
                self.buffer.clear();
            }
        }

        Ok(())
    }

    fn end(self) -> Result<Self::Ok, DeError> {
        if self.children.is_empty() {
            self.parent.writer.write_event(Event::Empty(self.attrs))?;
        } else {
            self.parent.writer.write_event(Event::Start(self.attrs.to_borrowed()))?;
            self.parent.writer.write(&self.children)?;
            self.parent.writer.write_event(Event::End(self.attrs.to_end()))?;
        }
        Ok(())
    }
}

impl<'r, 'w, W> ser::SerializeStructVariant for Struct<'r, 'w, W>
where
    W: 'w + Write,
{
    type Ok = ();
    type Error = DeError;

    #[inline]
    fn serialize_field<T: ?Sized + Serialize>(
        &mut self,
        key: &'static str,
        value: &T,
    ) -> Result<(), Self::Error> {
        <Self as ser::SerializeStruct>::serialize_field(self, key, value)
    }

    #[inline]
    fn end(self) -> Result<Self::Ok, Self::Error> {
        <Self as ser::SerializeStruct>::end(self)
    }
}

/// An implementation of `SerializeSeq' for serializing to XML.
pub struct Seq<'r, 'w, W>
where
    W: 'w + Write,
{
    parent: &'w mut Serializer<'r, W>,
}

impl<'r, 'w, W> Seq<'r, 'w, W>
where
    W: 'w + Write,
{
    /// Create a new `Seq`
    pub fn new(parent: &'w mut Serializer<'r, W>) -> Self {
        Seq { parent }
    }
}

impl<'r, 'w, W> ser::SerializeSeq for Seq<'r, 'w, W>
where
    W: 'w + Write,
{
    type Ok = ();
    type Error = DeError;

    fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: Serialize,
    {
        value.serialize(&mut *self.parent)?;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        Ok(())
    }
}

/// An implementation of `SerializeTuple`, `SerializeTupleStruct` and
/// `SerializeTupleVariant` for serializing to XML.
pub struct Tuple<'r, 'w, W>
where
    W: 'w + Write,
{
    parent: &'w mut Serializer<'r, W>,
    /// Possible qualified name of XML tag surrounding each element
    name: &'r str,
}

impl<'r, 'w, W> Tuple<'r, 'w, W>
where
    W: 'w + Write,
{
    /// Create a new `Tuple`
    pub fn new(parent: &'w mut Serializer<'r, W>, name: &'r str) -> Self {
        Tuple { parent, name }
    }
}

impl<'r, 'w, W> ser::SerializeTuple for Tuple<'r, 'w, W>
where
    W: 'w + Write,
{
    type Ok = ();
    type Error = DeError;

    fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: Serialize
    {
        write!(self.parent.writer.inner(), "<{}>", self.name).map_err(Error::Io)?;
        value.serialize(&mut *self.parent)?;
        write!(self.parent.writer.inner(), "</{}>", self.name).map_err(Error::Io)?;
        Ok(())
    }

    #[inline]
    fn end(self) -> Result<Self::Ok, Self::Error> {
        Ok(())
    }
}

impl<'r, 'w, W> ser::SerializeTupleStruct for Tuple<'r, 'w, W>
where
    W: 'w + Write,
{
    type Ok = ();
    type Error = DeError;

    #[inline]
    fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: Serialize
    {
        <Self as ser::SerializeTuple>::serialize_element(self, value)
    }

    #[inline]
    fn end(self) -> Result<Self::Ok, Self::Error> {
        <Self as ser::SerializeTuple>::end(self)
    }
}

impl<'r, 'w, W> ser::SerializeTupleVariant for Tuple<'r, 'w, W>
where
    W: 'w + Write,
{
    type Ok = ();
    type Error = DeError;

    #[inline]
    fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: Serialize
    {
        <Self as ser::SerializeTuple>::serialize_element(self, value)
    }

    #[inline]
    fn end(self) -> Result<Self::Ok, Self::Error> {
        <Self as ser::SerializeTuple>::end(self)
    }
}
<commit_msg>serialize a key as <key/> instead of aborting as an error<commit_after>use crate::{
    errors::{serialize::DeError, Error},
    events::{BytesEnd, BytesStart, Event},
    se::Serializer,
    writer::Writer,
};
use serde::ser::{self, Serialize};
use std::io::Write;

/// An implementation of `SerializeMap` for serializing to XML.
pub struct Map<'r, 'w, W>
where
    W: 'w + Write,
{
    parent: &'w mut Serializer<'r, W>,
}

impl<'r, 'w, W> Map<'r, 'w, W>
where
    W: 'w + Write,
{
    /// Create a new Map
    pub fn new(parent: &'w mut Serializer<'r, W>) -> Self {
        Map { parent }
    }
}

impl<'r, 'w, W> ser::SerializeMap for Map<'r, 'w, W>
where
    W: 'w + Write,
{
    type Ok = ();
    type Error = DeError;

    fn serialize_key<T: ?Sized + Serialize>(&mut self, key: &T) -> Result<(), DeError> {
        // Err(DeError::Unsupported(
        //    "impossible to serialize the key on its own, please use serialize_entry()",
        //))
        write!(self.parent.writer.inner(), "<").map_err(Error::Io)?;
        key.serialize(&mut *self.parent)?;
        write!(self.parent.writer.inner(), "/>").map_err(Error::Io)?;
        Ok(())
    }

    fn serialize_value<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<(), DeError> {
        value.serialize(&mut *self.parent)
    }

    fn end(self) -> Result<Self::Ok, DeError> {
        if let Some(tag) = self.parent.root_tag {
            self.parent
                .writer
                .write_event(Event::End(BytesEnd::borrowed(tag.as_bytes())))?;
        }
        Ok(())
    }

    fn serialize_entry<K: ?Sized + Serialize, V: ?Sized + Serialize>(
        &mut self,
        key: &K,
        value: &V,
    ) -> Result<(), DeError> {
        // TODO: Is it possible to ensure our key is never a composite type?
        // Anything which isn't a "primitive" would lead to malformed XML here...
        write!(self.parent.writer.inner(), "<").map_err(Error::Io)?;
        key.serialize(&mut *self.parent)?;
        write!(self.parent.writer.inner(), ">").map_err(Error::Io)?;

        value.serialize(&mut *self.parent)?;

        write!(self.parent.writer.inner(), "</").map_err(Error::Io)?;
        key.serialize(&mut *self.parent)?;
        write!(self.parent.writer.inner(), ">").map_err(Error::Io)?;
        Ok(())
    }
}

/// An implementation of `SerializeStruct` for serializing to XML.
pub struct Struct<'r, 'w, W>
where
    W: 'w + Write,
{
    parent: &'w mut Serializer<'r, W>,
    /// Buffer for holding fields, serialized as attributes. Doesn't allocate
    /// if there are no fields represented as attributes
    attrs: BytesStart<'w>,
    /// Buffer for holding fields, serialized as elements
    children: Vec<u8>,
    /// Buffer for serializing one field. Cleared after serialize each field
    buffer: Vec<u8>,
}

impl<'r, 'w, W> Struct<'r, 'w, W>
where
    W: 'w + Write,
{
    /// Create a new `Struct`
    pub fn new(parent: &'w mut Serializer<'r, W>, name: &'r str) -> Self {
        let name = name.as_bytes();
        Struct {
            parent,
            attrs: BytesStart::borrowed_name(name),
            children: Vec::new(),
            buffer: Vec::new(),
        }
    }
}

impl<'r, 'w, W> ser::SerializeStruct for Struct<'r, 'w, W>
where
    W: 'w + Write,
{
    type Ok = ();
    type Error = DeError;

    fn serialize_field<T: ?Sized + Serialize>(
        &mut self,
        key: &'static str,
        value: &T,
    ) -> Result<(), DeError> {
        // TODO: Inherit indentation state from self.parent.writer
        let writer = Writer::new(&mut self.buffer);
        let mut serializer = Serializer::with_root(writer, Some(key));
        value.serialize(&mut serializer)?;

        if !self.buffer.is_empty() {
            if self.buffer[0] == b'<' {
                // Drains buffer, moves it to children
                self.children.append(&mut self.buffer);
            } else {
                self.attrs.push_attribute((key.as_bytes(), self.buffer.as_ref()));
                self.buffer.clear();
            }
        }

        Ok(())
    }

    fn end(self) -> Result<Self::Ok, DeError> {
        if self.children.is_empty() {
            self.parent.writer.write_event(Event::Empty(self.attrs))?;
        } else {
            self.parent.writer.write_event(Event::Start(self.attrs.to_borrowed()))?;
            self.parent.writer.write(&self.children)?;
            self.parent.writer.write_event(Event::End(self.attrs.to_end()))?;
        }
        Ok(())
    }
}

impl<'r, 'w, W> ser::SerializeStructVariant for Struct<'r, 'w, W>
where
    W: 'w + Write,
{
    type Ok = ();
    type Error = DeError;

    #[inline]
    fn serialize_field<T: ?Sized + Serialize>(
        &mut self,
        key: &'static str,
        value: &T,
    ) -> Result<(), Self::Error> {
        <Self as ser::SerializeStruct>::serialize_field(self, key, value)
    }

    #[inline]
    fn end(self) -> Result<Self::Ok, Self::Error> {
        <Self as ser::SerializeStruct>::end(self)
    }
}

/// An implementation of `SerializeSeq' for serializing to XML.
pub struct Seq<'r, 'w, W>
where
    W: 'w + Write,
{
    parent: &'w mut Serializer<'r, W>,
}

impl<'r, 'w, W> Seq<'r, 'w, W>
where
    W: 'w + Write,
{
    /// Create a new `Seq`
    pub fn new(parent: &'w mut Serializer<'r, W>) -> Self {
        Seq { parent }
    }
}

impl<'r, 'w, W> ser::SerializeSeq for Seq<'r, 'w, W>
where
    W: 'w + Write,
{
    type Ok = ();
    type Error = DeError;

    fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: Serialize,
    {
        value.serialize(&mut *self.parent)?;
        Ok(())
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        Ok(())
    }
}

/// An implementation of `SerializeTuple`, `SerializeTupleStruct` and
/// `SerializeTupleVariant` for serializing to XML.
pub struct Tuple<'r, 'w, W>
where
    W: 'w + Write,
{
    parent: &'w mut Serializer<'r, W>,
    /// Possible qualified name of XML tag surrounding each element
    name: &'r str,
}

impl<'r, 'w, W> Tuple<'r, 'w, W>
where
    W: 'w + Write,
{
    /// Create a new `Tuple`
    pub fn new(parent: &'w mut Serializer<'r, W>, name: &'r str) -> Self {
        Tuple { parent, name }
    }
}

impl<'r, 'w, W> ser::SerializeTuple for Tuple<'r, 'w, W>
where
    W: 'w + Write,
{
    type Ok = ();
    type Error = DeError;

    fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: Serialize
    {
        write!(self.parent.writer.inner(), "<{}>", self.name).map_err(Error::Io)?;
        value.serialize(&mut *self.parent)?;
        write!(self.parent.writer.inner(), "</{}>", self.name).map_err(Error::Io)?;
        Ok(())
    }

    #[inline]
    fn end(self) -> Result<Self::Ok, Self::Error> {
        Ok(())
    }
}

impl<'r, 'w, W> ser::SerializeTupleStruct for Tuple<'r, 'w, W>
where
    W: 'w + Write,
{
    type Ok = ();
    type Error = DeError;

    #[inline]
    fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: Serialize
    {
        <Self as ser::SerializeTuple>::serialize_element(self, value)
    }

    #[inline]
    fn end(self) -> Result<Self::Ok, Self::Error> {
        <Self as ser::SerializeTuple>::end(self)
    }
}

impl<'r, 'w, W> ser::SerializeTupleVariant for Tuple<'r, 'w, W>
where
    W: 'w + Write,
{
    type Ok = ();
    type Error = DeError;

    #[inline]
    fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
    where
        T: Serialize
    {
        <Self as ser::SerializeTuple>::serialize_element(self, value)
    }

    #[inline]
    fn end(self) -> Result<Self::Ok, Self::Error> {
        <Self as ser::SerializeTuple>::end(self)
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::net::{Ipv4Addr, SocketAddrV4};
use std::net::UdpSocket;
use std::str;

use hyper;
use regex::Regex;
use xml::EventReader;
use xml::common::Error as XmlError;
use xml::reader::events::XmlEvent;

use gateway::Gateway;

// Content of the request.
const SEARCH_REQUEST: &'static str =
"M-SEARCH * HTTP/1.1\r
Host:239.255.255.250:1900\r
ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1\r
Man:\"ssdp:discover\"\r
MX:3\r\n\r\n";

// Error type this module emits.
#[derive(Debug)]
pub enum SearchError {
    HttpError(hyper::Error),
    IoError(io::Error),
    InvalidResponse,
    XmlError(XmlError),
}

impl From<hyper::Error> for SearchError {
    fn from(err: hyper::Error) -> SearchError {
        SearchError::HttpError(err)
    }
}

impl From<io::Error> for SearchError {
    fn from(err: io::Error) -> SearchError {
        SearchError::IoError(err)
    }
}

impl From<XmlError> for SearchError {
    fn from(err: XmlError) -> SearchError {
        SearchError::XmlError(err)
    }
}

// Try to find the gateway on the local network.
// Bind to the given interface.
pub fn search_gateway_from(ip: Ipv4Addr) -> Result<Gateway, SearchError> {
    let addr = SocketAddrV4::new(ip, 0);
    let socket = try!(UdpSocket::bind(addr));

    // send the request on the broadcast address
    try!(socket.send_to(SEARCH_REQUEST.as_bytes(), "239.255.255.250:1900"));
    let mut buf = [0u8; 1024];
    let (read, _) = try!(socket.recv_from(&mut buf));
    let text = str::from_utf8(&buf[..read]).unwrap();
    match parse_result(text) {
        None => Err(SearchError::InvalidResponse),
        Some(location) => {
            let control_url = try!(get_control_url(&location));
            Ok(Gateway::new(location.0, control_url))
        },
    }
}

// Try to find the gateway on the local network.
// Bind to all interfaces.
pub fn search_gateway() -> Result<Gateway, SearchError> {
    search_gateway_from(Ipv4Addr::new(0, 0, 0, 0))
}

// Parse the result.
fn parse_result(text: &str) -> Option<(SocketAddrV4, String)> {
    let re = Regex::new(r"(?i:Location):\s*http://(\d+\.\d+\.\d+\.\d+):(\d+)(/[^\r]*)").unwrap();
    for line in text.lines() {
        match re.captures(line) {
            None => continue,
            Some(cap) => {
                // these shouldn't fail if the regex matched.
                let addr = cap.at(1).unwrap();
                let port = cap.at(2).unwrap();
                return Some(
                    (SocketAddrV4::new(
                        addr.parse::<Ipv4Addr>().unwrap(),
                        port.parse::<u16>().unwrap()),
                     cap.at(3).unwrap().to_string()));
            },
        }
    }
    None
}

fn get_control_url(location: &(SocketAddrV4, String)) -> Result<String, SearchError> {
    let client = hyper::Client::new();
    let resp = try!(client.get(&format!("http://{}{}", location.0, location.1)).send());

    let mut parser = EventReader::new(resp);
    let mut chain = Vec::<String>::with_capacity(4);

    struct Service {
        service_type: String,
        control_url: String,
    }

    let mut service = Service{
        service_type: "".to_string(),
        control_url: "".to_string(),
    };

    for e in parser.events() {
        match e {
            XmlEvent::StartElement { name, .. } => {
                chain.push(name.to_repr());
                let tail = if chain.len() >= 3 {
                    chain.iter().skip(chain.len() - 3)
                } else {
                    continue
                };

                if vec!["device", "serviceList", "service"]
                        .iter()
                        .zip(tail)
                        .all(|(l, r)| l == r) {
                    service.service_type.clear();
                    service.control_url.clear();
                }
            },
            XmlEvent::EndElement { .. } => {
                let top = chain.pop();
                let tail = if top == Some("service".to_string())
                        && chain.len() >= 2 {
                    chain.iter().skip(chain.len() - 2)
                } else {
                    continue
                };

                if vec!["device", "serviceList"]
                        .iter()
                        .zip(tail)
                        .all(|(l, r)| l == r) {
                    if "urn:schemas-upnp-org:service:WANIPConnection:1"
                            == service.service_type
                            && service.control_url.len() != 0 {
                        return Ok(service.control_url);
                    }
                }
            },
            XmlEvent::Characters(text) => {
                let tail = if chain.len() >= 4 {
                    chain.iter().skip(chain.len() - 4)
                } else {
                    continue
                };

                if vec!["device", "serviceList", "service", "serviceType"]
                    .iter().zip(tail.clone()).all(|(l, r)| l == r) {
                    service.service_type.push_str(&text);
                }
                if vec!["device", "serviceList", "service", "controlURL"]
                    .iter().zip(tail).all(|(l, r)| l == r) {
                    service.control_url.push_str(&text);
                }
            },
            XmlEvent::Error(e) =>  return Err(e.into()),
            _ => (),
        }
    }
    Err(SearchError::InvalidResponse)
}

#[test]
fn test_parse_result_case_insensitivity() {
    assert!(parse_result("location:http://0.0.0.0:0/control_url").is_some());
    assert!(parse_result("LOCATION:http://0.0.0.0:0/control_url").is_some());
}

#[test]
fn test_parse_result() {
    let result = parse_result("location:http://0.0.0.0:0/control_url").unwrap();
    assert_eq!(result.0.ip(), &Ipv4Addr::new(0,0,0,0));
    assert_eq!(result.0.port(), 0);
    assert_eq!(&result.1[..], "/control_url");
}
<commit_msg>Remove unwrap, allow user to handle utf8 errors<commit_after>use std::io;
use std::net::{Ipv4Addr, SocketAddrV4};
use std::net::UdpSocket;
use std::str;

use hyper;
use regex::Regex;
use xml::EventReader;
use xml::common::Error as XmlError;
use xml::reader::events::XmlEvent;

use gateway::Gateway;

// Content of the request.
const SEARCH_REQUEST: &'static str =
"M-SEARCH * HTTP/1.1\r
Host:239.255.255.250:1900\r
ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1\r
Man:\"ssdp:discover\"\r
MX:3\r\n\r\n";

// Error type this module emits.
#[derive(Debug)]
pub enum SearchError {
    HttpError(hyper::Error),
    IoError(io::Error),
    InvalidResponse,
    Utf8Error(str::Utf8Error),
    XmlError(XmlError),
}

impl From<hyper::Error> for SearchError {
    fn from(err: hyper::Error) -> SearchError {
        SearchError::HttpError(err)
    }
}

impl From<io::Error> for SearchError {
    fn from(err: io::Error) -> SearchError {
        SearchError::IoError(err)
    }
}

impl From<str::Utf8Error> for SearchError {
    fn from(err: str::Utf8Error) -> SearchError {
        SearchError::Utf8Error(err)
    }
}

impl From<XmlError> for SearchError {
    fn from(err: XmlError) -> SearchError {
        SearchError::XmlError(err)
    }
}

// Try to find the gateway on the local network.
// Bind to the given interface.
pub fn search_gateway_from(ip: Ipv4Addr) -> Result<Gateway, SearchError> {
    let addr = SocketAddrV4::new(ip, 0);
    let socket = try!(UdpSocket::bind(addr));

    // send the request on the broadcast address
    try!(socket.send_to(SEARCH_REQUEST.as_bytes(), "239.255.255.250:1900"));
    let mut buf = [0u8; 1024];
    let (read, _) = try!(socket.recv_from(&mut buf));
    let text = try!(str::from_utf8(&buf[..read]));
    match parse_result(text) {
        None => Err(SearchError::InvalidResponse),
        Some(location) => {
            let control_url = try!(get_control_url(&location));
            Ok(Gateway::new(location.0, control_url))
        },
    }
}

// Try to find the gateway on the local network.
// Bind to all interfaces.
pub fn search_gateway() -> Result<Gateway, SearchError> {
    search_gateway_from(Ipv4Addr::new(0, 0, 0, 0))
}

// Parse the result.
fn parse_result(text: &str) -> Option<(SocketAddrV4, String)> {
    let re = Regex::new(r"(?i:Location):\s*http://(\d+\.\d+\.\d+\.\d+):(\d+)(/[^\r]*)").unwrap();
    for line in text.lines() {
        match re.captures(line) {
            None => continue,
            Some(cap) => {
                // these shouldn't fail if the regex matched.
                let addr = cap.at(1).unwrap();
                let port = cap.at(2).unwrap();
                return Some(
                    (SocketAddrV4::new(
                        addr.parse::<Ipv4Addr>().unwrap(),
                        port.parse::<u16>().unwrap()),
                     cap.at(3).unwrap().to_string()));
            },
        }
    }
    None
}

fn get_control_url(location: &(SocketAddrV4, String)) -> Result<String, SearchError> {
    let client = hyper::Client::new();
    let resp = try!(client.get(&format!("http://{}{}", location.0, location.1)).send());

    let mut parser = EventReader::new(resp);
    let mut chain = Vec::<String>::with_capacity(4);

    struct Service {
        service_type: String,
        control_url: String,
    }

    let mut service = Service{
        service_type: "".to_string(),
        control_url: "".to_string(),
    };

    for e in parser.events() {
        match e {
            XmlEvent::StartElement { name, .. } => {
                chain.push(name.to_repr());
                let tail = if chain.len() >= 3 {
                    chain.iter().skip(chain.len() - 3)
                } else {
                    continue
                };

                if vec!["device", "serviceList", "service"]
                        .iter()
                        .zip(tail)
                        .all(|(l, r)| l == r) {
                    service.service_type.clear();
                    service.control_url.clear();
                }
            },
            XmlEvent::EndElement { .. } => {
                let top = chain.pop();
                let tail = if top == Some("service".to_string())
                        && chain.len() >= 2 {
                    chain.iter().skip(chain.len() - 2)
                } else {
                    continue
                };

                if vec!["device", "serviceList"]
                        .iter()
                        .zip(tail)
                        .all(|(l, r)| l == r) {
                    if "urn:schemas-upnp-org:service:WANIPConnection:1"
                            == service.service_type
                            && service.control_url.len() != 0 {
                        return Ok(service.control_url);
                    }
                }
            },
            XmlEvent::Characters(text) => {
                let tail = if chain.len() >= 4 {
                    chain.iter().skip(chain.len() - 4)
                } else {
                    continue
                };

                if vec!["device", "serviceList", "service", "serviceType"]
                    .iter().zip(tail.clone()).all(|(l, r)| l == r) {
                    service.service_type.push_str(&text);
                }
                if vec!["device", "serviceList", "service", "controlURL"]
                    .iter().zip(tail).all(|(l, r)| l == r) {
                    service.control_url.push_str(&text);
                }
            },
            XmlEvent::Error(e) =>  return Err(e.into()),
            _ => (),
        }
    }
    Err(SearchError::InvalidResponse)
}

#[test]
fn test_parse_result_case_insensitivity() {
    assert!(parse_result("location:http://0.0.0.0:0/control_url").is_some());
    assert!(parse_result("LOCATION:http://0.0.0.0:0/control_url").is_some());
}

#[test]
fn test_parse_result() {
    let result = parse_result("location:http://0.0.0.0:0/control_url").unwrap();
    assert_eq!(result.0.ip(), &Ipv4Addr::new(0,0,0,0));
    assert_eq!(result.0.port(), 0);
    assert_eq!(&result.1[..], "/control_url");
}
<|endoftext|>