<commit_before>use std::cmp;
use std::fmt;
use std::io;
use std::ops::Deref;
#[cfg(feature = "termcolor")]
use termcolor::{ColorSpec, WriteColor};

use Doc;

/// Trait representing the operations necessary to render a document
pub trait Render {
    type Error;

    fn write_str(&mut self, s: &str) -> Result<usize, Self::Error>;

    fn write_str_all(&mut self, mut s: &str) -> Result<(), Self::Error> {
        while !s.is_empty() {
            let count = self.write_str(s)?;
            s = &s[count..];
        }
        Ok(())
    }
}

/// Writes to something implementing `std::io::Write`
pub struct IoWrite<W> {
    upstream: W,
}

impl<W> IoWrite<W> {
    pub fn new(upstream: W) -> IoWrite<W> {
        IoWrite { upstream }
    }
}

impl<W> Render for IoWrite<W>
where
    W: io::Write,
{
    type Error = io::Error;

    fn write_str(&mut self, s: &str) -> io::Result<usize> {
        self.upstream.write(s.as_bytes())
    }

    fn write_str_all(&mut self, s: &str) -> io::Result<()> {
        self.upstream.write_all(s.as_bytes())
    }
}

/// Writes to something implementing `std::fmt::Write`
pub struct FmtWrite<W> {
    upstream: W,
}

impl<W> FmtWrite<W> {
    pub fn new(upstream: W) -> FmtWrite<W> {
        FmtWrite { upstream }
    }
}

impl<W> Render for FmtWrite<W>
where
    W: fmt::Write,
{
    type Error = fmt::Error;

    fn write_str(&mut self, s: &str) -> Result<usize, fmt::Error> {
        self.write_str_all(s).map(|_| s.len())
    }

    fn write_str_all(&mut self, s: &str) -> fmt::Result {
        self.upstream.write_str(s)
    }
}

/// Trait representing the operations necessary to write an annotated document.
pub trait RenderAnnotated<A>: Render {
    fn push_annotation(&mut self, annotation: &A) -> Result<(), Self::Error>;
    fn pop_annotation(&mut self) -> Result<(), Self::Error>;
}

impl<A, W> RenderAnnotated<A> for IoWrite<W>
where
    W: io::Write,
{
    fn push_annotation(&mut self, _: &A) -> Result<(), Self::Error> {
        Ok(())
    }

    fn pop_annotation(&mut self) -> Result<(), Self::Error> {
        Ok(())
    }
}

impl<A, W> RenderAnnotated<A> for FmtWrite<W>
where
    W: fmt::Write,
{
    fn push_annotation(&mut self, _: &A) -> Result<(), Self::Error> {
        Ok(())
    }

    fn pop_annotation(&mut self) -> Result<(), Self::Error> {
        Ok(())
    }
}

#[cfg(feature = "termcolor")]
pub struct TermColored<W> {
    color_stack: Vec<ColorSpec>,
    upstream: W,
}

#[cfg(feature = "termcolor")]
impl<W> TermColored<W> {
    pub fn new(upstream: W) -> TermColored<W> {
        TermColored {
            color_stack: Vec::new(),
            upstream,
        }
    }
}

#[cfg(feature = "termcolor")]
impl<W> Render for TermColored<W>
where
    W: io::Write,
{
    type Error = io::Error;

    fn write_str(&mut self, s: &str) -> io::Result<usize> {
        self.upstream.write(s.as_bytes())
    }

    fn write_str_all(&mut self, s: &str) -> io::Result<()> {
        self.upstream.write_all(s.as_bytes())
    }
}

#[cfg(feature = "termcolor")]
impl<W> RenderAnnotated<ColorSpec> for TermColored<W>
where
    W: WriteColor,
{
    fn push_annotation(&mut self, color: &ColorSpec) -> Result<(), Self::Error> {
        self.color_stack.push(color.clone());
        self.upstream.set_color(color)
    }

    fn pop_annotation(&mut self) -> Result<(), Self::Error> {
        self.color_stack.pop();
        match self.color_stack.last() {
            Some(previous) => self.upstream.set_color(previous),
            None => self.upstream.reset(),
        }
    }
}

#[inline]
pub fn best<'a, W, T, A>(doc: &'a Doc<'a, T, A>, width: usize, out: &mut W) -> Result<(), W::Error>
where
    T: Deref<Target = Doc<'a, T, A>>,
    W: ?Sized + RenderAnnotated<A>,
{
    #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
    enum Mode {
        Break,
        Flat,
    }

    type Cmd<'a, T, A> = (usize, Mode, &'a Doc<'a, T, A>);

    fn write_newline<W>(ind: usize, out: &mut W) -> Result<(), W::Error>
    where
        W: ?Sized + Render,
    {
        out.write_str_all("\n")?;
        write_spaces(ind, out)
    }

    fn write_spaces<W>(spaces: usize, out: &mut W) -> Result<(), W::Error>
    where
        W: ?Sized + Render,
    {
        macro_rules! make_spaces {
            () => { "" };
            ($s: tt $($t: tt)*) => { concat!("          ", make_spaces!($($t)*)) };
        }

        const SPACES: &str = make_spaces!(,,,,,,,,,,);
        let mut inserted = 0;
        while inserted < spaces {
            let insert = cmp::min(SPACES.len(), spaces - inserted);
            inserted += out.write_str(&SPACES[..insert])?;
        }

        Ok(())
    }

    fn fitting<'a, T, A>(
        next: Cmd<'a, T, A>,
        bcmds: &[Cmd<'a, T, A>],
        fcmds: &mut Vec<Cmd<'a, T, A>>,
        mut rem: isize,
    ) -> bool
    where
        T: Deref<Target = Doc<'a, T, A>>,
    {
        let mut bidx = bcmds.len();
        fcmds.clear(); // clear from previous calls from best
        fcmds.push(next);

        loop {
            let mut cmd = match fcmds.pop() {
                None => {
                    if bidx == 0 {
                        // All commands have been processed
                        return true;
                    } else {
                        bidx -= 1;
                        bcmds[bidx]
                    }
                }
                Some(cmd) => cmd,
            };
            loop {
                let (ind, mode, doc) = cmd;
                match *doc {
                    Doc::Nil => {}
                    Doc::Append(ref ldoc, ref rdoc) => {
                        fcmds.push((ind, mode, rdoc));
                        // Since appended documents often appear in sequence on the left side we
                        // gain a slight performance increase by batching these pushes (avoiding
                        // to push and directly pop `Append` documents)
                        let mut doc = ldoc;
                        while let Doc::Append(ref l, ref r) = **doc {
                            fcmds.push((ind, mode, r));
                            doc = l;
                        }
                        cmd = (ind, mode, doc);
                        continue;
                    }
                    Doc::Nest(off, ref doc) => {
                        cmd = (ind + off, mode, doc);
                        continue;
                    }
                    Doc::Space => match mode {
                        Mode::Flat => {
                            rem -= 1;
                            if rem < 0 {
                                return false;
                            }
                        }
                        Mode::Break => return true,
                    },
                    // Newlines inside the group makes it not fit, but those outside lets it
                    // fit on the current line
                    Doc::Newline => return bidx < bcmds.len(),
                    Doc::Text(ref str) => {
                        rem -= str.len() as isize;
                        if rem < 0 {
                            return false;
                        }
                    }
                    Doc::FlatAlt(_, ref doc)
                    | Doc::Group(ref doc)
                    | Doc::Annotated(_, ref doc)
                    | Doc::Union(_, ref doc) => {
                        cmd = (ind, mode, doc);
                        continue;
                    }
                }
                break;
            }
        }
    }

    let mut pos = 0;
    let mut bcmds = vec![(0, Mode::Break, doc)];
    let mut fcmds = vec![];
    let mut annotation_levels = vec![];

    while let Some(mut cmd) = bcmds.pop() {
        loop {
            let (ind, mode, doc) = cmd;
            match *doc {
                Doc::Nil => {}
                Doc::Append(ref ldoc, ref rdoc) => {
                    bcmds.push((ind, mode, rdoc));
                    let mut doc = ldoc;
                    while let Doc::Append(ref l, ref r) = **doc {
                        bcmds.push((ind, mode, r));
                        doc = l;
                    }
                    cmd = (ind, mode, doc);
                    continue;
                }
                Doc::FlatAlt(ref b, ref f) => {
                    cmd = (
                        ind,
                        mode,
                        match mode {
                            Mode::Break => b,
                            Mode::Flat => f,
                        },
                    );
                    continue;
                }
                Doc::Group(ref doc) => match mode {
                    Mode::Flat => {
                        cmd = (ind, Mode::Flat, doc);
                        continue;
                    }
                    Mode::Break => {
                        let next = (ind, Mode::Flat, &**doc);
                        let rem = width as isize - pos as isize;
                        cmd = if fitting(next, &bcmds, &mut fcmds, rem) {
                            next
                        } else {
                            (ind, Mode::Break, doc)
                        };
                        continue;
                    }
                },
                Doc::Nest(off, ref doc) => {
                    cmd = (ind + off, mode, doc);
                    continue;
                }
                Doc::Space => match mode {
                    Mode::Flat => {
                        write_spaces(1, out)?;
                    }
                    Mode::Break => {
                        write_newline(ind, out)?;
                        pos = ind;
                    }
                },
                Doc::Newline => {
                    write_newline(ind, out)?;
                    pos = ind;
                }
                Doc::Text(ref s) => {
                    out.write_str_all(s)?;
                    pos += s.len();
                }
                Doc::Annotated(ref ann, ref doc) => {
                    out.push_annotation(ann)?;
                    annotation_levels.push(bcmds.len());
                    cmd = (ind, mode, doc);
                    continue;
                }
                Doc::Union(ref l, ref r) => {
                    let next = (ind, Mode::Flat, &**l);
                    let rem = width as isize - pos as isize;
                    cmd = if fitting(next, &bcmds, &mut fcmds, rem) {
                        (ind, mode, l)
                    } else {
                        (ind, mode, r)
                    };
                    continue;
                }
            }

            break;
        }
        if annotation_levels.last() == Some(&bcmds.len()) {
            annotation_levels.pop();
            out.pop_annotation()?;
        }
    }

    Ok(())
}
<commit_msg>perf: Simplify fitting more<commit_after>use std::cmp;
use std::fmt;
use std::io;
use std::ops::Deref;
#[cfg(feature = "termcolor")]
use termcolor::{ColorSpec, WriteColor};

use Doc;

/// Trait representing the operations necessary to render a document
pub trait Render {
    type Error;

    fn write_str(&mut self, s: &str) -> Result<usize, Self::Error>;

    fn write_str_all(&mut self, mut s: &str) -> Result<(), Self::Error> {
        while !s.is_empty() {
            let count = self.write_str(s)?;
            s = &s[count..];
        }
        Ok(())
    }
}

/// Writes to something implementing `std::io::Write`
pub struct IoWrite<W> {
    upstream: W,
}

impl<W> IoWrite<W> {
    pub fn new(upstream: W) -> IoWrite<W> {
        IoWrite { upstream }
    }
}

impl<W> Render for IoWrite<W>
where
    W: io::Write,
{
    type Error = io::Error;

    fn write_str(&mut self, s: &str) -> io::Result<usize> {
        self.upstream.write(s.as_bytes())
    }

    fn write_str_all(&mut self, s: &str) -> io::Result<()> {
        self.upstream.write_all(s.as_bytes())
    }
}

/// Writes to something implementing `std::fmt::Write`
pub struct FmtWrite<W> {
    upstream: W,
}

impl<W> FmtWrite<W> {
    pub fn new(upstream: W) -> FmtWrite<W> {
        FmtWrite { upstream }
    }
}

impl<W> Render for FmtWrite<W>
where
    W: fmt::Write,
{
    type Error = fmt::Error;

    fn write_str(&mut self, s: &str) -> Result<usize, fmt::Error> {
        self.write_str_all(s).map(|_| s.len())
    }

    fn write_str_all(&mut self, s: &str) -> fmt::Result {
        self.upstream.write_str(s)
    }
}

/// Trait representing the operations necessary to write an annotated document.
pub trait RenderAnnotated<A>: Render {
    fn push_annotation(&mut self, annotation: &A) -> Result<(), Self::Error>;
    fn pop_annotation(&mut self) -> Result<(), Self::Error>;
}

impl<A, W> RenderAnnotated<A> for IoWrite<W>
where
    W: io::Write,
{
    fn push_annotation(&mut self, _: &A) -> Result<(), Self::Error> {
        Ok(())
    }

    fn pop_annotation(&mut self) -> Result<(), Self::Error> {
        Ok(())
    }
}

impl<A, W> RenderAnnotated<A> for FmtWrite<W>
where
    W: fmt::Write,
{
    fn push_annotation(&mut self, _: &A) -> Result<(), Self::Error> {
        Ok(())
    }

    fn pop_annotation(&mut self) -> Result<(), Self::Error> {
        Ok(())
    }
}

#[cfg(feature = "termcolor")]
pub struct TermColored<W> {
    color_stack: Vec<ColorSpec>,
    upstream: W,
}

#[cfg(feature = "termcolor")]
impl<W> TermColored<W> {
    pub fn new(upstream: W) -> TermColored<W> {
        TermColored {
            color_stack: Vec::new(),
            upstream,
        }
    }
}

#[cfg(feature = "termcolor")]
impl<W> Render for TermColored<W>
where
    W: io::Write,
{
    type Error = io::Error;

    fn write_str(&mut self, s: &str) -> io::Result<usize> {
        self.upstream.write(s.as_bytes())
    }

    fn write_str_all(&mut self, s: &str) -> io::Result<()> {
        self.upstream.write_all(s.as_bytes())
    }
}

#[cfg(feature = "termcolor")]
impl<W> RenderAnnotated<ColorSpec> for TermColored<W>
where
    W: WriteColor,
{
    fn push_annotation(&mut self, color: &ColorSpec) -> Result<(), Self::Error> {
        self.color_stack.push(color.clone());
        self.upstream.set_color(color)
    }

    fn pop_annotation(&mut self) -> Result<(), Self::Error> {
        self.color_stack.pop();
        match self.color_stack.last() {
            Some(previous) => self.upstream.set_color(previous),
            None => self.upstream.reset(),
        }
    }
}

#[inline]
pub fn best<'a, W, T, A>(doc: &'a Doc<'a, T, A>, width: usize, out: &mut W) -> Result<(), W::Error>
where
    T: Deref<Target = Doc<'a, T, A>>,
    W: ?Sized + RenderAnnotated<A>,
{
    #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
    enum Mode {
        Break,
        Flat,
    }

    type Cmd<'a, T, A> = (usize, Mode, &'a Doc<'a, T, A>);

    fn write_newline<W>(ind: usize, out: &mut W) -> Result<(), W::Error>
    where
        W: ?Sized + Render,
    {
        out.write_str_all("\n")?;
        write_spaces(ind, out)
    }

    fn write_spaces<W>(spaces: usize, out: &mut W) -> Result<(), W::Error>
    where
        W: ?Sized + Render,
    {
        macro_rules! make_spaces {
            () => { "" };
            ($s: tt $($t: tt)*) => { concat!("          ", make_spaces!($($t)*)) };
        }

        const SPACES: &str = make_spaces!(,,,,,,,,,,);
        let mut inserted = 0;
        while inserted < spaces {
            let insert = cmp::min(SPACES.len(), spaces - inserted);
            inserted += out.write_str(&SPACES[..insert])?;
        }

        Ok(())
    }

    fn fitting<'a, T, A>(
        next: &'a Doc<'a, T, A>,
        bcmds: &[Cmd<'a, T, A>],
        fcmds: &mut Vec<&'a Doc<'a, T, A>>,
        mut rem: isize,
    ) -> bool
    where
        T: Deref<Target = Doc<'a, T, A>>,
    {
        let mut bidx = bcmds.len();
        fcmds.clear(); // clear from previous calls from best
        fcmds.push(next);

        let mut mode = Mode::Flat;
        loop {
            let mut doc = match fcmds.pop() {
                None => {
                    if bidx == 0 {
                        // All commands have been processed
                        return true;
                    } else {
                        bidx -= 1;
                        mode = Mode::Break;
                        bcmds[bidx].2
                    }
                }
                Some(cmd) => cmd,
            };
            loop {
                match *doc {
                    Doc::Nil => {}
                    Doc::Append(ref ldoc, ref rdoc) => {
                        fcmds.push(rdoc);
                        // Since appended documents often appear in sequence on the left side we
                        // gain a slight performance increase by batching these pushes (avoiding
                        // to push and directly pop `Append` documents)
                        doc = ldoc;
                        while let Doc::Append(ref l, ref r) = *doc {
                            fcmds.push(r);
                            doc = l;
                        }
                        continue;
                    }
                    Doc::Space => match mode {
                        Mode::Flat => {
                            rem -= 1;
                            if rem < 0 {
                                return false;
                            }
                        }
                        Mode::Break => return true,
                    },
                    // Newlines inside the group makes it not fit, but those outside lets it
                    // fit on the current line
                    Doc::Newline => return mode == Mode::Break,
                    Doc::Text(ref str) => {
                        rem -= str.len() as isize;
                        if rem < 0 {
                            return false;
                        }
                    }
                    Doc::Nest(_, ref next)
                    | Doc::FlatAlt(_, ref next)
                    | Doc::Group(ref next)
                    | Doc::Annotated(_, ref next)
                    | Doc::Union(_, ref next) => {
                        doc = next;
                        continue;
                    }
                }
                break;
            }
        }
    }

    let mut pos = 0;
    let mut bcmds = vec![(0, Mode::Break, doc)];
    let mut fcmds = vec![];
    let mut annotation_levels = vec![];

    while let Some(mut cmd) = bcmds.pop() {
        loop {
            let (ind, mode, doc) = cmd;
            match *doc {
                Doc::Nil => {}
                Doc::Append(ref ldoc, ref rdoc) => {
                    bcmds.push((ind, mode, rdoc));
                    let mut doc = ldoc;
                    while let Doc::Append(ref l, ref r) = **doc {
                        bcmds.push((ind, mode, r));
                        doc = l;
                    }
                    cmd = (ind, mode, doc);
                    continue;
                }
                Doc::FlatAlt(ref b, ref f) => {
                    cmd = (
                        ind,
                        mode,
                        match mode {
                            Mode::Break => b,
                            Mode::Flat => f,
                        },
                    );
                    continue;
                }
                Doc::Group(ref doc) => match mode {
                    Mode::Flat => {
                        cmd = (ind, Mode::Flat, doc);
                        continue;
                    }
                    Mode::Break => {
                        let rem = width as isize - pos as isize;
                        cmd = if fitting(doc, &bcmds, &mut fcmds, rem) {
                            (ind, Mode::Flat, &**doc)
                        } else {
                            (ind, Mode::Break, doc)
                        };
                        continue;
                    }
                },
                Doc::Nest(off, ref doc) => {
                    cmd = (ind + off, mode, doc);
                    continue;
                }
                Doc::Space => match mode {
                    Mode::Flat => {
                        write_spaces(1, out)?;
                    }
                    Mode::Break => {
                        write_newline(ind, out)?;
                        pos = ind;
                    }
                },
                Doc::Newline => {
                    write_newline(ind, out)?;
                    pos = ind;
                }
                Doc::Text(ref s) => {
                    out.write_str_all(s)?;
                    pos += s.len();
                }
                Doc::Annotated(ref ann, ref doc) => {
                    out.push_annotation(ann)?;
                    annotation_levels.push(bcmds.len());
                    cmd = (ind, mode, doc);
                    continue;
                }
                Doc::Union(ref l, ref r) => {
                    let rem = width as isize - pos as isize;
                    cmd = if fitting(l, &bcmds, &mut fcmds, rem) {
                        (ind, mode, l)
                    } else {
                        (ind, mode, r)
                    };
                    continue;
                }
            }

            break;
        }
        if annotation_levels.last() == Some(&bcmds.len()) {
            annotation_levels.pop();
            out.pop_annotation()?;
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>//! Error types that can be emitted from this library

use std::old_io::IoError;
use std::error;
use std::fmt;

/// Generic result type with ZipError as its error variant
pub type ZipResult<T> = Result<T, ZipError>;

/// Error type for Zip
#[derive(Show)]
pub enum ZipError
{
    /// An Error caused by I/O
    Io(IoError),

    /// This file is probably not a zipfile. The argument is enclosed.
    InvalidZipFile(&'static str),

    /// This file is unsupported. The reason is enclosed.
    UnsupportedZipFile(&'static str),

    /// The ZipReader is not available.
    ReaderUnavailable,
}

impl ZipError
{
    fn detail(&self) -> ::std::string::CowString
    {
        use ::std::error::Error;
        use ::std::borrow::IntoCow;

        match *self
        {
            ZipError::Io(ref io_err) => {
                ("Io Error: ".to_string() + io_err.description()).into_cow()
            },
            ZipError::InvalidZipFile(msg) | ZipError::UnsupportedZipFile(msg) => {
                (self.description().to_string() + ": " + msg).into_cow()
            },
            ZipError::ReaderUnavailable => {
                self.description().into_cow()
            },
        }
    }
}

impl error::FromError<IoError> for ZipError
{
    fn from_error(err: IoError) -> ZipError
    {
        ZipError::Io(err)
    }
}

impl fmt::Display for ZipError
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>
    {
        fmt.write_str(&*self.detail())
    }
}

impl error::Error for ZipError
{
    fn description(&self) -> &str
    {
        match *self
        {
            ZipError::Io(ref io_err) => io_err.description(),
            ZipError::InvalidZipFile(..) => "Invalid Zip File",
            ZipError::UnsupportedZipFile(..) => "Unsupported Zip File",
            ZipError::ReaderUnavailable => "No reader available",
        }
    }

    fn cause(&self) -> Option<&error::Error>
    {
        match *self
        {
            ZipError::Io(ref io_err) => Some(io_err as &error::Error),
            _ => None,
        }
    }
}
<commit_msg>Derive Debug instead of Show<commit_after>//! Error types that can be emitted from this library

use std::old_io::IoError;
use std::error;
use std::fmt;

/// Generic result type with ZipError as its error variant
pub type ZipResult<T> = Result<T, ZipError>;

/// Error type for Zip
#[derive(Debug)]
pub enum ZipError
{
    /// An Error caused by I/O
    Io(IoError),

    /// This file is probably not a zipfile. The argument is enclosed.
    InvalidZipFile(&'static str),

    /// This file is unsupported. The reason is enclosed.
    UnsupportedZipFile(&'static str),

    /// The ZipReader is not available.
    ReaderUnavailable,
}

impl ZipError
{
    fn detail(&self) -> ::std::string::CowString
    {
        use ::std::error::Error;
        use ::std::borrow::IntoCow;

        match *self
        {
            ZipError::Io(ref io_err) => {
                ("Io Error: ".to_string() + io_err.description()).into_cow()
            },
            ZipError::InvalidZipFile(msg) | ZipError::UnsupportedZipFile(msg) => {
                (self.description().to_string() + ": " + msg).into_cow()
            },
            ZipError::ReaderUnavailable => {
                self.description().into_cow()
            },
        }
    }
}

impl error::FromError<IoError> for ZipError
{
    fn from_error(err: IoError) -> ZipError
    {
        ZipError::Io(err)
    }
}

impl fmt::Display for ZipError
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>
    {
        fmt.write_str(&*self.detail())
    }
}

impl error::Error for ZipError
{
    fn description(&self) -> &str
    {
        match *self
        {
            ZipError::Io(ref io_err) => io_err.description(),
            ZipError::InvalidZipFile(..) => "Invalid Zip File",
            ZipError::UnsupportedZipFile(..) => "Unsupported Zip File",
            ZipError::ReaderUnavailable => "No reader available",
        }
    }

    fn cause(&self) -> Option<&error::Error>
    {
        match *self
        {
            ZipError::Io(ref io_err) => Some(io_err as &error::Error),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>#[pkgid = "compress"];
#[deny(warnings)];
#[deny(missing_doc)];

//! dox (placeholder)

extern mod extra;

//mod flate;
pub mod lz4;
<commit_msg>pkgid => crate_id<commit_after>#[crate_id = "compress"];
#[deny(warnings)];
#[deny(missing_doc)];

//! dox (placeholder)

extern mod extra;

//mod flate;
pub mod lz4;
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
Syntax extension to generate FourCCs.

Once loaded, fourcc!() is called with a single 4-character string,
and an optional ident that is either `big`, `little`, or `target`.
The ident represents endianness, and specifies in which direction
the characters should be read. If the ident is omitted, it is assumed
to be `big`, i.e. left-to-right order. It returns a u32.

# Examples

To load the extension and use it:

```rust,ignore
#[phase(plugin)]
extern crate fourcc;

fn main() {
    let val = fourcc!("\xC0\xFF\xEE!");
    assert_eq!(val, 0xC0FFEE21u32);
    let little_val = fourcc!("foo ", little);
    assert_eq!(little_val, 0x21EEFFC0u32);
}
```

# References

* [Wikipedia: FourCC](http://en.wikipedia.org/wiki/FourCC)

*/

#![crate_id = "fourcc#0.11.0-pre"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/")]

#![feature(plugin_registrar, managed_boxes)]

extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::attr::contains;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::InternedString;
use rustc::plugin::Registry;

use std::gc::Gc;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("fourcc", expand_syntax_ext);
}

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                         -> Box<base::MacResult> {
    let (expr, endian) = parse_tts(cx, tts);

    let little = match endian {
        None => false,
        Some(Ident{ident, span}) => match token::get_ident(ident).get() {
            "little" => true,
            "big" => false,
            "target" => target_endian_little(cx, sp),
            _ => {
                cx.span_err(span, "invalid endian directive in fourcc!");
                target_endian_little(cx, sp)
            }
        }
    };

    let s = match expr.node {
        // expression is a literal
        ast::ExprLit(ref lit) => match lit.node {
            // string literal
            ast::LitStr(ref s, _) => {
                if s.get().char_len() != 4 {
                    cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
                }
                s
            }
            _ => {
                cx.span_err(expr.span, "unsupported literal in fourcc!");
                return base::DummyResult::expr(sp)
            }
        },
        _ => {
            cx.span_err(expr.span, "non-literal in fourcc!");
            return base::DummyResult::expr(sp)
        }
    };

    let mut val = 0u32;
    for codepoint in s.get().chars().take(4) {
        let byte = if codepoint as u32 > 0xFF {
            cx.span_err(expr.span, "fourcc! literal character out of range 0-255");
            0u8
        } else {
            codepoint as u8
        };

        val = if little {
            (val >> 8) | ((byte as u32) << 24)
        } else {
            (val << 8) | (byte as u32)
        };
    }
    let e = cx.expr_lit(sp, ast::LitUint(val as u64, ast::TyU32));
    MacExpr::new(e)
}

struct Ident {
    ident: ast::Ident,
    span: Span
}

fn parse_tts(cx: &ExtCtxt,
             tts: &[ast::TokenTree]) -> (Gc<ast::Expr>, Option<Ident>) {
    let p = &mut parse::new_parser_from_tts(cx.parse_sess(),
                                            cx.cfg(),
                                            tts.iter()
                                               .map(|x| (*x).clone())
                                               .collect());
    let ex = p.parse_expr();
    let id = if p.token == token::EOF {
        None
    } else {
        p.expect(&token::COMMA);
        let lo = p.span.lo;
        let ident = p.parse_ident();
        let hi = p.last_span.hi;
        Some(Ident{ident: ident, span: mk_sp(lo, hi)})
    };
    if p.token != token::EOF {
        p.unexpected();
    }
    (ex, id)
}

fn target_endian_little(cx: &ExtCtxt, sp: Span) -> bool {
    let meta = cx.meta_name_value(sp, InternedString::new("target_endian"),
        ast::LitStr(InternedString::new("little"), ast::CookedStr));
    contains(cx.cfg().as_slice(), meta)
}

// FIXME (10872): This is required to prevent an LLVM assert on Windows
#[test]
fn dummy_test() { }
<commit_msg>Simplify creating a parser from a token tree<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
Syntax extension to generate FourCCs.

Once loaded, fourcc!() is called with a single 4-character string,
and an optional ident that is either `big`, `little`, or `target`.
The ident represents endianness, and specifies in which direction
the characters should be read. If the ident is omitted, it is assumed
to be `big`, i.e. left-to-right order. It returns a u32.

# Examples

To load the extension and use it:

```rust,ignore
#[phase(plugin)]
extern crate fourcc;

fn main() {
    let val = fourcc!("\xC0\xFF\xEE!");
    assert_eq!(val, 0xC0FFEE21u32);
    let little_val = fourcc!("foo ", little);
    assert_eq!(little_val, 0x21EEFFC0u32);
}
```

# References

* [Wikipedia: FourCC](http://en.wikipedia.org/wiki/FourCC)

*/

#![crate_id = "fourcc#0.11.0-pre"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/")]

#![feature(plugin_registrar, managed_boxes)]

extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::attr::contains;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::parse::token::InternedString;
use rustc::plugin::Registry;

use std::gc::Gc;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("fourcc", expand_syntax_ext);
}

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                         -> Box<base::MacResult> {
    let (expr, endian) = parse_tts(cx, tts);

    let little = match endian {
        None => false,
        Some(Ident{ident, span}) => match token::get_ident(ident).get() {
            "little" => true,
            "big" => false,
            "target" => target_endian_little(cx, sp),
            _ => {
                cx.span_err(span, "invalid endian directive in fourcc!");
                target_endian_little(cx, sp)
            }
        }
    };

    let s = match expr.node {
        // expression is a literal
        ast::ExprLit(ref lit) => match lit.node {
            // string literal
            ast::LitStr(ref s, _) => {
                if s.get().char_len() != 4 {
                    cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
                }
                s
            }
            _ => {
                cx.span_err(expr.span, "unsupported literal in fourcc!");
                return base::DummyResult::expr(sp)
            }
        },
        _ => {
            cx.span_err(expr.span, "non-literal in fourcc!");
            return base::DummyResult::expr(sp)
        }
    };

    let mut val = 0u32;
    for codepoint in s.get().chars().take(4) {
        let byte = if codepoint as u32 > 0xFF {
            cx.span_err(expr.span, "fourcc! literal character out of range 0-255");
            0u8
        } else {
            codepoint as u8
        };

        val = if little {
            (val >> 8) | ((byte as u32) << 24)
        } else {
            (val << 8) | (byte as u32)
        };
    }
    let e = cx.expr_lit(sp, ast::LitUint(val as u64, ast::TyU32));
    MacExpr::new(e)
}

struct Ident {
    ident: ast::Ident,
    span: Span
}

fn parse_tts(cx: &ExtCtxt,
             tts: &[ast::TokenTree]) -> (Gc<ast::Expr>, Option<Ident>) {
    let p = &mut cx.new_parser_from_tts(tts);
    let ex = p.parse_expr();
    let id = if p.token == token::EOF {
        None
    } else {
        p.expect(&token::COMMA);
        let lo = p.span.lo;
        let ident = p.parse_ident();
        let hi = p.last_span.hi;
        Some(Ident{ident: ident, span: mk_sp(lo, hi)})
    };
    if p.token != token::EOF {
        p.unexpected();
    }
    (ex, id)
}

fn target_endian_little(cx: &ExtCtxt, sp: Span) -> bool {
    let meta = cx.meta_name_value(sp, InternedString::new("target_endian"),
        ast::LitStr(InternedString::new("little"), ast::CookedStr));
    contains(cx.cfg().as_slice(), meta)
}

// FIXME (10872): This is required to prevent an LLVM assert on Windows
#[test]
fn dummy_test() { }
<|endoftext|>


<commit_before>use std::iter::Iterator;
use std::collections::HashSet;
use std::hash::{Hash, Hasher, SipHasher};

pub trait SearchSpace {
    type State: Hash;
    type Action;
    type Iterator: Iterator<Item=Self::Action>;

    fn actions(&self, state: &Self::State) -> Self::Iterator;
    fn next_state(&self, state: &Self::State, action: &Self::Action) -> Self::State;
    fn is_goal(&self, state: &Self::State) -> bool;
}

pub fn depth_first_search<S>(space: &S, start: S::State) -> Option<Vec<S::Action>>
where S: SearchSpace {
    let mut path = Vec::new();
    let actions = space.actions(&start);
    let mut frontier = vec![(start, actions)];
    let mut visited = HashSet::new();

    loop {
        let result = match frontier.last_mut() {
            None => return None,
            Some(&mut (ref mut state, ref mut actions)) => {
                if space.is_goal(&state) {
                    return Some(path);
                }
                match actions.next() {
                    None => None,
                    Some(action) => {
                        let next_state = space.next_state(&state, &action);

                        let mut hasher = SipHasher::new();
                        next_state.hash(&mut hasher);
                        let hash = hasher.finish();
                        if visited.contains(&hash) {
                            continue;
                        }
                        visited.insert(hash);

                        let next_actions = space.actions(&next_state);
                        path.push(action);
                        Some((next_state, next_actions))
                    }
                }
            }
        };
        match result {
            None => {
                path.pop();
                frontier.pop();
            },
            Some((next_state, next_actions)) => {
                frontier.push((next_state, next_actions));
            },
        };
    }
}

#[cfg(test)]
pub mod tests {
    use std::vec::IntoIter;
    use super::*;

    #[test]
    pub fn test_depth_first_search() {
        struct S {
            goal: i32,
        }

        #[derive(Debug, Clone, PartialEq)]
        enum Direction {
            Left,
            Right
        }

        impl SearchSpace for S {
            type State = i32;
            type Action = Direction;
            type Iterator = IntoIter<Self::Action>;

            fn actions(&self, state: &i32) -> Self::Iterator {
                if *state == 0 || *state == 1 {
                    vec![Direction::Left, Direction::Right].into_iter()
                } else if *state == 2 {
                    vec![Direction::Left].into_iter()
                }
                else {
                    vec![].into_iter()
                }
            }

            fn next_state(&self, state: &i32, action: &Direction) -> i32 {
                match *state {
                    0 => match *action {
                        Direction::Left => 1,
                        Direction::Right => 2,
                    },
                    1 => match *action {
                        Direction::Left => 3,
                        Direction::Right => 4,
                    },
                    2 => 2,
                    node => node
                }
            }

            fn is_goal(&self, state: &i32) -> bool {
                return self.goal == *state
            }
        }

        impl S {
            fn solve(start: i32, goal: i32) -> Option<Vec<Direction>> {
                let space = S { goal: goal };
                depth_first_search(&space, start)
            }
        }

        assert_eq!(S::solve(0, 0).unwrap(), vec![]);
        assert_eq!(S::solve(0, 1).unwrap(), vec![Direction::Left]);
        assert_eq!(S::solve(0, 2).unwrap(), vec![Direction::Right]);
        assert_eq!(S::solve(0, 3).unwrap(), vec![Direction::Left, Direction::Left]);
        assert_eq!(S::solve(0, 4).unwrap(), vec![Direction::Left, Direction::Right]);
        assert_eq!(S::solve(2, 2).unwrap(), vec![]);
        assert!(S::solve(2, 0).is_none());
        assert!(S::solve(5, 0).is_none());
    }
}
<commit_msg>Refactoring<commit_after>use std::iter::Iterator;
use std::collections::HashSet;
use std::hash::{Hash, Hasher, SipHasher};

pub trait SearchSpace {
    type State: Hash;
    type Action;
    type Iterator: Iterator<Item=(Self::Action, Self::State)>;

    fn expand(&self, state: &Self::State) -> Self::Iterator;
    fn is_goal(&self, state: &Self::State) -> bool;
}

pub fn depth_first_search<S>(space: &S, start: S::State) -> Option<Vec<S::Action>>
where S: SearchSpace {
    if space.is_goal(&start) {
        return Some(vec![]);
    }

    let mut path = Vec::new();
    let mut visited = HashSet::new();
    let mut frontier = vec![space.expand(&start)];

    loop {
        let result = match frontier.last_mut() {
            None => return None,
            Some(&mut ref mut iter) => {
                match iter.next() {
                    None => {
                        path.pop();
                        None
                    },
                    Some((action, state)) => {
                        let mut hasher = SipHasher::new();
                        state.hash(&mut hasher);
                        let hash = hasher.finish();
                        if visited.contains(&hash) {
                            continue;
                        }
                        visited.insert(hash);

                        path.push(action);
                        if space.is_goal(&state) {
                            return Some(path);
                        }
                        Some(space.expand(&state))
                    }
                }
            }
        };
        match result {
            None => {
                frontier.pop();
            }
            Some(iter) => {
                frontier.push(iter);
            }
        };
    }
}

#[cfg(test)]
pub mod tests {
    use std::vec::IntoIter;
    use super::*;

    #[test]
    pub fn test_depth_first_search() {
        struct S {
            goal: i32,
        }

        #[derive(Debug, PartialEq)]
        enum Direction {
            Left,
            Right
        }

        impl SearchSpace for S {
            type State = i32;
            type Action = Direction;
            type Iterator = IntoIter<(Self::Action, Self::State)>;

            fn expand(&self, state: &Self::State) -> Self::Iterator {
                if *state == 0 {
                    vec![(Direction::Left, 1), (Direction::Right, 2)].into_iter()
                } else if *state == 1 {
                    vec![(Direction::Left, 3), (Direction::Right, 4)].into_iter()
                } else if *state == 2 {
                    vec![(Direction::Left, 2)].into_iter()
                } else {
                    vec![].into_iter()
                }
            }

            fn is_goal(&self, state: &i32) -> bool {
                return self.goal == *state
            }
        }

        impl S {
            fn solve(start: i32, goal: i32) -> Option<Vec<Direction>> {
                let space = S { goal: goal };
                depth_first_search(&space, start)
            }
        }

        assert_eq!(S::solve(0, 0).unwrap(), vec![]);
        assert_eq!(S::solve(0, 1).unwrap(), vec![Direction::Left]);
        assert_eq!(S::solve(0, 2).unwrap(), vec![Direction::Right]);
        assert_eq!(S::solve(0, 3).unwrap(), vec![Direction::Left, Direction::Left]);
        assert_eq!(S::solve(0, 4).unwrap(), vec![Direction::Left, Direction::Right]);
        assert_eq!(S::solve(2, 2).unwrap(), vec![]);
        assert!(S::solve(2, 0).is_none());
        assert!(S::solve(5, 0).is_none());
    }
}
<|endoftext|>


<commit_before>//! A data type suitable for storing sensitive information such as passwords and private keys in memory, featuring constant time equality, mlock and zeroing out.
extern crate libc;
use std::fmt;
use std::borrow::Borrow;
use std::borrow::BorrowMut;
use libc::funcs::posix88::mman;

/// A data type suitable for storing sensitive information such as passwords and private keys in memory, that implements:
///
/// - Automatic zeroing in `Drop`
/// - Constant time comparison in `PartialEq`
/// - Outputting `***SECRET***` to prevent leaking secrets into logs in `fmt::Debug` and `fmt::Display`
/// - Automatic `mlock` to protect against leaking into swap
pub struct SecStr {
    content: Vec<u8>
}

impl SecStr {
    #[inline(never)]
    pub fn zero_out(&mut self) {
        unsafe {
            std::ptr::write_bytes(self.content.as_ptr() as *mut libc::c_void, 0, self.content.len());
        }
    }

    pub fn new(cont: Vec<u8>) -> SecStr {
        unsafe {
            mman::mlock(cont.as_ptr() as *const libc::c_void, cont.len() as libc::size_t);
        }
        SecStr { content: cont }
    }

    pub fn unsecure<'r>(&'r self) -> &'r [u8] {
        self.borrow()
    }

    pub fn unsecure_mut<'r>(&'r mut self) -> &'r mut [u8] {
        self.borrow_mut()
    }
}

// Creation
impl<T> From<T> for SecStr where T: Into<Vec<u8>> {
    fn from(s: T) -> SecStr {
        SecStr::new(s.into())
    }
}

// Borrowing
impl Borrow<[u8]> for SecStr {
    fn borrow(&self) -> &[u8] {
        self.content.borrow()
    }
}

impl BorrowMut<[u8]> for SecStr {
    fn borrow_mut(&mut self) -> &mut [u8] {
        self.content.borrow_mut()
    }
}

// Overwrite memory with zeros when we're done
impl Drop for SecStr {
    fn drop(&mut self) {
        self.zero_out();
        unsafe {
            mman::munlock(self.content.as_ptr() as *const libc::c_void, self.content.len() as libc::size_t);
        }
    }
}

// Constant time comparison
impl PartialEq for SecStr {
    #[inline(never)]
    fn eq(&self, other: &SecStr) -> bool {
        let ref us = self.content;
        let ref them = other.content;
        if us.len() != them.len() {
            return false;
        }
        let mut result = 0;
        for i in 0..us.len() {
            result |= us[i] ^ them[i];
        }
        result == 0
    }
}

// Make sure sensitive information is not logged accidentally
impl fmt::Debug for SecStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("***SECRET***").map_err(|_| { fmt::Error })
    }
}

impl fmt::Display for SecStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("***SECRET***").map_err(|_| { fmt::Error })
    }
}

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

    #[test]
    fn test_basic() {
        let my_sec = SecStr::from("hello");
        assert_eq!(my_sec, SecStr::from("hello".to_string()));
        assert_eq!(my_sec.unsecure(), b"hello");
    }

    #[test]
    fn test_zero_out() {
        let mut my_sec = SecStr::from("hello");
        my_sec.zero_out();
        assert_eq!(my_sec.unsecure(), b"\x00\x00\x00\x00\x00");
    }

    #[test]
    fn test_comparison() {
        assert_eq!(SecStr::from("hello"),  SecStr::from("hello"));
        assert!(  SecStr::from("hello") != SecStr::from("yolo"));
        assert!(  SecStr::from("hello") != SecStr::from("olleh"));
    }

    #[test]
    fn test_show() {
        assert_eq!(format!("{}", SecStr::from("hello")), "***SECRET***".to_string());
    }

}
<commit_msg>mlock only on unix<commit_after>//! A data type suitable for storing sensitive information such as passwords and private keys in memory, featuring constant time equality, mlock and zeroing out.
extern crate libc;
use std::fmt;
use std::borrow::Borrow;
use std::borrow::BorrowMut;

/// A data type suitable for storing sensitive information such as passwords and private keys in memory, that implements:
///
/// - Automatic zeroing in `Drop`
/// - Constant time comparison in `PartialEq`
/// - Outputting `***SECRET***` to prevent leaking secrets into logs in `fmt::Debug` and `fmt::Display`
/// - Automatic `mlock` to protect against leaking into swap
pub struct SecStr {
    content: Vec<u8>
}

impl SecStr {
    #[inline(never)]
    pub fn zero_out(&mut self) {
        unsafe {
            std::ptr::write_bytes(self.content.as_ptr() as *mut libc::c_void, 0, self.content.len());
        }
    }

    pub fn new(cont: Vec<u8>) -> SecStr {
        memlock::mlock(&cont);
        SecStr { content: cont }
    }

    pub fn unsecure(&self) -> &[u8] {
        self.borrow()
    }

    pub fn unsecure_mut(&mut self) -> &mut [u8] {
        self.borrow_mut()
    }
}

// Creation
impl<T> From<T> for SecStr where T: Into<Vec<u8>> {
    fn from(s: T) -> SecStr {
        SecStr::new(s.into())
    }
}

// Borrowing
impl Borrow<[u8]> for SecStr {
    fn borrow(&self) -> &[u8] {
        self.content.borrow()
    }
}

impl BorrowMut<[u8]> for SecStr {
    fn borrow_mut(&mut self) -> &mut [u8] {
        self.content.borrow_mut()
    }
}

// Overwrite memory with zeros when we're done
impl Drop for SecStr {
    fn drop(&mut self) {
        self.zero_out();
        memlock::munlock(&self.content);
    }
}

// Constant time comparison
impl PartialEq for SecStr {
    #[inline(never)]
    fn eq(&self, other: &SecStr) -> bool {
        let ref us = self.content;
        let ref them = other.content;
        if us.len() != them.len() {
            return false;
        }
        let mut result = 0;
        for i in 0..us.len() {
            result |= us[i] ^ them[i];
        }
        result == 0
    }
}

// Make sure sensitive information is not logged accidentally
impl fmt::Debug for SecStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("***SECRET***").map_err(|_| { fmt::Error })
    }
}

impl fmt::Display for SecStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("***SECRET***").map_err(|_| { fmt::Error })
    }
}

#[cfg(unix)]
mod memlock {
    extern crate libc;
    use self::libc::funcs::posix88::mman;

    pub fn mlock(cont: &Vec<u8>) {
        unsafe {
            mman::mlock(cont.as_ptr() as *const libc::c_void, cont.len() as libc::size_t);
        }
    }

    pub fn munlock(cont: &Vec<u8>) {
        unsafe {
            mman::munlock(cont.as_ptr() as *const libc::c_void, cont.len() as libc::size_t);
        }
    }
}

#[cfg(not(unix))]
mod memlock {
    fn mlock(cont: &Vec<u8>) {
    }

    fn munlock(cont: &Vec<u8>) {
    }
}

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

    #[test]
    fn test_basic() {
        let my_sec = SecStr::from("hello");
        assert_eq!(my_sec, SecStr::from("hello".to_string()));
        assert_eq!(my_sec.unsecure(), b"hello");
    }

    #[test]
    fn test_zero_out() {
        let mut my_sec = SecStr::from("hello");
        my_sec.zero_out();
        assert_eq!(my_sec.unsecure(), b"\x00\x00\x00\x00\x00");
    }

    #[test]
    fn test_comparison() {
        assert_eq!(SecStr::from("hello"),  SecStr::from("hello"));
        assert!(  SecStr::from("hello") != SecStr::from("yolo"));
        assert!(  SecStr::from("hello") != SecStr::from("olleh"));
    }

    #[test]
    fn test_show() {
        assert_eq!(format!("{}", SecStr::from("hello")), "***SECRET***".to_string());
    }

}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::thread;
use std::sync::mpsc::channel;

/// Compute the frequency of each letter (technically of each unicode codepoint) using the given
/// number of worker threads.
pub fn frequency(texts: &[&str], num_workers: usize) -> HashMap<char, usize> {
    assert!(num_workers > 0);
    let part_size_floor = texts.len() / num_workers;
    let rem = texts.len() % num_workers;
    let part_size = if rem > 0 { part_size_floor + 1 } else { part_size_floor };
    let mut parts: Vec<Vec<String>> = Vec::with_capacity(part_size);
    for _ in 0 .. num_workers {
        parts.push(Vec::with_capacity(part_size));
    }
    let mut i = 0;
    for line in texts.iter() {
        // We'll need to clone those strings in order to satisfy some lifetime guarantees. Basically
        // it's hard for the system to be sure that the threads spawned don't outlive the strings.
        parts[i].push(line.to_string());
        i = (i + 1) % num_workers;
    }

    let (tx, rx) = channel();

    for part in parts {
        let tx = tx.clone();
        thread::spawn(move || {
            tx.send(count(part)).unwrap();
        });
    }

    let mut results: HashMap<char, usize> = HashMap::new();
    for _ in 0..num_workers {
        let part_results = rx.recv().unwrap();
        for (c, n) in part_results.into_iter() {
            match results.entry(c) {
                Entry::Vacant(view) => { view.insert(n); },
                Entry::Occupied(mut view) => {
                    *view.get_mut() += n;
                }
            }
        }
    }
    results
}

fn count(lines: Vec<String>) -> HashMap<char, usize> {
    let mut results: HashMap<char, usize> = HashMap::new();
    for line in lines.iter() {
        for c in line.chars() {
            if c.is_alphabetic() {
                match results.entry(c.to_lowercase().next().unwrap()) {
                    Entry::Vacant(view) => { view.insert(1); },
                    Entry::Occupied(mut view) => {
                        *view.get_mut() += 1;
                    }
                }
            }
        }
    }
    results
}
<commit_msg>parallel-letter-frequency: Use `Entry#or_insert`<commit_after>use std::collections::HashMap;
use std::thread;
use std::sync::mpsc::channel;

/// Compute the frequency of each letter (technically of each unicode codepoint) using the given
/// number of worker threads.
pub fn frequency(texts: &[&str], num_workers: usize) -> HashMap<char, usize> {
    assert!(num_workers > 0);
    let part_size_floor = texts.len() / num_workers;
    let rem = texts.len() % num_workers;
    let part_size = if rem > 0 { part_size_floor + 1 } else { part_size_floor };
    let mut parts: Vec<Vec<String>> = Vec::with_capacity(part_size);
    for _ in 0 .. num_workers {
        parts.push(Vec::with_capacity(part_size));
    }
    let mut i = 0;
    for line in texts.iter() {
        // We'll need to clone those strings in order to satisfy some lifetime guarantees. Basically
        // it's hard for the system to be sure that the threads spawned don't outlive the strings.
        parts[i].push(line.to_string());
        i = (i + 1) % num_workers;
    }

    let (tx, rx) = channel();

    for part in parts {
        let tx = tx.clone();
        thread::spawn(move || {
            tx.send(count(part)).unwrap();
        });
    }

    let mut results: HashMap<char, usize> = HashMap::new();
    for _ in 0..num_workers {
        let part_results = rx.recv().unwrap();
        for (c, n) in part_results.into_iter() {
            *results.entry(c).or_insert(0) += n;
        }
    }
    results
}

fn count(lines: Vec<String>) -> HashMap<char, usize> {
    let mut results: HashMap<char, usize> = HashMap::new();
    for line in lines.iter() {
        for c in line.chars() {
            if c.is_alphabetic() {
                *results.entry(c.to_lowercase().next().unwrap()).or_insert(0) += 1;
            }
        }
    }
    results
}
<|endoftext|>


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

//! The [`Server`](trait.Server.html) trait and helpers.
//!
//! The `Server` trait for the use by the [`Endpoint`](../endpoint/struct.Endpoint.html) is defined
//! here. Furthermore, some helpers for convenient creation and composition of servers are
//! available. Note that not all of these helpers are necessarily zero-cost, at least at this time.

use futures::{Future, IntoFuture};
use serde::Serialize;
use serde_json::{Value, to_value};

use endpoint::ServerCtl;
use message::RpcError;

/// The server endpoint.
///
/// This is usually implemented by the end application and provides the actual functionality of the
/// RPC server. It allows composition of more servers together.
///
/// The default implementations of the callbacks return None, indicating that the given method is
/// not known. It allows implementing only RPCs or only notifications without having to worry about
/// the other callback. If you want a server that does nothing at all, use
/// [`Empty`](struct.Empty.html).
pub trait Server {
    /// The successfull result of the RPC call.
    type Success: Serialize;
    /// The result of the RPC call
    ///
    /// Once the future resolves, the value or error is sent to the client as the reply. The reply
    /// is wrapped automatically.
    type RpcCallResult: IntoFuture<Item = Self::Success, Error = RpcError> + 'static;
    /// The result of the RPC call.
    ///
    /// As the client doesn't expect anything in return, both the success and error results are
    /// thrown away and therefore (). However, it still makes sense to distinguish success and
    /// error.
    type NotificationResult: IntoFuture<Item = (), Error = ()> + 'static;
    /// Called when the client requests something.
    ///
    /// This is a callback from the [endpoint](struct.Endpoint.html) when the client requests
    /// something. If the method is unknown, it shall return `None`. This allows composition of
    /// servers.
    ///
    /// Conversion of parameters and handling of errors is up to the implementer of this trait.
    fn rpc(&self, _ctl: &ServerCtl, _method: &str, _params: &Option<Value>)
           -> Option<Self::RpcCallResult> {
        None
    }
    /// Called when the client sends a notification.
    ///
    /// This is a callback from the [endpoint](struct.Endpoint.html) when the client requests
    /// something. If the method is unknown, it shall return `None`. This allows composition of
    /// servers.
    ///
    /// Conversion of parameters and handling of errors is up to the implementer of this trait.
    fn notification(&self, _ctl: &ServerCtl, _method: &str, _params: &Option<Value>)
                    -> Option<Self::NotificationResult> {
        None
    }
    /// Called when the endpoint is initialized.
    ///
    /// It provides a default empty implementation, which can be overriden to hook onto the
    /// initialization.
    fn initialized(&self, _ctl: &ServerCtl) {}
}

/// A RPC server that knows no methods.
///
/// You can use this if you want to have a client-only [Endpoint](struct.Endpoint.html). It simply
/// terminates the server part right away. Or, more conveniently, use `Endpoint`'s
/// [`client_only`](struct.Endpoint.html#method.client_only) method.
pub struct Empty;

impl Server for Empty {
    type Success = ();
    type RpcCallResult = Result<(), RpcError>;
    type NotificationResult = Result<(), ()>;
    fn initialized(&self, ctl: &ServerCtl) {
        ctl.terminate();
    }
}

/// An RPC server wrapper with dynamic dispatch.
///
/// This server wraps another server and converts it into a common ground, so multiple different
/// servers can be used as trait objects. Basically, it boxes the futures it returns and converts
/// the result into `serde_json::Value`. It can then be used together with
/// [`ServerChain`](struct.ServerChain.html) easilly. Note that this conversion incurs
/// runtime costs.
pub struct AbstractServer<S: Server>(S);

impl<S: Server> AbstractServer<S> {
    /// Wraps another server into an abstract server.
    pub fn new(server: S) -> Self {
        AbstractServer(server)
    }
    /// Unwraps the abstract server and provides the one inside back.
    pub fn into_inner(self) -> S {
        self.0
    }
}

/// A RPC call result wrapping trait objects.
pub type BoxRpcCallResult = Box<Future<Item = Value, Error = RpcError>>;
/// A notification call result wrapping trait objects.
pub type BoxNotificationResult = Box<Future<Item = (), Error = ()>>;

impl<S: Server> Server for AbstractServer<S> {
    type Success = Value;
    type RpcCallResult = BoxRpcCallResult;
    type NotificationResult = BoxNotificationResult;
    fn rpc(&self, ctl: &ServerCtl, method: &str, params: &Option<Value>)
           -> Option<Self::RpcCallResult> {
        self.0
            .rpc(ctl, method, params)
            .map(|f| -> Box<Future<Item = Value, Error = RpcError>> {
                let future = f.into_future()
                    .map(|result| {
                        to_value(result)
                            .expect("Your result type is not convertible to JSON, which is a bug")
                    });
                Box::new(future)
            })
    }
    fn notification(&self, ctl: &ServerCtl, method: &str, params: &Option<Value>)
                    -> Option<Self::NotificationResult> {
        // It seems the type signature is computed from inside the closure and it doesn't fit on
        // the outside, so we need to declare it manually :-(
        self.0
            .notification(ctl, method, params)
            .map(|f| -> Box<Future<Item = (), Error = ()>> { Box::new(f.into_future()) })
    }
    fn initialized(&self, ctl: &ServerCtl) {
        self.0.initialized(ctl)
    }
}

/// A type to store servers as trait objects.
///
/// See also [`AbstractServer`](struct.AbstractServer.html) and
/// [`ServerChain`](struct.ServerChain.html).
pub type BoxServer = Box<Server<Success = Value,
                                RpcCallResult = Box<Future<Item = Value, Error = RpcError>>,
                                NotificationResult = Box<Future<Item = (), Error = ()>>>>;

/// A server that chains several other servers.
///
/// This composes multiple servers into one. When a notification or an rpc comes, it tries one by
/// one and passes the call to each of them. If the server provides an answer, the iteration is
/// stopped and that answer is returned. If the server refuses the given method name, another
/// server in the chain is tried, until one is found or we run out of servers.
///
/// Initialization is called on all the servers.
///
/// The [`AbstractServer`](struct.AbstractServer.html) is one of the ways to plug servers with
/// incompatible future and success types inside.
pub struct ServerChain(Vec<BoxServer>);

impl ServerChain {
    /// Construct a new server.
    pub fn new(subservers: Vec<BoxServer>) -> Self {
        ServerChain(subservers)
    }
    /// Consume the server and return the subservers inside.
    pub fn into_inner(self) -> Vec<BoxServer> {
        self.0
    }
    /// Iterate through the servers and return the first result that is `Some(_)`.
    fn iter_chain<R, F: Fn(&BoxServer) -> Option<R>>(&self, f: F) -> Option<R> {
        for sub in self.0.iter() {
            let result = f(sub);
            if result.is_some() {
                return result;
            }
        }
        None
    }
}

impl Server for ServerChain {
    type Success = Value;
    type RpcCallResult = BoxRpcCallResult;
    type NotificationResult = BoxNotificationResult;
    fn rpc(&self, ctl: &ServerCtl, method: &str, params: &Option<Value>)
           -> Option<Self::RpcCallResult> {
        self.iter_chain(|sub| sub.rpc(ctl, method, params))
    }
    fn notification(&self, ctl: &ServerCtl, method: &str, params: &Option<Value>)
                    -> Option<Self::NotificationResult> {
        self.iter_chain(|sub| sub.notification(ctl, method, params))
    }
    fn initialized(&self, ctl: &ServerCtl) {
        for sub in self.0.iter() {
            sub.initialized(ctl);
        }
    }
}

#[cfg(test)]
mod tests {
    use std::cell::{Cell, RefCell};

    use super::*;

    /// Check the empty server is somewhat sane.
    #[test]
    fn empty() {
        let server = Empty;
        let (ctl, dropped, _killed) = ServerCtl::new_test();
        // As we can't reasonably check all possible method names, do so for just a bunch
        for method in ["method", "notification", "check"].iter() {
            assert!(server.rpc(&ctl, method, &None).is_none());
            assert!(server.notification(&ctl, method, &None).is_none());
        }
        // It terminates the ctl on the server side on initialization
        server.initialized(&ctl);
        dropped.wait().unwrap();
    }

    /// A server that logs what has been called.
    #[derive(Default, Debug, PartialEq)]
    struct LogServer {
        serial: Cell<usize>,
        rpc: RefCell<Vec<usize>>,
        notification: RefCell<Vec<usize>>,
        initialized: RefCell<Vec<usize>>,
    }

    impl LogServer {
        fn update(&self, what: &RefCell<Vec<usize>>) {
            let serial = self.serial.get() + 1;
            self.serial.set(serial);
            what.borrow_mut().push(serial);
        }
    }

    impl Server for LogServer {
        type Success = bool;
        type RpcCallResult = Result<bool, RpcError>;
        type NotificationResult = Result<(), ()>;
        fn rpc(&self, _ctl: &ServerCtl, method: &str, params: &Option<Value>)
               -> Option<Self::RpcCallResult> {
            self.update(&self.rpc);
            match method {
                "test" => {
                    assert!(params.is_none());
                    Some(Ok(true))
                },
                _ => None,
            }
        }
        fn notification(&self, _ctl: &ServerCtl, method: &str, params: &Option<Value>)
                        -> Option<Self::NotificationResult> {
            self.update(&self.notification);
            assert!(params.is_none());
            match method {
                "notification" => Some(Ok(())),
                _ => None,
            }
        }
        fn initialized(&self, _ctl: &ServerCtl) {
            self.update(&self.initialized);
        }
    }

    /// Testing of the abstract server
    ///
    /// Just checking the data gets through and calling everything, there's nothing much to test
    /// anyway.
    #[test]
    fn abstract_server() {
        let log_server = LogServer::default();
        let abstract_server = AbstractServer::new(log_server);
        let (ctl, _, _) = ServerCtl::new_test();
        let rpc_result = abstract_server.rpc(&ctl, "test", &None)
            .unwrap()
            .wait()
            .unwrap();
        assert_eq!(Value::Bool(true), rpc_result);
        abstract_server.notification(&ctl, "notification", &None)
            .unwrap()
            .wait()
            .unwrap();
        assert!(abstract_server.rpc(&ctl, "another", &None).is_none());
        assert!(abstract_server.notification(&ctl, "another", &None).is_none());
        abstract_server.initialized(&ctl);
        let log_server = abstract_server.into_inner();
        let expected = LogServer {
            serial: Cell::new(5),
            rpc: RefCell::new(vec![1, 3]),
            notification: RefCell::new(vec![2, 4]),
            initialized: RefCell::new(vec![5]),
        };
        assert_eq!(expected, log_server);
    }

    struct AnotherServer;

    impl Server for AnotherServer {
        type Success = usize;
        type RpcCallResult = Result<usize, RpcError>;
        type NotificationResult = Result<(), ()>;
        fn rpc(&self, _ctl: &ServerCtl, method: &str, params: &Option<Value>)
               -> Option<Self::RpcCallResult> {
            assert!(params.as_ref()
                        .unwrap()
                        .is_null());
            match method {
                "another" => Some(Ok(42)),
                _ => None,
            }
        }
        // Ignore the other methods
    }

    /// Test the chain.
    ///
    /// By the asserts on params in the servers we check that only whan should be called is.
    #[test]
    fn chain() {
        let empty_server = Empty;
        let log_server = LogServer::default();
        let another_server = AnotherServer;
        let (ctl, dropped, _killed) = ServerCtl::new_test();
        let chain = ServerChain::new(vec![Box::new(AbstractServer::new(empty_server)),
                                          Box::new(AbstractServer::new(log_server)),
                                          Box::new(AbstractServer::new(another_server))]);
        chain.initialized(&ctl);
        dropped.wait().unwrap();
        assert_eq!(Value::Bool(true),
                   chain.rpc(&ctl, "test", &None)
                       .unwrap()
                       .wait()
                       .unwrap());
        assert_eq!(json!(42),
                   chain.rpc(&ctl, "another", &Some(Value::Null))
                       .unwrap()
                       .wait()
                       .unwrap());
        assert!(chain.rpc(&ctl, "wrong", &Some(Value::Null)).is_none());
        chain.notification(&ctl, "notification", &None)
            .unwrap()
            .wait()
            .unwrap();
        assert!(chain.notification(&ctl, "another", &None).is_none());
        // It would be great to check what is logged inside the log server. But downcasting a trait
        // object seems to be a big pain and probably isn't worth it here.
    }
}
<commit_msg>More idiomatic code<commit_after>// Copyright 2017 tokio-jsonrpc Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! The [`Server`](trait.Server.html) trait and helpers.
//!
//! The `Server` trait for the use by the [`Endpoint`](../endpoint/struct.Endpoint.html) is defined
//! here. Furthermore, some helpers for convenient creation and composition of servers are
//! available. Note that not all of these helpers are necessarily zero-cost, at least at this time.

use futures::{Future, IntoFuture};
use serde::Serialize;
use serde_json::{Value, to_value};

use endpoint::ServerCtl;
use message::RpcError;

/// The server endpoint.
///
/// This is usually implemented by the end application and provides the actual functionality of the
/// RPC server. It allows composition of more servers together.
///
/// The default implementations of the callbacks return None, indicating that the given method is
/// not known. It allows implementing only RPCs or only notifications without having to worry about
/// the other callback. If you want a server that does nothing at all, use
/// [`Empty`](struct.Empty.html).
pub trait Server {
    /// The successfull result of the RPC call.
    type Success: Serialize;
    /// The result of the RPC call
    ///
    /// Once the future resolves, the value or error is sent to the client as the reply. The reply
    /// is wrapped automatically.
    type RpcCallResult: IntoFuture<Item = Self::Success, Error = RpcError> + 'static;
    /// The result of the RPC call.
    ///
    /// As the client doesn't expect anything in return, both the success and error results are
    /// thrown away and therefore (). However, it still makes sense to distinguish success and
    /// error.
    type NotificationResult: IntoFuture<Item = (), Error = ()> + 'static;
    /// Called when the client requests something.
    ///
    /// This is a callback from the [endpoint](struct.Endpoint.html) when the client requests
    /// something. If the method is unknown, it shall return `None`. This allows composition of
    /// servers.
    ///
    /// Conversion of parameters and handling of errors is up to the implementer of this trait.
    fn rpc(&self, _ctl: &ServerCtl, _method: &str, _params: &Option<Value>)
           -> Option<Self::RpcCallResult> {
        None
    }
    /// Called when the client sends a notification.
    ///
    /// This is a callback from the [endpoint](struct.Endpoint.html) when the client requests
    /// something. If the method is unknown, it shall return `None`. This allows composition of
    /// servers.
    ///
    /// Conversion of parameters and handling of errors is up to the implementer of this trait.
    fn notification(&self, _ctl: &ServerCtl, _method: &str, _params: &Option<Value>)
                    -> Option<Self::NotificationResult> {
        None
    }
    /// Called when the endpoint is initialized.
    ///
    /// It provides a default empty implementation, which can be overriden to hook onto the
    /// initialization.
    fn initialized(&self, _ctl: &ServerCtl) {}
}

/// A RPC server that knows no methods.
///
/// You can use this if you want to have a client-only [Endpoint](struct.Endpoint.html). It simply
/// terminates the server part right away. Or, more conveniently, use `Endpoint`'s
/// [`client_only`](struct.Endpoint.html#method.client_only) method.
pub struct Empty;

impl Server for Empty {
    type Success = ();
    type RpcCallResult = Result<(), RpcError>;
    type NotificationResult = Result<(), ()>;
    fn initialized(&self, ctl: &ServerCtl) {
        ctl.terminate();
    }
}

/// An RPC server wrapper with dynamic dispatch.
///
/// This server wraps another server and converts it into a common ground, so multiple different
/// servers can be used as trait objects. Basically, it boxes the futures it returns and converts
/// the result into `serde_json::Value`. It can then be used together with
/// [`ServerChain`](struct.ServerChain.html) easilly. Note that this conversion incurs
/// runtime costs.
pub struct AbstractServer<S: Server>(S);

impl<S: Server> AbstractServer<S> {
    /// Wraps another server into an abstract server.
    pub fn new(server: S) -> Self {
        AbstractServer(server)
    }
    /// Unwraps the abstract server and provides the one inside back.
    pub fn into_inner(self) -> S {
        self.0
    }
}

/// A RPC call result wrapping trait objects.
pub type BoxRpcCallResult = Box<Future<Item = Value, Error = RpcError>>;
/// A notification call result wrapping trait objects.
pub type BoxNotificationResult = Box<Future<Item = (), Error = ()>>;

impl<S: Server> Server for AbstractServer<S> {
    type Success = Value;
    type RpcCallResult = BoxRpcCallResult;
    type NotificationResult = BoxNotificationResult;
    fn rpc(&self, ctl: &ServerCtl, method: &str, params: &Option<Value>)
           -> Option<Self::RpcCallResult> {
        self.0
            .rpc(ctl, method, params)
            .map(|f| -> Box<Future<Item = Value, Error = RpcError>> {
                let future = f.into_future()
                    .map(|result| {
                        to_value(result)
                            .expect("Your result type is not convertible to JSON, which is a bug")
                    });
                Box::new(future)
            })
    }
    fn notification(&self, ctl: &ServerCtl, method: &str, params: &Option<Value>)
                    -> Option<Self::NotificationResult> {
        // It seems the type signature is computed from inside the closure and it doesn't fit on
        // the outside, so we need to declare it manually :-(
        self.0
            .notification(ctl, method, params)
            .map(|f| -> Box<Future<Item = (), Error = ()>> { Box::new(f.into_future()) })
    }
    fn initialized(&self, ctl: &ServerCtl) {
        self.0.initialized(ctl)
    }
}

/// A type to store servers as trait objects.
///
/// See also [`AbstractServer`](struct.AbstractServer.html) and
/// [`ServerChain`](struct.ServerChain.html).
pub type BoxServer = Box<Server<Success = Value,
                                RpcCallResult = Box<Future<Item = Value, Error = RpcError>>,
                                NotificationResult = Box<Future<Item = (), Error = ()>>>>;

/// A server that chains several other servers.
///
/// This composes multiple servers into one. When a notification or an rpc comes, it tries one by
/// one and passes the call to each of them. If the server provides an answer, the iteration is
/// stopped and that answer is returned. If the server refuses the given method name, another
/// server in the chain is tried, until one is found or we run out of servers.
///
/// Initialization is called on all the servers.
///
/// The [`AbstractServer`](struct.AbstractServer.html) is one of the ways to plug servers with
/// incompatible future and success types inside.
pub struct ServerChain(Vec<BoxServer>);

impl ServerChain {
    /// Construct a new server.
    pub fn new(subservers: Vec<BoxServer>) -> Self {
        ServerChain(subservers)
    }
    /// Consume the server and return the subservers inside.
    pub fn into_inner(self) -> Vec<BoxServer> {
        self.0
    }
    /// Iterate through the servers and return the first result that is `Some(_)`.
    fn iter_chain<R, F: Fn(&BoxServer) -> Option<R>>(&self, f: F) -> Option<R> {
        for sub in &self.0 {
            let result = f(sub);
            if result.is_some() {
                return result;
            }
        }
        None
    }
}

impl Server for ServerChain {
    type Success = Value;
    type RpcCallResult = BoxRpcCallResult;
    type NotificationResult = BoxNotificationResult;
    fn rpc(&self, ctl: &ServerCtl, method: &str, params: &Option<Value>)
           -> Option<Self::RpcCallResult> {
        self.iter_chain(|sub| sub.rpc(ctl, method, params))
    }
    fn notification(&self, ctl: &ServerCtl, method: &str, params: &Option<Value>)
                    -> Option<Self::NotificationResult> {
        self.iter_chain(|sub| sub.notification(ctl, method, params))
    }
    fn initialized(&self, ctl: &ServerCtl) {
        for sub in &self.0 {
            sub.initialized(ctl);
        }
    }
}

#[cfg(test)]
mod tests {
    use std::cell::{Cell, RefCell};

    use super::*;

    /// Check the empty server is somewhat sane.
    #[test]
    fn empty() {
        let server = Empty;
        let (ctl, dropped, _killed) = ServerCtl::new_test();
        // As we can't reasonably check all possible method names, do so for just a bunch
        for method in ["method", "notification", "check"].iter() {
            assert!(server.rpc(&ctl, method, &None).is_none());
            assert!(server.notification(&ctl, method, &None).is_none());
        }
        // It terminates the ctl on the server side on initialization
        server.initialized(&ctl);
        dropped.wait().unwrap();
    }

    /// A server that logs what has been called.
    #[derive(Default, Debug, PartialEq)]
    struct LogServer {
        serial: Cell<usize>,
        rpc: RefCell<Vec<usize>>,
        notification: RefCell<Vec<usize>>,
        initialized: RefCell<Vec<usize>>,
    }

    impl LogServer {
        fn update(&self, what: &RefCell<Vec<usize>>) {
            let serial = self.serial.get() + 1;
            self.serial.set(serial);
            what.borrow_mut().push(serial);
        }
    }

    impl Server for LogServer {
        type Success = bool;
        type RpcCallResult = Result<bool, RpcError>;
        type NotificationResult = Result<(), ()>;
        fn rpc(&self, _ctl: &ServerCtl, method: &str, params: &Option<Value>)
               -> Option<Self::RpcCallResult> {
            self.update(&self.rpc);
            match method {
                "test" => {
                    assert!(params.is_none());
                    Some(Ok(true))
                },
                _ => None,
            }
        }
        fn notification(&self, _ctl: &ServerCtl, method: &str, params: &Option<Value>)
                        -> Option<Self::NotificationResult> {
            self.update(&self.notification);
            assert!(params.is_none());
            match method {
                "notification" => Some(Ok(())),
                _ => None,
            }
        }
        fn initialized(&self, _ctl: &ServerCtl) {
            self.update(&self.initialized);
        }
    }

    /// Testing of the abstract server
    ///
    /// Just checking the data gets through and calling everything, there's nothing much to test
    /// anyway.
    #[test]
    fn abstract_server() {
        let log_server = LogServer::default();
        let abstract_server = AbstractServer::new(log_server);
        let (ctl, _, _) = ServerCtl::new_test();
        let rpc_result = abstract_server.rpc(&ctl, "test", &None)
            .unwrap()
            .wait()
            .unwrap();
        assert_eq!(Value::Bool(true), rpc_result);
        abstract_server.notification(&ctl, "notification", &None)
            .unwrap()
            .wait()
            .unwrap();
        assert!(abstract_server.rpc(&ctl, "another", &None).is_none());
        assert!(abstract_server.notification(&ctl, "another", &None).is_none());
        abstract_server.initialized(&ctl);
        let log_server = abstract_server.into_inner();
        let expected = LogServer {
            serial: Cell::new(5),
            rpc: RefCell::new(vec![1, 3]),
            notification: RefCell::new(vec![2, 4]),
            initialized: RefCell::new(vec![5]),
        };
        assert_eq!(expected, log_server);
    }

    struct AnotherServer;

    impl Server for AnotherServer {
        type Success = usize;
        type RpcCallResult = Result<usize, RpcError>;
        type NotificationResult = Result<(), ()>;
        fn rpc(&self, _ctl: &ServerCtl, method: &str, params: &Option<Value>)
               -> Option<Self::RpcCallResult> {
            assert!(params.as_ref()
                        .unwrap()
                        .is_null());
            match method {
                "another" => Some(Ok(42)),
                _ => None,
            }
        }
        // Ignore the other methods
    }

    /// Test the chain.
    ///
    /// By the asserts on params in the servers we check that only whan should be called is.
    #[test]
    fn chain() {
        let empty_server = Empty;
        let log_server = LogServer::default();
        let another_server = AnotherServer;
        let (ctl, dropped, _killed) = ServerCtl::new_test();
        let chain = ServerChain::new(vec![Box::new(AbstractServer::new(empty_server)),
                                          Box::new(AbstractServer::new(log_server)),
                                          Box::new(AbstractServer::new(another_server))]);
        chain.initialized(&ctl);
        dropped.wait().unwrap();
        assert_eq!(Value::Bool(true),
                   chain.rpc(&ctl, "test", &None)
                       .unwrap()
                       .wait()
                       .unwrap());
        assert_eq!(json!(42),
                   chain.rpc(&ctl, "another", &Some(Value::Null))
                       .unwrap()
                       .wait()
                       .unwrap());
        assert!(chain.rpc(&ctl, "wrong", &Some(Value::Null)).is_none());
        chain.notification(&ctl, "notification", &None)
            .unwrap()
            .wait()
            .unwrap();
        assert!(chain.notification(&ctl, "another", &None).is_none());
        // It would be great to check what is logged inside the log server. But downcasting a trait
        // object seems to be a big pain and probably isn't worth it here.
    }
}
<|endoftext|>


<commit_before>extern crate gst;

use std::env;
use std::os::raw::c_void;
use std::mem;

extern "C" fn signal_callback(_src: *mut gst::GstElement, pad: *mut gst::GstPad, sinkpad: &mut gst::Pad){
    unsafe{
        if !sinkpad.is_linked(){
            let mut decodebin_pad = gst::Pad::new(pad).unwrap();
            let caps = decodebin_pad.query_caps(None).unwrap();
            let structure = caps.structure(0).unwrap();
            if structure.name().starts_with("video") {
                decodebin_pad.link(sinkpad).unwrap();
            }
        }
    }
}

fn main(){
    gst::init();
    let args: Vec<_> = env::args().collect();
    let uri: &str = if args.len() == 2 {
        args[1].as_ref()
    }else{
        panic!("Usage: pipeline file_path");
    };

    let mut pipeline = gst::Pipeline::new("video_player").expect("Couldn't create playbin");
    let mut filesrc = gst::Element::new("filesrc", "").unwrap();
    filesrc.set("location", uri);
    let mut decodebin = gst::Element::new("decodebin", "").unwrap();
    let mut sink = gst::Element::new("glimagesink", "").unwrap();
    let mut sink_pad = sink.static_pad("sink").unwrap();
    unsafe{
        decodebin.signal_connect("pad-added", mem::transmute(signal_callback as *mut c_void), &mut sink_pad);
    }
    if !pipeline.add_and_link(filesrc, decodebin){
        panic!("couldn't link filesrc and decodebin");
    }
    pipeline.add(sink);
    let mut mainloop = gst::MainLoop::new();
    let mut bus = pipeline.bus().expect("Couldn't get pipeline bus");
    let bus_receiver = bus.receiver();
    mainloop.spawn();
    pipeline.play();
    for message in bus_receiver.iter(){
        match message.parse(){
            gst::Message::StateChangedParsed{ref old, ref new, ..} => {
                println!("element `{}` changed from {:?} to {:?}", message.src_name(), old, new);
            }
            gst::Message::ErrorParsed{ref error, ref debug, ..} => {
				println!("error msg from element `{}`: {}, {}. Quitting", message.src_name(), error.message(), debug);
                break;
            }
            gst::Message::Eos(_) => {
                println!("eos received quiting");
                break;
            }
            _ => {
                println!("msg of type `{}` from element `{}`", message.type_name(), message.src_name());
            }
        }
    }
    mainloop.quit();
}
<commit_msg>decodebin example: use ffi prefix<commit_after>extern crate gst;

use std::env;
use std::os::raw::c_void;
use std::mem;

extern "C" fn signal_callback(_src: *mut gst::ffi::GstElement, pad: *mut gst::ffi::GstPad, sinkpad: &mut gst::Pad){
    unsafe{
        if !sinkpad.is_linked(){
            let mut decodebin_pad = gst::Pad::new(pad).unwrap();
            let caps = decodebin_pad.query_caps(None).unwrap();
            let structure = caps.structure(0).unwrap();
            if structure.name().starts_with("video") {
                decodebin_pad.link(sinkpad).unwrap();
            }
        }
    }
}

fn main(){
    gst::init();
    let args: Vec<_> = env::args().collect();
    let uri: &str = if args.len() == 2 {
        args[1].as_ref()
    }else{
        panic!("Usage: pipeline file_path");
    };

    let mut pipeline = gst::Pipeline::new("video_player").expect("Couldn't create playbin");
    let mut filesrc = gst::Element::new("filesrc", "").unwrap();
    filesrc.set("location", uri);
    let mut decodebin = gst::Element::new("decodebin", "").unwrap();
    let mut sink = gst::Element::new("glimagesink", "").unwrap();
    let mut sink_pad = sink.static_pad("sink").unwrap();
    unsafe{
        decodebin.signal_connect("pad-added", mem::transmute(signal_callback as *mut c_void), &mut sink_pad);
    }
    if !pipeline.add_and_link(filesrc, decodebin){
        panic!("couldn't link filesrc and decodebin");
    }
    pipeline.add(sink);
    let mut mainloop = gst::MainLoop::new();
    let mut bus = pipeline.bus().expect("Couldn't get pipeline bus");
    let bus_receiver = bus.receiver();
    mainloop.spawn();
    pipeline.play();
    for message in bus_receiver.iter(){
        match message.parse(){
            gst::Message::StateChangedParsed{ref old, ref new, ..} => {
                println!("element `{}` changed from {:?} to {:?}", message.src_name(), old, new);
            }
            gst::Message::ErrorParsed{ref error, ref debug, ..} => {
				println!("error msg from element `{}`: {}, {}. Quitting", message.src_name(), error.message(), debug);
                break;
            }
            gst::Message::Eos(_) => {
                println!("eos received quiting");
                break;
            }
            _ => {
                println!("msg of type `{}` from element `{}`", message.type_name(), message.src_name());
            }
        }
    }
    mainloop.quit();
}
<|endoftext|>


<commit_before>//! Shapes in the game, like units (triangles) and buildings (squares).
extern crate graphics;
use self::graphics::types::Triangle;
use self::graphics::math;
use super::state;

use common::Vec2;

pub trait Shape {
    fn get_shape(&self, size: f64) -> Triangle;

    fn is_hit(&self, size: f64, position: Vec2) -> bool;
}

impl Shape for state::Unit {
    /// Return the base shape of the unit.
    fn get_shape(&self, size: f64) -> Triangle {
        // Base shape
        let mut triangle: Triangle = [
            [0.0, size / 2.0], // Left
            [size, size],      // Top right
            [size, 0.0],       // Bottom right
        ];

        // Transformations
        for point in triangle.iter_mut() {
            // Translate center to zero point
            *point = math::add(*point, [-size / 2.0, -size / 2.0]);

            // Rotate
            let rotation_matrix = math::rotate_radians(self.angle);
            *point = math::transform_vec(rotation_matrix, *point);

            // Translate to effective position
            *point = math::add(*point, self.position.into());
        }

        triangle
    }

    /// Calculate whether or not this unit is hit by the point at the specified position.
    fn is_hit(&self, size: f64, position: Vec2) -> bool {
        let hitbox = self.get_shape(size);
        math::inside_triangle(hitbox, position.into())
    }
}

#[cfg(test)]
mod test {
    use std::f64::consts::FRAC_PI_2;

    use super::{Shape, Vec2, state};

    #[test]
    fn test_hitbox() {
        // Create a unit at position (100,100) that has been rotated by 90° CW.
        //
        //    /\
        //   /__\
        //
        let mut unit = state::Unit::new(0, Vec2::new(100.0, 100.0));
        unit.angle = FRAC_PI_2;

        // The following points should be outside of the hitbox.
        assert_eq!(unit.is_hit(50.0, Vec2::new(0.0, 0.0)), false);
        assert_eq!(unit.is_hit(50.0, Vec2::new(50.0, 50.0)), false);

        // The following five points should be inside the hitbox.
        //      .
        //     /.\
        //   ./_._\.
        //
        let vertical_distance = 50.0 / 2.0 - 1.0;
        assert_eq!(unit.is_hit(50.0, Vec2::new(100.0, 100.0)), true);
        assert_eq!(unit.is_hit(50.0, Vec2::new(100.0, 100.0 - vertical_distance)), true);
        assert_eq!(unit.is_hit(50.0, Vec2::new(100.0, 100.0 + vertical_distance)), true);
        assert_eq!(unit.is_hit(50.0, Vec2::new(100.0 - vertical_distance, 100.0 + vertical_distance)), true);
        assert_eq!(unit.is_hit(50.0, Vec2::new(100.0 + vertical_distance, 100.0 + vertical_distance)), true);

        // The following two points should be outside the hitbox.
        //
        //  . /\ .
        //   /__\
        //
        assert_eq!(unit.is_hit(50.0, Vec2::new(100.0 - vertical_distance, 100.0)), false);
        assert_eq!(unit.is_hit(50.0, Vec2::new(100.0 + vertical_distance, 100.0)), false);
    }
}
<commit_msg>Negative addition is positive subtraction<commit_after>//! Shapes in the game, like units (triangles) and buildings (squares).
extern crate graphics;
use self::graphics::types::Triangle;
use self::graphics::math;
use super::state;

use common::Vec2;

pub trait Shape {
    fn get_shape(&self, size: f64) -> Triangle;

    fn is_hit(&self, size: f64, position: Vec2) -> bool;
}

impl Shape for state::Unit {
    /// Return the base shape of the unit.
    fn get_shape(&self, size: f64) -> Triangle {
        // Base shape
        let mut triangle: Triangle = [
            [0.0, size / 2.0], // Left
            [size, size],      // Top right
            [size, 0.0],       // Bottom right
        ];

        // Transformations
        for point in triangle.iter_mut() {
            // Translate center to zero point
            *point = math::sub(*point, [size / 2.0, size / 2.0]);

            // Rotate
            let rotation_matrix = math::rotate_radians(self.angle);
            *point = math::transform_vec(rotation_matrix, *point);

            // Translate to effective position
            *point = math::add(*point, self.position.into());
        }

        triangle
    }

    /// Calculate whether or not this unit is hit by the point at the specified position.
    fn is_hit(&self, size: f64, position: Vec2) -> bool {
        let hitbox = self.get_shape(size);
        math::inside_triangle(hitbox, position.into())
    }
}

#[cfg(test)]
mod test {
    use std::f64::consts::FRAC_PI_2;

    use super::{Shape, Vec2, state};

    #[test]
    fn test_hitbox() {
        // Create a unit at position (100,100) that has been rotated by 90° CW.
        //
        //    /\
        //   /__\
        //
        let mut unit = state::Unit::new(0, Vec2::new(100.0, 100.0));
        unit.angle = FRAC_PI_2;

        // The following points should be outside of the hitbox.
        assert_eq!(unit.is_hit(50.0, Vec2::new(0.0, 0.0)), false);
        assert_eq!(unit.is_hit(50.0, Vec2::new(50.0, 50.0)), false);

        // The following five points should be inside the hitbox.
        //      .
        //     /.\
        //   ./_._\.
        //
        let vertical_distance = 50.0 / 2.0 - 1.0;
        assert_eq!(unit.is_hit(50.0, Vec2::new(100.0, 100.0)), true);
        assert_eq!(unit.is_hit(50.0, Vec2::new(100.0, 100.0 - vertical_distance)), true);
        assert_eq!(unit.is_hit(50.0, Vec2::new(100.0, 100.0 + vertical_distance)), true);
        assert_eq!(unit.is_hit(50.0, Vec2::new(100.0 - vertical_distance, 100.0 + vertical_distance)), true);
        assert_eq!(unit.is_hit(50.0, Vec2::new(100.0 + vertical_distance, 100.0 + vertical_distance)), true);

        // The following two points should be outside the hitbox.
        //
        //  . /\ .
        //   /__\
        //
        assert_eq!(unit.is_hit(50.0, Vec2::new(100.0 - vertical_distance, 100.0)), false);
        assert_eq!(unit.is_hit(50.0, Vec2::new(100.0 + vertical_distance, 100.0)), false);
    }
}
<|endoftext|>