<commit_before>//! Tools for composing generative fine art.

mod canvas;
mod gpu;
mod raster;
mod render;

pub mod prelude {
    pub use super::*;

    pub use palette::{
        self,
        Alpha,
        Blend,
        ComponentWise,
        Hue,
        IntoColor,
        LinSrgb,
        LinSrgba,
        Saturate,
    };
    pub use rand::{self, rngs::StdRng, Rng, SeedableRng};
    pub use structopt::StructOpt;
}

pub use self::{
    gpu::{Gpu, Shader, UniformBuffer},
    render::Context,
};
pub use canvas::{Canvas, Paint};

use self::{gpu::*, prelude::*, raster::Method};
use failure::Error;
use lyon_path::math::Point;
use render::*;
use std::{path::PathBuf, time::Duration};

/// A two dimensional point.
pub type P2 = Point;

/// A compiled GLSL program.
pub type Program = glium::program::Program;

/// A value or an error.
pub type Result<T> = std::result::Result<T, Error>;

/// Command line options for a painting run.
///
/// Construct with `Options::from_args()` to run the CLI.
#[derive(StructOpt, Debug, Clone)]
#[structopt(name = "valora")]
pub struct Options {
    #[structopt(flatten)]
    pub world: World,

    /// The number of frames to delay saving to file. For example, if delay=100,
    /// 100 frames will be rendered silently and then the 101st and those after it
    /// will be saved to file.
    #[structopt(short = "d", long = "delay", default_value = "0")]
    pub delay: usize,

    /// Prefix of output path. Output is <prefix>/<seed>/<frame_number>.png
    #[structopt(short = "o", long = "output", parse(from_os_str))]
    pub output: Option<PathBuf>,
}

/// The world in which the painting takes place.
#[derive(StructOpt, Debug, Copy, Clone)]
#[structopt(name = "world")]
pub struct World {
    /// The RNG seed for this painting.
    #[structopt(short = "e", long = "seed", default_value = "0")]
    pub seed: u64,

    /// The width in coordinate space of the painting.
    ///
    /// Coordinate space may differ from output space. If width is 500 but scale is 10, the painting
    /// will have a coordinate space width of 500, but the final output will have a width of 5000 pixels.
    #[structopt(short = "w", long = "width", default_value = "512")]
    pub width: f32,
    /// The height in coordinate space of the painting.
    ///
    /// Coordinate space may differ from output space. If height is 500 but scale is 10, the painting
    /// will have a coordinate space height of 500, but the final output will have a height of 5000 pixels.
    #[structopt(short = "h", long = "height", default_value = "650")]
    pub height: f32,

    /// The scale of the output.
    ///
    /// The final output space is (width*scale)x(height*scale). This value is useful for painting
    /// and doing work at one quickly rendering resolution, and later exporting at a much higher
    /// resolution while preserving the composition exactly.
    ///
    /// This value may be needed when writing shaders or using other raster graphics, to adjust them
    /// for the real output size. Vector painting such as with paths should not need to consider this.
    #[structopt(short = "s", long = "scale", default_value = "1.0")]
    pub scale: f32,

    /// The total number of frames in this painting.
    #[structopt(short = "f", long = "frames")]
    pub frames: Option<usize>,

    /// The number of frames (to try) to render per second.
    #[structopt(short = "r", long = "frames_per_second", default_value = "24")]
    pub framerate: usize,
}

impl World {
    /// Normalizes coordinates into the range [0, 1] by dividing them by the coordinate space dimensions.
    pub fn normalize(&self, p: P2) -> P2 { P2::new(p.x / self.width, p.y / self.height) }

    /// Returns the center of the coordinate space.
    pub fn center(&self) -> P2 { P2::new(self.width / 2.0, self.height / 2.0) }
}

/// Draws a rectangle path covering the entire canvas.
impl Paint for World {
    fn paint(&self, comp: &mut Canvas) {
        comp.line_to(P2::new(0.0, 0.0));
        comp.line_to(P2::new(self.width, 0.0));
        comp.line_to(P2::new(self.width, self.height));
        comp.line_to(P2::new(0.0, self.height));
        comp.line_to(P2::new(0.0, 0.0));
    }
}

/// A trait for types which paint canvases.
pub trait Artist: Sized {
    /// Constructs the artist.
    fn setup(gpu: &Gpu, world: &World, rng: &mut StdRng) -> Result<Self>;

    /// Paints a single frame. Context provides the frame number, and other resources to needed to
    /// generate the painting.
    fn paint(&mut self, ctx: Context, canvas: &mut Canvas);
}

/// Run a painter.
pub fn run<A: Artist>(options: Options) -> Result<()> {
    let (output_width, output_height) = (
        (options.world.width as f32 * options.world.scale) as u32,
        (options.world.height as f32 * options.world.scale) as u32,
    );

    let (gpu, mut strategy) = if let Some(base_path) = options.output.clone() {
        let (gpu, _) = Gpu::new()?;
        let buffer = gpu.build_texture(output_width, output_height)?;

        (
            gpu,
            RenderStrategy::File {
                buffer,
                output_path: move |frame_number: usize, seed: u64| {
                    let mut base_path = base_path.clone();
                    base_path.push(format!("{}", seed));
                    std::fs::create_dir_all(&base_path)
                        .expect(&format!("To create save directory {:?}", base_path));
                    base_path.push(format!("{}.png", frame_number));
                    base_path
                },
            },
        )
    } else {
        let (gpu, events_loop) = Gpu::with_window(output_width, output_height)?;
        let wait = Duration::from_secs_f64(1. / options.world.framerate as f64);
        let gpu_clone = gpu.clone();

        (
            gpu,
            RenderStrategy::Screen {
                events_loop,
                wait,
                get_frame: move || {
                    gpu_clone
                        .get_frame()
                        .expect("To get frame from windowed gpu")
                },
            },
        )
    };

    let mut current_seed = options.world.seed;
    loop {
        let mut rng = StdRng::seed_from_u64(current_seed);
        let mut artist = A::setup(&gpu, &options.world, &mut rng)?;

        let mut renderer = Renderer {
            strategy: &mut strategy,
            gpu: &gpu,
            options: Options {
                world: World {
                    seed: current_seed,
                    ..options.world
                },
                ..options.clone()
            },
            rng: &mut rng,
            output_width: output_width,
            output_height: output_height,
        };

        if let Some(rebuild) = renderer.render_frames(|ctx, canvas| artist.paint(ctx, canvas))? {
            match rebuild {
                Rebuild::NewSeed(new_seed) => {
                    current_seed = new_seed;
                }
            }
        } else {
            break;
        }
    }

    Ok(())
}
<commit_msg>Pretentious*2<commit_after>//! A brush for generative fine art.

mod canvas;
mod gpu;
mod raster;
mod render;

pub mod prelude {
    pub use super::*;

    pub use palette::{
        self,
        Alpha,
        Blend,
        ComponentWise,
        Hue,
        IntoColor,
        LinSrgb,
        LinSrgba,
        Saturate,
    };
    pub use rand::{self, rngs::StdRng, Rng, SeedableRng};
    pub use structopt::StructOpt;
}

pub use self::{
    gpu::{Gpu, Shader, UniformBuffer},
    render::Context,
};
pub use canvas::{Canvas, Paint};

use self::{gpu::*, prelude::*, raster::Method};
use failure::Error;
use lyon_path::math::Point;
use render::*;
use std::{path::PathBuf, time::Duration};

/// A two dimensional point.
pub type P2 = Point;

/// A compiled GLSL program.
pub type Program = glium::program::Program;

/// A value or an error.
pub type Result<T> = std::result::Result<T, Error>;

/// Command line options for a painting run.
///
/// Construct with `Options::from_args()` to run the CLI.
#[derive(StructOpt, Debug, Clone)]
#[structopt(name = "valora")]
pub struct Options {
    #[structopt(flatten)]
    pub world: World,

    /// The number of frames to delay saving to file. For example, if delay=100,
    /// 100 frames will be rendered silently and then the 101st and those after it
    /// will be saved to file.
    #[structopt(short = "d", long = "delay", default_value = "0")]
    pub delay: usize,

    /// Prefix of output path. Output is <prefix>/<seed>/<frame_number>.png
    #[structopt(short = "o", long = "output", parse(from_os_str))]
    pub output: Option<PathBuf>,
}

/// The world in which the painting takes place.
#[derive(StructOpt, Debug, Copy, Clone)]
#[structopt(name = "world")]
pub struct World {
    /// The RNG seed for this painting.
    #[structopt(short = "e", long = "seed", default_value = "0")]
    pub seed: u64,

    /// The width in coordinate space of the painting.
    ///
    /// Coordinate space may differ from output space. If width is 500 but scale is 10, the painting
    /// will have a coordinate space width of 500, but the final output will have a width of 5000 pixels.
    #[structopt(short = "w", long = "width", default_value = "512")]
    pub width: f32,
    /// The height in coordinate space of the painting.
    ///
    /// Coordinate space may differ from output space. If height is 500 but scale is 10, the painting
    /// will have a coordinate space height of 500, but the final output will have a height of 5000 pixels.
    #[structopt(short = "h", long = "height", default_value = "650")]
    pub height: f32,

    /// The scale of the output.
    ///
    /// The final output space is (width*scale)x(height*scale). This value is useful for painting
    /// and doing work at one quickly rendering resolution, and later exporting at a much higher
    /// resolution while preserving the composition exactly.
    ///
    /// This value may be needed when writing shaders or using other raster graphics, to adjust them
    /// for the real output size. Vector painting such as with paths should not need to consider this.
    #[structopt(short = "s", long = "scale", default_value = "1.0")]
    pub scale: f32,

    /// The total number of frames in this painting.
    #[structopt(short = "f", long = "frames")]
    pub frames: Option<usize>,

    /// The number of frames (to try) to render per second.
    #[structopt(short = "r", long = "frames_per_second", default_value = "24")]
    pub framerate: usize,
}

impl World {
    /// Normalizes coordinates into the range [0, 1] by dividing them by the coordinate space dimensions.
    pub fn normalize(&self, p: P2) -> P2 { P2::new(p.x / self.width, p.y / self.height) }

    /// Returns the center of the coordinate space.
    pub fn center(&self) -> P2 { P2::new(self.width / 2.0, self.height / 2.0) }
}

/// Draws a rectangle path covering the entire canvas.
impl Paint for World {
    fn paint(&self, comp: &mut Canvas) {
        comp.line_to(P2::new(0.0, 0.0));
        comp.line_to(P2::new(self.width, 0.0));
        comp.line_to(P2::new(self.width, self.height));
        comp.line_to(P2::new(0.0, self.height));
        comp.line_to(P2::new(0.0, 0.0));
    }
}

/// A trait for types which paint canvases.
pub trait Artist: Sized {
    /// Constructs the artist.
    fn setup(gpu: &Gpu, world: &World, rng: &mut StdRng) -> Result<Self>;

    /// Paints a single frame. Context provides the frame number, and other resources to needed to
    /// generate the painting.
    fn paint(&mut self, ctx: Context, canvas: &mut Canvas);
}

/// Run a painter.
pub fn run<A: Artist>(options: Options) -> Result<()> {
    let (output_width, output_height) = (
        (options.world.width as f32 * options.world.scale) as u32,
        (options.world.height as f32 * options.world.scale) as u32,
    );

    let (gpu, mut strategy) = if let Some(base_path) = options.output.clone() {
        let (gpu, _) = Gpu::new()?;
        let buffer = gpu.build_texture(output_width, output_height)?;

        (
            gpu,
            RenderStrategy::File {
                buffer,
                output_path: move |frame_number: usize, seed: u64| {
                    let mut base_path = base_path.clone();
                    base_path.push(format!("{}", seed));
                    std::fs::create_dir_all(&base_path)
                        .expect(&format!("To create save directory {:?}", base_path));
                    base_path.push(format!("{}.png", frame_number));
                    base_path
                },
            },
        )
    } else {
        let (gpu, events_loop) = Gpu::with_window(output_width, output_height)?;
        let wait = Duration::from_secs_f64(1. / options.world.framerate as f64);
        let gpu_clone = gpu.clone();

        (
            gpu,
            RenderStrategy::Screen {
                events_loop,
                wait,
                get_frame: move || {
                    gpu_clone
                        .get_frame()
                        .expect("To get frame from windowed gpu")
                },
            },
        )
    };

    let mut current_seed = options.world.seed;
    loop {
        let mut rng = StdRng::seed_from_u64(current_seed);
        let mut artist = A::setup(&gpu, &options.world, &mut rng)?;

        let mut renderer = Renderer {
            strategy: &mut strategy,
            gpu: &gpu,
            options: Options {
                world: World {
                    seed: current_seed,
                    ..options.world
                },
                ..options.clone()
            },
            rng: &mut rng,
            output_width: output_width,
            output_height: output_height,
        };

        if let Some(rebuild) = renderer.render_frames(|ctx, canvas| artist.paint(ctx, canvas))? {
            match rebuild {
                Rebuild::NewSeed(new_seed) => {
                    current_seed = new_seed;
                }
            }
        } else {
            break;
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>//! atty is a simple utility that answers one question
//! > is this a tty?
//!
//! usage is just as simple
//!
//! ```
//! if atty::is(atty::Stream::Stdout) {
//!   println!("i'm a tty")
//! }
//! ```
//!
//! ```
//! if atty::isnt(atty::Stream::Stdout) {
//!   println!("i'm not a tty")
//! }
//! ```

#![cfg_attr(unix, no_std)]

#[cfg(unix)]
extern crate libc;
#[cfg(windows)]
extern crate winapi;
#[cfg(target_os = "redox")]
extern crate termion;

#[cfg(windows)]
use winapi::shared::minwindef::DWORD;

/// possible stream sources
#[derive(Clone, Copy, Debug)]
pub enum Stream {
    Stdout,
    Stderr,
    Stdin,
}

/// returns true if this is a tty
#[cfg(unix)]
pub fn is(stream: Stream) -> bool {
    extern crate libc;

    let fd = match stream {
        Stream::Stdout => libc::STDOUT_FILENO,
        Stream::Stderr => libc::STDERR_FILENO,
        Stream::Stdin => libc::STDIN_FILENO,
    };
    unsafe { libc::isatty(fd) != 0 }
}

/// returns true if this is a tty
#[cfg(windows)]
pub fn is(stream: Stream) -> bool {
    use winapi::um::winbase::{STD_ERROR_HANDLE as STD_ERROR, STD_INPUT_HANDLE as STD_INPUT,
                 STD_OUTPUT_HANDLE as STD_OUTPUT};

    let (fd, others) = match stream {
        Stream::Stdin => (STD_INPUT, [STD_ERROR, STD_OUTPUT]),
        Stream::Stderr => (STD_ERROR, [STD_INPUT, STD_OUTPUT]),
        Stream::Stdout => (STD_OUTPUT, [STD_INPUT, STD_ERROR]),
    };
    if unsafe { console_on_any(&[fd]) } {
        // False positives aren't possible. If we got a console then
        // we definitely have a tty on stdin.
        return true;
    }

    // At this point, we *could* have a false negative. We can determine that
    // this is true negative if we can detect the presence of a console on
    // any of the other streams. If another stream has a console, then we know
    // we're in a Windows console and can therefore trust the negative.
    if unsafe { console_on_any(&others) } {
        return false;
    }

    // Otherwise, we fall back to a very strange msys hack to see if we can
    // sneakily detect the presence of a tty.
    unsafe { msys_tty_on(fd) }
}

/// returns true if this is _not_ a tty
pub fn isnt(stream: Stream) -> bool {
    !is(stream)
}

/// Returns true if any of the given fds are on a console.
#[cfg(windows)]
unsafe fn console_on_any(fds: &[DWORD]) -> bool {
    use winapi::um::consoleapi::GetConsoleMode;
    use winapi::um::processenv::GetStdHandle;

    for &fd in fds {
        let mut out = 0;
        let handle = GetStdHandle(fd);
        if GetConsoleMode(handle, &mut out) != 0 {
            return true;
        }
    }
    false
}

/// Returns true if there is an MSYS tty on the given handle.
#[cfg(windows)]
unsafe fn msys_tty_on(fd: DWORD) -> bool {
    use std::ffi::OsString;
    use std::mem;
    use std::os::windows::ffi::OsStringExt;
    use std::slice;

    use winapi::ctypes::c_void;
    use winapi::um::winbase::GetFileInformationByHandleEx;
    use winapi::um::fileapi::FILE_NAME_INFO;
    use winapi::um::minwinbase::FileNameInfo;
    use winapi::um::processenv::GetStdHandle;
    use winapi::shared::minwindef::MAX_PATH;

    let size = mem::size_of::<FILE_NAME_INFO>();
    let mut name_info_bytes = vec![0u8; size + MAX_PATH];
    let res = GetFileInformationByHandleEx(
        GetStdHandle(fd),
        FileNameInfo,
        &mut *name_info_bytes as *mut _ as *mut c_void,
        name_info_bytes.len() as u32,
    );
    if res == 0 {
        return false;
    }
    let name_info: FILE_NAME_INFO = *(name_info_bytes[0..size].as_ptr() as
                                          *const FILE_NAME_INFO);
    let name_bytes =
        &name_info_bytes[size..size + name_info.FileNameLength as usize];
    let name_u16 = slice::from_raw_parts(
        name_bytes.as_ptr() as *const u16,
        name_bytes.len() / 2,
    );
    let name = OsString::from_wide(name_u16)
        .as_os_str()
        .to_string_lossy()
        .into_owned();
    name.contains("msys-") && name.contains("-pty")
}

/// returns true if this is a tty
#[cfg(target_os = "redox")]
pub fn is(stream: Stream) -> bool {
    use std::io;
    use termion::is_tty;

    match stream {
        Stream::Stdin => is_tty(&io::stdin()),
        Stream::Stdout => is_tty(&io::stdout()),
        Stream::Stderr => is_tty(&io::stderr()),
    }
}

/// returns true if this is a tty
#[cfg(target_arch = "wasm32")]
pub fn is(_stream: Stream) -> bool {
    false
}

#[cfg(test)]
mod tests {
    use super::{Stream, is};

    #[test]
    #[cfg(windows)]
    fn is_err() {
        // appveyor pipes its output
        assert!(!is(Stream::Stderr))
    }

    #[test]
    #[cfg(windows)]
    fn is_out() {
        // appveyor pipes its output
        assert!(!is(Stream::Stdout))
    }

    #[test]
    #[cfg(windows)]
    fn is_in() {
        assert!(is(Stream::Stdin))
    }

    #[test]
    #[cfg(unix)]
    fn is_err() {
        assert!(is(Stream::Stderr))
    }

    #[test]
    #[cfg(unix)]
    fn is_out() {
        assert!(is(Stream::Stdout))
    }

    #[test]
    #[cfg(target_os = "macos")]
    fn is_in() {
        // macos on travis seems to pipe its input
        assert!(is(Stream::Stdin))
    }

    #[test]
    #[cfg(all(not(target_os = "macos"), unix))]
    fn is_in() {
        assert!(is(Stream::Stdin))
    }
}
<commit_msg>fix pty detection<commit_after>//! atty is a simple utility that answers one question
//! > is this a tty?
//!
//! usage is just as simple
//!
//! ```
//! if atty::is(atty::Stream::Stdout) {
//!   println!("i'm a tty")
//! }
//! ```
//!
//! ```
//! if atty::isnt(atty::Stream::Stdout) {
//!   println!("i'm not a tty")
//! }
//! ```

#![cfg_attr(unix, no_std)]

#[cfg(unix)]
extern crate libc;
#[cfg(windows)]
extern crate winapi;
#[cfg(target_os = "redox")]
extern crate termion;

#[cfg(windows)]
use winapi::shared::minwindef::DWORD;

/// possible stream sources
#[derive(Clone, Copy, Debug)]
pub enum Stream {
    Stdout,
    Stderr,
    Stdin,
}

/// returns true if this is a tty
#[cfg(unix)]
pub fn is(stream: Stream) -> bool {
    extern crate libc;

    let fd = match stream {
        Stream::Stdout => libc::STDOUT_FILENO,
        Stream::Stderr => libc::STDERR_FILENO,
        Stream::Stdin => libc::STDIN_FILENO,
    };
    unsafe { libc::isatty(fd) != 0 }
}

/// returns true if this is a tty
#[cfg(windows)]
pub fn is(stream: Stream) -> bool {
    use winapi::um::winbase::{STD_ERROR_HANDLE as STD_ERROR, STD_INPUT_HANDLE as STD_INPUT,
                 STD_OUTPUT_HANDLE as STD_OUTPUT};

    let (fd, others) = match stream {
        Stream::Stdin => (STD_INPUT, [STD_ERROR, STD_OUTPUT]),
        Stream::Stderr => (STD_ERROR, [STD_INPUT, STD_OUTPUT]),
        Stream::Stdout => (STD_OUTPUT, [STD_INPUT, STD_ERROR]),
    };
    if unsafe { console_on_any(&[fd]) } {
        // False positives aren't possible. If we got a console then
        // we definitely have a tty on stdin.
        return true;
    }

    // At this point, we *could* have a false negative. We can determine that
    // this is true negative if we can detect the presence of a console on
    // any of the other streams. If another stream has a console, then we know
    // we're in a Windows console and can therefore trust the negative.
    if unsafe { console_on_any(&others) } {
        return false;
    }

    // Otherwise, we fall back to a very strange msys hack to see if we can
    // sneakily detect the presence of a tty.
    unsafe { msys_tty_on(fd) }
}

/// returns true if this is _not_ a tty
pub fn isnt(stream: Stream) -> bool {
    !is(stream)
}

/// Returns true if any of the given fds are on a console.
#[cfg(windows)]
unsafe fn console_on_any(fds: &[DWORD]) -> bool {
    use winapi::um::consoleapi::GetConsoleMode;
    use winapi::um::processenv::GetStdHandle;

    for &fd in fds {
        let mut out = 0;
        let handle = GetStdHandle(fd);
        if GetConsoleMode(handle, &mut out) != 0 {
            return true;
        }
    }
    false
}

/// Returns true if there is an MSYS tty on the given handle.
#[cfg(windows)]
unsafe fn msys_tty_on(fd: DWORD) -> bool {
    use std::ffi::OsString;
    use std::mem;
    use std::os::windows::ffi::OsStringExt;
    use std::slice;

    use winapi::ctypes::c_void;
    use winapi::um::winbase::GetFileInformationByHandleEx;
    use winapi::um::fileapi::FILE_NAME_INFO;
    use winapi::um::minwinbase::FileNameInfo;
    use winapi::um::processenv::GetStdHandle;
    use winapi::shared::minwindef::MAX_PATH;

    let size = mem::size_of::<FILE_NAME_INFO>();
    let mut name_info_bytes = vec![0u8; size + MAX_PATH];
    let res = GetFileInformationByHandleEx(
        GetStdHandle(fd),
        FileNameInfo,
        &mut *name_info_bytes as *mut _ as *mut c_void,
        name_info_bytes.len() as u32,
    );
    if res == 0 {
        return false;
    }
    let name_info: FILE_NAME_INFO = *(name_info_bytes[0..size].as_ptr() as
                                          *const FILE_NAME_INFO);
    let name_bytes =
        &name_info_bytes[size..size + name_info.FileNameLength as usize];
    let name_u16 = slice::from_raw_parts(
        name_bytes.as_ptr() as *const u16,
        name_bytes.len() / 2,
    );
    let name = OsString::from_wide(name_u16)
        .as_os_str()
        .to_string_lossy()
        .into_owned();
    // This checks whether 'pty' exists in the file name, which indicates that
    // a pseudo-terminal is attached. To mitigate against false positives
    // (e.g., an actual file name that contains 'pty'), we also require that
    // either the strings 'msys-' or 'cygwin-' are in the file name as well.)
    let is_msys = name.contains("msys-") || name.contains("cygwin-");
    let is_pty = name.contains("-pty");
    is_msys && is_pty
}

/// returns true if this is a tty
#[cfg(target_os = "redox")]
pub fn is(stream: Stream) -> bool {
    use std::io;
    use termion::is_tty;

    match stream {
        Stream::Stdin => is_tty(&io::stdin()),
        Stream::Stdout => is_tty(&io::stdout()),
        Stream::Stderr => is_tty(&io::stderr()),
    }
}

/// returns true if this is a tty
#[cfg(target_arch = "wasm32")]
pub fn is(_stream: Stream) -> bool {
    false
}

#[cfg(test)]
mod tests {
    use super::{Stream, is};

    #[test]
    #[cfg(windows)]
    fn is_err() {
        // appveyor pipes its output
        assert!(!is(Stream::Stderr))
    }

    #[test]
    #[cfg(windows)]
    fn is_out() {
        // appveyor pipes its output
        assert!(!is(Stream::Stdout))
    }

    #[test]
    #[cfg(windows)]
    fn is_in() {
        assert!(is(Stream::Stdin))
    }

    #[test]
    #[cfg(unix)]
    fn is_err() {
        assert!(is(Stream::Stderr))
    }

    #[test]
    #[cfg(unix)]
    fn is_out() {
        assert!(is(Stream::Stdout))
    }

    #[test]
    #[cfg(target_os = "macos")]
    fn is_in() {
        // macos on travis seems to pipe its input
        assert!(is(Stream::Stdin))
    }

    #[test]
    #[cfg(all(not(target_os = "macos"), unix))]
    fn is_in() {
        assert!(is(Stream::Stdin))
    }
}
<|endoftext|>


<commit_before>/// Re-export slog
///
/// Users of this library can, but don't have to use slog to build their own loggers
#[macro_use]
pub extern crate slog ;
extern crate slog_stdlog;

use slog::DrainExt;

extern crate regex;
use regex::Regex;

extern crate reqwest;
use reqwest::Url;

extern crate select;
use select::document::Document;
use select::predicate::Name;

use std::io::Read;

pub struct Inspirer {
    logger: slog::Logger,
}

impl Inspirer {
    /// Initialize 'Inspirer'
    ///
    /// Either provide a custom slog::Logger or default to the standard `log`
    /// crate.
    ///
    /// # Examples
    /// ```
    /// inspirer::Inspirer::init(None);
    /// ```
    pub fn init(logger: Option<slog::Logger>) -> Self {
        Inspirer {
            logger: logger.unwrap_or_else(|| slog::Logger::root(slog_stdlog::StdLog.fuse(), o!())),
        }
    }

    /// The `aux2key` function extracts TeX keys from LaTeX .aux files. These can be for either BibTeX
    /// or BibLaTeX.
    ///
    /// # Examples
    /// ```
    /// let inspirer = inspirer::Inspirer::init(None);
    ///
    /// let input =
    /// r"\relax
    /// \citation{Abramovici:1992ah}".to_string();
    ///
    /// assert_eq!(inspirer.aux2key(input), vec!("Abramovici:1992ah"));
    /// ```
    pub fn aux2key(&self, input_data: String) -> Vec<String> {

        let regex = Regex::new(r"\\citation\{([a-zA-Z]+:\d{4}[a-z]{2,3})\}").unwrap();
        // Below regex is for Biber. Check correctness and write tests.
        // r"\\abx@aux@cite\{([a-zA-Z]+:\d{4}[a-z]{2,3})\}"

        regex.captures_iter(&input_data)
            .map(|c| c.get(1).unwrap().as_str().to_string())
            .collect()
    }

    /// Fetches BibTeX entries from inspire.net.
    ///
    /// # Examples
    ///
    /// ```
    /// let inspirer = inspirer::Inspirer::init(None);
    ///
    /// println!("{}", inspirer.fetch_bibtex_with_key("Abramovici:1992ah".to_string()).expect("Error"));
    /// ```
    pub fn fetch_bibtex_with_key(&self, key: String) -> Option<String> {

        let api_url = Url::parse(&format!(r"https://inspirehep.net/search?of=hx&p={}/", key))
            .unwrap();

        let mut response = reqwest::get(api_url).expect("Failed to send get request");

        let mut html = String::new();
        response.read_to_string(&mut html).expect("Failed to read response.");

        let document = Document::from(html.as_str());

        Some(document.find(Name("pre")).first().expect("No text found.").text())
    }
}

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

    #[test]
    fn test_aux_bibtex_0_citations() {
        let input = r"\relax ".to_string();

        let output: Vec<String> = Vec::new();
        assert_eq!(Inspirer::init(None).aux2key(input), output);
    }

    #[test]
    fn test_aux_bibtex_1_citation() {
        let input = r"\relax
            \citation{Abramovici:1992ah}"
            .to_string();

        assert_eq!(Inspirer::init(None).aux2key(input),
                   vec!["Abramovici:1992ah"]);
    }

    #[test]
    fn test_aux_bibtex_2_citation() {
        let input = r"\relax
            \citation{Abramovici:1992ah}
            \citation{Thorne:1992sdb}"
            .to_string();

        assert_eq!(Inspirer::init(None).aux2key(input),
                   vec!["Abramovici:1992ah", "Thorne:1992sdb"]);
    }
}
<commit_msg>lib: Query inspire API more carefully<commit_after>/// Re-export slog
///
/// Users of this library can, but don't have to use slog to build their own loggers
#[macro_use]
pub extern crate slog ;
extern crate slog_stdlog;

use slog::DrainExt;

extern crate regex;
use regex::Regex;

extern crate reqwest;
use reqwest::Url;

extern crate select;
use select::document::Document;
use select::predicate::Name;

use std::io::Read;

pub struct Inspirer {
    logger: slog::Logger,
}

impl Inspirer {
    /// Initialize 'Inspirer'
    ///
    /// Either provide a custom slog::Logger or default to the standard `log`
    /// crate.
    ///
    /// # Examples
    /// ```
    /// inspirer::Inspirer::init(None);
    /// ```
    pub fn init(logger: Option<slog::Logger>) -> Self {
        Inspirer {
            logger: logger.unwrap_or_else(|| slog::Logger::root(slog_stdlog::StdLog.fuse(), o!())),
        }
    }

    /// The `aux2key` function extracts TeX keys from LaTeX .aux files. These can be for either BibTeX
    /// or BibLaTeX.
    ///
    /// # Examples
    /// ```
    /// let inspirer = inspirer::Inspirer::init(None);
    ///
    /// let input =
    /// r"\relax
    /// \citation{Abramovici:1992ah}".to_string();
    ///
    /// assert_eq!(inspirer.aux2key(input), vec!("Abramovici:1992ah"));
    /// ```
    pub fn aux2key(&self, input_data: String) -> Vec<String> {

        let regex = Regex::new(r"\\citation\{([a-zA-Z]+:\d{4}[a-z]{2,3})\}").unwrap();
        // Below regex is for Biber. Check correctness and write tests.
        // r"\\abx@aux@cite\{([a-zA-Z]+:\d{4}[a-z]{2,3})\}"

        regex.captures_iter(&input_data)
            .map(|c| c.get(1).unwrap().as_str().to_string())
            .collect()
    }

    /// Fetches BibTeX entries from inspire.net.
    ///
    /// # Examples
    ///
    /// ```
    /// let inspirer = inspirer::Inspirer::init(None);
    ///
    /// println!("{}", inspirer.fetch_bibtex_with_key("Abramovici:1992ah".to_string()).expect("Error"));
    /// ```
    pub fn fetch_bibtex_with_key(&self, key: String) -> Option<String> {

        let mut api_url: Url = Url::parse("https://inspirehep.net")
            .expect("Unable to parse API URL")
            .join("search")
            .unwrap();
        api_url.query_pairs_mut()
            .append_pair("of", "hx")
            .append_pair("p", &key);

        debug!(self.logger, "Querying inspire API";
               "URL" => api_url.to_string());
        let mut response = reqwest::get(api_url).expect("Failed to send get request");
        debug!(self.logger, "GET request completed";
               "HTTP response status" => response.status().to_string());

        let mut html = String::new();
        response.read_to_string(&mut html).expect("Failed to read response.");

        let document = Document::from(html.as_str());

        Some(document.find(Name("pre")).first().expect("No text found.").text())
    }
}

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

    #[test]
    fn test_aux_bibtex_0_citations() {
        let input = r"\relax ".to_string();

        let output: Vec<String> = Vec::new();
        assert_eq!(Inspirer::init(None).aux2key(input), output);
    }

    #[test]
    fn test_aux_bibtex_1_citation() {
        let input = r"\relax
            \citation{Abramovici:1992ah}"
            .to_string();

        assert_eq!(Inspirer::init(None).aux2key(input),
                   vec!["Abramovici:1992ah"]);
    }

    #[test]
    fn test_aux_bibtex_2_citation() {
        let input = r"\relax
            \citation{Abramovici:1992ah}
            \citation{Thorne:1992sdb}"
            .to_string();

        assert_eq!(Inspirer::init(None).aux2key(input),
                   vec!["Abramovici:1992ah", "Thorne:1992sdb"]);
    }
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;
use tokenizer::{Token, Tokenizer};

mod tokenizer;

pub struct Point {
    x: f64,
    y: f64,
    z: Option<f64>,
    m: Option<f64>,
}

impl Point {
    fn from_tokens(tokens: &mut Tokenizer) -> Self {
        match tokens.next() {
            Some(Token::ParenOpen) => (),
            _ => panic!("FIXME"),
        };
        let x = match tokens.next() {
            Some(Token::Number(n)) => n,
            _ => panic!("FIXME"),
        };
        let y = match tokens.next() {
            Some(Token::Number(n)) => n,
            _ => panic!("FIXME"),
        };
        match tokens.next() {
            Some(Token::ParenClose) => (),
            _ => panic!("FIXME"),
        };
        Point {x: x, y: y, z: None, m: None}
    }
}

pub struct Wkt {
    items: Vec<Point>
}

impl Wkt {
    fn new() -> Self {
        Wkt {items: vec![]}
    }

    fn add_point(&mut self, point: Point) {
        self.items.push(point);
    }

    fn from_reader(reader: &mut Reader) -> Self {
        match reader.read_to_string() {
            Ok(string) => Wkt::from_str(string.as_slice()),
            Err(err) => panic!(err),
        }
    }

    fn from_str(wkt_str: &str) -> Self {
        let ref mut tokens = tokenizer::tokenize(wkt_str);
        Wkt::from_tokens(tokens)
    }

    fn from_tokens(tokens: &mut Tokenizer) -> Self {
        let mut wkt = Wkt::new();
        match tokens.next() {
            Some(Token::Word(word)) => {
                if !word.is_ascii() {
                    panic!("Encountered non-ascii word");
                }
                let uppercased = word.to_ascii_uppercase();
                match uppercased.as_slice() {
                    "POINT" => {
                        wkt.add_point(Point::from_tokens(tokens));
                        wkt
                    },
                    _ => wkt,
                }
            },
            // None
            _ => panic!("Invalid WKT format"),
        }
    }
}

#[test]
fn basic_point() {
    let mut wkt = Wkt::from_str("POINT (10 -20)");
    assert_eq!(1, wkt.items.len());
    let point = wkt.items.pop().unwrap();
    assert_eq!(10.0, point.x);
    assert_eq!(-20.0, point.y);
    assert_eq!(None, point.z);
    assert_eq!(None, point.m);
}
<commit_msg>Constructors should return Result<commit_after>use std::ascii::AsciiExt;
use tokenizer::{Token, Tokenizer};

mod tokenizer;

pub struct Point {
    x: f64,
    y: f64,
    z: Option<f64>,
    m: Option<f64>,
}

impl Point {
    fn from_tokens(tokens: &mut Tokenizer) ->  Result<Self, &'static str> {
        match tokens.next() {
            Some(Token::ParenOpen) => (),
            _ => return Err("FIXME"),
        };
        let x = match tokens.next() {
            Some(Token::Number(n)) => n,
            _ => return Err("FIXME"),
        };
        let y = match tokens.next() {
            Some(Token::Number(n)) => n,
            _ => return Err("FIXME"),
        };
        match tokens.next() {
            Some(Token::ParenClose) => (),
            _ => return Err("FIXME"),
        };
        Ok(Point {x: x, y: y, z: None, m: None})
    }
}

pub struct Wkt {
    items: Vec<Point>
}

impl Wkt {
    fn new() -> Self {
        Wkt {items: vec![]}
    }

    fn add_point(&mut self, point: Point) {
        self.items.push(point);
    }

    fn from_reader(reader: &mut Reader) -> Result<Self, &'static str> {
        match reader.read_to_string() {
            Ok(string) => Wkt::from_str(string.as_slice()),
            Err(err) => Err(err.desc),
        }
    }

    fn from_str(wkt_str: &str) -> Result<Self, &'static str> {
        let tokens = tokenizer::tokenize(wkt_str);
        Wkt::from_tokens(tokens)
    }

    fn from_tokens(mut tokens: Tokenizer) -> Result<Self, &'static str> {
        let mut wkt = Wkt::new();
        match tokens.next() {
            Some(Token::Word(word)) => {
                if !word.is_ascii() {
                    return Err("Encountered non-ascii word");
                }
                let uppercased = word.to_ascii_uppercase();
                match uppercased.as_slice() {
                    "POINT" => {
                        match Point::from_tokens(&mut tokens) {
                            Ok(point) => {
                                wkt.add_point(point);
                                Ok(wkt)
                            }
                            Err(s) => Err(s),
                        }
                    },
                    _ => Ok(wkt),
                }
            },
            // None
            _ => Err("Invalid WKT format"),
        }
    }
}

#[test]
fn basic_point() {
    let mut wkt = Wkt::from_str("POINT (10 -20)").ok().unwrap();
    assert_eq!(1, wkt.items.len());
    let point = wkt.items.pop().unwrap();
    assert_eq!(10.0, point.x);
    assert_eq!(-20.0, point.y);
    assert_eq!(None, point.z);
    assert_eq!(None, point.m);
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::fmt;
use std::iter::FromIterator;

#[derive(Clone, PartialEq, Eq)]
pub enum Token {
    Output,
    Input,
    Loop(Vec<Token>),
    Move(i32),
    Add(i32, i32),
    Set(i32, i32),
    MulCopy(i32, i32, i32),
    Scan(i32),
    LoadOut(i32, i32),
    LoadOutSet(i32),
    If(i32, Vec<Token>),
}

impl fmt::Debug for Token {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Output => write!(f, "Output"),
            Input => write!(f, "Input"),
            Move(offset) => write!(f, "Move(offset={})", offset),
            Add(offset, value) => write!(f, "Add(offset={}, value={})", offset, value),
            Set(offset, value) => write!(f, "Set(offset={}, value={})", offset, value),
            MulCopy(src, dest, mul) => {
                write!(f, "MulCopy(src={}, dest={}, mul={})", src, dest, mul)
            }
            Scan(offset) => write!(f, "Scan(offset={})", offset),
            LoadOut(offset, add) => write!(f, "LoadOut(offset={}, add={})", offset, add),
            LoadOutSet(value) => write!(f, "LoadOutSet(value={})", value),
            Loop(ref content) => {
                if f.alternate() {
                    write!(f, "Loop(content={:#?})", content)
                } else {
                    write!(f, "Loop(content={:?})", content)
                }
            }
            If(offset, ref content) => {
                if f.alternate() {
                    write!(f, "If(offset={}, content={:#?})", offset, content)
                } else {
                    write!(f, "If(offset={}, content={:?})", offset, content)
                }
            }
        }
    }
}

use Token::*;

#[derive(Default)]
struct OptimizeState {
    tokens: Vec<Token>,
    // With HashMap, the order sometimes switches
    // in recursion, and the optimizer never exits.
    adds: BTreeMap<i32, i32>,
    sets: BTreeMap<i32, i32>,
    shift: i32,
}

impl OptimizeState {
    fn apply_shift(&mut self) {
        if self.shift != 0 {
            self.tokens.push(Move(self.shift));
            self.shift = 0;
        }
    }

    fn apply_adds_sets(&mut self) {
        for (offset, value) in self.sets.iter() {
            self.tokens.push(Set(*offset, *value));
        }
        for (offset, value) in self.adds.iter() {
            self.tokens.push(Add(*offset, *value));
        }
        self.sets.clear();
        self.adds.clear();
    }
}

pub fn parse(code: &str) -> Vec<Token> {
    _parse(&mut code.chars())
}

fn _parse(chars: &mut std::str::Chars) -> Vec<Token> {
    let mut tokens = Vec::new();
    while let Some(i) = chars.next() {
        match i {
            '+' => tokens.push(Add(0, 1)),
            '-' => tokens.push(Add(0, -1)),
            '>' => tokens.push(Move(1)),
            '<' => tokens.push(Move(-1)),
            '[' => tokens.push(Loop(_parse(chars))),
            ']' => {
                break;
            }
            ',' => tokens.push(Input),
            '.' => {
                tokens.push(LoadOut(0, 0));
                tokens.push(Output);
            }
            _ => (),
        };
    }

    tokens
}

fn _optimize(tokens: &Vec<Token>) -> OptimizeState {
    let mut do_output = false;
    let mut state = OptimizeState::default();

    for token in tokens.iter() {
        match *token {
            Set(..) | Add(..) | Move(_) | LoadOut(..) | LoadOutSet(_) | Output => {}
            _ => {
                if do_output {
                    state.tokens.push(Output);
                    do_output = false;
                }

                state.apply_adds_sets();
            }
        }

        match *token {
            Loop(_) | Input | Scan(_) => {
                state.apply_shift();
            }
            _ => {}
        }

        match *token {
            Set(mut offset, val) => {
                offset += state.shift;
                // Add before Set does nothing; remove it
                state.adds.remove(&offset);
                state.sets.insert(offset, val);
            }
            Add(mut offset, mut val) => {
                offset += state.shift;
                if state.sets.contains_key(&offset) {
                    val = state.sets.get(&offset).unwrap() + val;
                    state.sets.insert(offset, val);
                } else {
                    val = state.adds.get(&offset).unwrap_or(&0) + val;
                    state.adds.insert(offset, val);
                }
            }
            MulCopy(src, dest, mul) => {
                state.tokens.push(MulCopy(src + state.shift, dest + state.shift, mul))
            }
            If(offset, ref contents) => {
                let mut newcontents = Vec::new();
                for i in contents.iter() {
                    newcontents.push(match *i {
                        Set(offset, value) => Set(offset + state.shift, value),
                        MulCopy(src, dest, mul) => {
                            MulCopy(src + state.shift, dest + state.shift, mul)
                        }
                        _ => unreachable!(),
                    });
                }
                state.tokens.push(If(offset + state.shift, newcontents));
            }
            Move(offset) => state.shift += offset,
            Output => do_output = true,
            LoadOut(mut offset, add) => {
                offset += state.shift;
                if state.sets.contains_key(&offset) {
                    state.tokens.push(LoadOutSet(state.sets.get(&offset).unwrap() + add));
                } else {
                    state.tokens.push(LoadOut(offset, state.adds.get(&offset).unwrap_or(&0) + add));
                }
            }
            Loop(ref contents) => _optimize_loop(contents, &mut state),
            LoadOutSet(value) => state.tokens.push(LoadOutSet(value)),
            Input => state.tokens.push(Input),
            Scan(offset) => state.tokens.push(Scan(offset + state.shift)),
        }
    }

    if do_output {
        state.tokens.push(Output);
    }

    state
}

fn _optimize_loop(tokens: &Vec<Token>, outer: &mut OptimizeState) {
    let mut inner = _optimize(tokens);

    if inner.shift != 0 && inner.sets.is_empty() && inner.adds.is_empty() &&
       inner.tokens.is_empty() {
        outer.tokens.push(Scan(inner.shift));
    } else if inner.shift == 0 && inner.tokens.is_empty() && inner.adds.contains_key(&0) &&
              inner.adds.len() == 1 {
        if !inner.sets.is_empty() {
            let mut iftokens = Vec::new();
            for (offset, value) in inner.sets.iter() {
                iftokens.push(Set(*offset, *value));
            }
            iftokens.push(Set(0, 0));
            outer.tokens.push(If(0, iftokens));
        } else {
            outer.sets.insert(0, 0);
        }
    } else if inner.shift == 0 && inner.tokens.is_empty() && inner.adds.get(&0) == Some(&-1) {
        let contents = inner.adds.iter().filter_map(|(offset, value)| {
            if *offset != 0 {
                let src = 0;
                let dest = *offset;
                let mul = *value;
                Some(MulCopy(src, dest, mul))
            } else {
                None
            }
        });

        if !inner.sets.is_empty() {
            let iftokens = Vec::from_iter(inner.sets
                .iter()
                .map(|(offset, value)| Set(*offset, *value))
                .chain(contents));
            outer.tokens.push(If(0, iftokens));
        } else {
            outer.tokens.extend(contents);
        }

        outer.sets.insert(0, 0);
    } else {
        inner.apply_adds_sets();
        inner.apply_shift();

        outer.tokens.push(Loop(inner.tokens));
    }
}

pub fn optimize(tokens: Vec<Token>) -> Vec<Token> {
    let mut oldtokens = tokens;
    // Ignore sets/adds/shifts at end of file
    let mut newtokens = _optimize(&oldtokens).tokens;
    while newtokens != oldtokens {
        oldtokens = newtokens;
        newtokens = _optimize(&oldtokens).tokens;
    }
    newtokens
}
<commit_msg>Remove unneeded .iter() calls in for loops<commit_after>use std::collections::BTreeMap;
use std::fmt;
use std::iter::FromIterator;

#[derive(Clone, PartialEq, Eq)]
pub enum Token {
    Output,
    Input,
    Loop(Vec<Token>),
    Move(i32),
    Add(i32, i32),
    Set(i32, i32),
    MulCopy(i32, i32, i32),
    Scan(i32),
    LoadOut(i32, i32),
    LoadOutSet(i32),
    If(i32, Vec<Token>),
}

impl fmt::Debug for Token {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Output => write!(f, "Output"),
            Input => write!(f, "Input"),
            Move(offset) => write!(f, "Move(offset={})", offset),
            Add(offset, value) => write!(f, "Add(offset={}, value={})", offset, value),
            Set(offset, value) => write!(f, "Set(offset={}, value={})", offset, value),
            MulCopy(src, dest, mul) => {
                write!(f, "MulCopy(src={}, dest={}, mul={})", src, dest, mul)
            }
            Scan(offset) => write!(f, "Scan(offset={})", offset),
            LoadOut(offset, add) => write!(f, "LoadOut(offset={}, add={})", offset, add),
            LoadOutSet(value) => write!(f, "LoadOutSet(value={})", value),
            Loop(ref content) => {
                if f.alternate() {
                    write!(f, "Loop(content={:#?})", content)
                } else {
                    write!(f, "Loop(content={:?})", content)
                }
            }
            If(offset, ref content) => {
                if f.alternate() {
                    write!(f, "If(offset={}, content={:#?})", offset, content)
                } else {
                    write!(f, "If(offset={}, content={:?})", offset, content)
                }
            }
        }
    }
}

use Token::*;

#[derive(Default)]
struct OptimizeState {
    tokens: Vec<Token>,
    // With HashMap, the order sometimes switches
    // in recursion, and the optimizer never exits.
    adds: BTreeMap<i32, i32>,
    sets: BTreeMap<i32, i32>,
    shift: i32,
}

impl OptimizeState {
    fn apply_shift(&mut self) {
        if self.shift != 0 {
            self.tokens.push(Move(self.shift));
            self.shift = 0;
        }
    }

    fn apply_adds_sets(&mut self) {
        for (offset, value) in &self.sets {
            self.tokens.push(Set(*offset, *value));
        }
        for (offset, value) in &self.adds {
            self.tokens.push(Add(*offset, *value));
        }
        self.sets.clear();
        self.adds.clear();
    }
}

pub fn parse(code: &str) -> Vec<Token> {
    _parse(&mut code.chars())
}

fn _parse(chars: &mut std::str::Chars) -> Vec<Token> {
    let mut tokens = Vec::new();
    while let Some(i) = chars.next() {
        match i {
            '+' => tokens.push(Add(0, 1)),
            '-' => tokens.push(Add(0, -1)),
            '>' => tokens.push(Move(1)),
            '<' => tokens.push(Move(-1)),
            '[' => tokens.push(Loop(_parse(chars))),
            ']' => {
                break;
            }
            ',' => tokens.push(Input),
            '.' => {
                tokens.push(LoadOut(0, 0));
                tokens.push(Output);
            }
            _ => (),
        };
    }

    tokens
}

fn _optimize(tokens: &Vec<Token>) -> OptimizeState {
    let mut do_output = false;
    let mut state = OptimizeState::default();

    for token in tokens {
        match *token {
            Set(..) | Add(..) | Move(_) | LoadOut(..) | LoadOutSet(_) | Output => {}
            _ => {
                if do_output {
                    state.tokens.push(Output);
                    do_output = false;
                }

                state.apply_adds_sets();
            }
        }

        match *token {
            Loop(_) | Input | Scan(_) => {
                state.apply_shift();
            }
            _ => {}
        }

        match *token {
            Set(mut offset, val) => {
                offset += state.shift;
                // Add before Set does nothing; remove it
                state.adds.remove(&offset);
                state.sets.insert(offset, val);
            }
            Add(mut offset, mut val) => {
                offset += state.shift;
                if state.sets.contains_key(&offset) {
                    val = state.sets.get(&offset).unwrap() + val;
                    state.sets.insert(offset, val);
                } else {
                    val = state.adds.get(&offset).unwrap_or(&0) + val;
                    state.adds.insert(offset, val);
                }
            }
            MulCopy(src, dest, mul) => {
                state.tokens.push(MulCopy(src + state.shift, dest + state.shift, mul))
            }
            If(offset, ref contents) => {
                let mut newcontents = Vec::new();
                for i in contents {
                    newcontents.push(match *i {
                        Set(offset, value) => Set(offset + state.shift, value),
                        MulCopy(src, dest, mul) => {
                            MulCopy(src + state.shift, dest + state.shift, mul)
                        }
                        _ => unreachable!(),
                    });
                }
                state.tokens.push(If(offset + state.shift, newcontents));
            }
            Move(offset) => state.shift += offset,
            Output => do_output = true,
            LoadOut(mut offset, add) => {
                offset += state.shift;
                if state.sets.contains_key(&offset) {
                    state.tokens.push(LoadOutSet(state.sets.get(&offset).unwrap() + add));
                } else {
                    state.tokens.push(LoadOut(offset, state.adds.get(&offset).unwrap_or(&0) + add));
                }
            }
            Loop(ref contents) => _optimize_loop(contents, &mut state),
            LoadOutSet(value) => state.tokens.push(LoadOutSet(value)),
            Input => state.tokens.push(Input),
            Scan(offset) => state.tokens.push(Scan(offset + state.shift)),
        }
    }

    if do_output {
        state.tokens.push(Output);
    }

    state
}

fn _optimize_loop(tokens: &Vec<Token>, outer: &mut OptimizeState) {
    let mut inner = _optimize(tokens);

    if inner.shift != 0 && inner.sets.is_empty() && inner.adds.is_empty() &&
       inner.tokens.is_empty() {
        outer.tokens.push(Scan(inner.shift));
    } else if inner.shift == 0 && inner.tokens.is_empty() && inner.adds.contains_key(&0) &&
              inner.adds.len() == 1 {
        if !inner.sets.is_empty() {
            let mut iftokens = Vec::new();
            for (offset, value) in &inner.sets {
                iftokens.push(Set(*offset, *value));
            }
            iftokens.push(Set(0, 0));
            outer.tokens.push(If(0, iftokens));
        } else {
            outer.sets.insert(0, 0);
        }
    } else if inner.shift == 0 && inner.tokens.is_empty() && inner.adds.get(&0) == Some(&-1) {
        let contents = inner.adds.iter().filter_map(|(offset, value)| {
            if *offset != 0 {
                let src = 0;
                let dest = *offset;
                let mul = *value;
                Some(MulCopy(src, dest, mul))
            } else {
                None
            }
        });

        if !inner.sets.is_empty() {
            let iftokens = Vec::from_iter(inner.sets
                .iter()
                .map(|(offset, value)| Set(*offset, *value))
                .chain(contents));
            outer.tokens.push(If(0, iftokens));
        } else {
            outer.tokens.extend(contents);
        }

        outer.sets.insert(0, 0);
    } else {
        inner.apply_adds_sets();
        inner.apply_shift();

        outer.tokens.push(Loop(inner.tokens));
    }
}

pub fn optimize(tokens: Vec<Token>) -> Vec<Token> {
    let mut oldtokens = tokens;
    // Ignore sets/adds/shifts at end of file
    let mut newtokens = _optimize(&oldtokens).tokens;
    while newtokens != oldtokens {
        oldtokens = newtokens;
        newtokens = _optimize(&oldtokens).tokens;
    }
    newtokens
}
<|endoftext|>


<commit_before>// rouler - A container-based system for generating die rolls
// Copyright (C) 2016 by John Berry
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#![warn(missing_docs)]
//! # rouler - A container-like system for generating dice rolls
//!
//! [![Crates.io](https://img.shields.io/crates/v/rouler.svg)](https://crates.io/crates/rouler)
//!
//! rouler is a library for handling repeatable dice rolls in a conveniently storable way.
//! At the heart of rouler is the `Roller`, a simple struct that contains both the syntax for a specific
//! dice roll, and the result of the most recent roll. This allows you to store a particular roll
//! type in a variable, that can then be passed around (within the limits of mutable values), and
//! repeated via method calls as needed. It is meant to be useful for CRPGs and tabletop game aids.
//!
//! ## Example usage
//!
//! ```
//! use rouler::Roller;
//!
//! let mut stat = Roller::new("3d6");
//!
//! println!("STR: {}", stat.total());
//! println!("DEX: {}", stat.reroll());
//! ```
//!
//! ## The Die Roll Syntax
//!
//! rouler uses parsed strings to define die rolls, according to the following [pest](https://github.com/dragostis/pest/)
//! grammar found in `parse.rs`, with some additional rules checking:
//!
//! ```rust,ignore
//! expression = _{
//!     { ["("] ~ expression ~ [")"] | number }
//!     addition       = { plus  | minus }
//!     multiplication = { times | slash }
//!     die_roll       = { roll }
//! }
//! number = @{ ["-"]? ~ (["0"] | ['1'..'9'] ~ ['0'..'9']*) }
//! plus   =  { ["+"] }
//! minus  =  { ["-"] }
//! times  =  { ["*"] }
//! slash  =  { ["/"] }
//! roll   =  { ["d"] | ["D"] }
//!
//! whitespace = _{ [" "] }
//! ```
//!
//! Largely this should all be familiar basic mathematical notation, the key addition being the `d` operator,
//! which operates according to the standard notation familiar from tabletop RPGs, ie.:
//!
//! `n[d|D]s`, where `n` = the number of dice to roll, and `s` = the number of sides on each die.
//!
//! There are additional constraints checked for in this operator alone as well: neither `n` or `s` can be zero,
//! and `s` cannot be a negative number. `n` is allowed to be negative, but rather than rolling "negative dice",
//! this merely negates the value of the entire roll, such that `-3d6` would generate a value between -3 and -18.

#[macro_use]
extern crate pest;
extern crate rand;

mod parse;
mod random;
mod roll;

pub use roll::{Roller, roll_dice};<commit_msg>Add changelog to main doc page<commit_after>// rouler - A container-based system for generating die rolls
// Copyright (C) 2016 by John Berry
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#![warn(missing_docs)]
//! # rouler - A container-like system for generating dice rolls
//!
//! [![Crates.io](https://img.shields.io/crates/v/rouler.svg)](https://crates.io/crates/rouler)
//!
//! rouler is a library for handling repeatable dice rolls in a conveniently storable way.
//! At the heart of rouler is the `Roller`, a simple struct that contains both the syntax for a specific
//! dice roll, and the result of the most recent roll. This allows you to store a particular roll
//! type in a variable, that can then be passed around (within the limits of mutable values), and
//! repeated via method calls as needed. It is meant to be useful for CRPGs and tabletop game aids.
//!
//! ## Example usage
//!
//! ```
//! use rouler::Roller;
//!
//! let mut stat = Roller::new("3d6");
//!
//! println!("STR: {}", stat.total());
//! println!("DEX: {}", stat.reroll());
//! ```
//!
//! ## The Die Roll Syntax
//!
//! rouler uses parsed strings to define die rolls, according to the following [pest](https://github.com/dragostis/pest/)
//! grammar found in `parse.rs`, with some additional rules checking:
//!
//! ```rust,ignore
//! expression = _{
//!     { ["("] ~ expression ~ [")"] | number }
//!     addition       = { plus  | minus }
//!     multiplication = { times | slash }
//!     die_roll       = { roll }
//! }
//! number = @{ ["-"]? ~ (["0"] | ['1'..'9'] ~ ['0'..'9']*) }
//! plus   =  { ["+"] }
//! minus  =  { ["-"] }
//! times  =  { ["*"] }
//! slash  =  { ["/"] }
//! roll   =  { ["d"] | ["D"] }
//!
//! whitespace = _{ [" "] }
//! ```
//!
//! Largely this should all be familiar basic mathematical notation, the key addition being the `d` operator,
//! which operates according to the standard notation familiar from tabletop RPGs, ie.:
//!
//! `n[d|D]s`, where `n` = the number of dice to roll, and `s` = the number of sides on each die.
//!
//! There are additional constraints checked for in this operator alone as well: neither `n` or `s` can be zero,
//! and `s` cannot be a negative number. `n` is allowed to be negative, but rather than rolling "negative dice",
//! this merely negates the value of the entire roll, such that `-3d6` would generate a value between -3 and -18.
//!
//! ## Changelog
//!
//! ### 0.1.3
//! * Added Iterator support to Rollers
//! * Better type inference for Roller::new()
//!
//! ### 0.1.2
//! * Documentation fixes
//!
//! ### 0.1.1
//! * Documentation fixes
//!
//! ### 0.1.0
//! * Initial release
#[macro_use]
extern crate pest;
extern crate rand;

mod parse;
mod random;
mod roll;

pub use roll::{Roller, roll_dice};<|endoftext|>


<commit_before>// Copyright 2017-2018 int08h LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//!
//! An implementation of the [Roughtime](https://roughtime.googlesource.com/roughtime)
//! secure time synchronization protocol.
//!
//! Roughtime aims to achieve rough time synchronisation in a secure way that doesn't
//! depend on any particular time server, and in such a way that, if a time server does
//! misbehave, clients end up with cryptographic proof of it.
//!
//! # Protocol
//!
//! Roughtime messages are represented by [`RtMessage`](struct.RtMessage.html) which
//! implements the mapping of Roughtime `u32` [`tags`](enum.Tag.html) to byte-strings.
//!
//! # Client
//!
//! A Roughtime client can be found in `src/bin/client.rs`. To run the client:
//!
//! ```bash
//! $ cargo run --release --bin client roughtime.int08h.com 2002
//! ```
//!
//! Consult the client's `--help` output for all runtime options.
//!
//! # Server
//!
//! The Roughtime server implementation is in `src/bin/server.rs`. The server is
//! configured via a YAML config file. See [FileConfig](config/struct.FileConfig.html)
//! for details of the configuration parameters.
//!
//! To run the server:
//!
//! ```bash
//! $ cargo run --release --bin server /path/to/config.file
//! ```
//!

extern crate byteorder;
extern crate core;
extern crate time;
extern crate yaml_rust;

mod error;
mod message;
mod tag;

pub mod config;
pub mod keys;
pub mod merkle;
pub mod sign;

pub use error::Error;
pub use message::RtMessage;
pub use tag::Tag;

/// Version of Roughenough
pub const VERSION: &str = "1.0.5";

//  Constants and magic numbers of the Roughtime protocol

/// Minimum size (in bytes) of a client request
pub const MIN_REQUEST_LENGTH: u32 = 1024;

/// Minimum size (in bytes) of seeds used to derive private keys
pub const MIN_SEED_LENGTH: u32 = 32;

/// Size (in bytes) of an Ed25519 public key
pub const PUBKEY_LENGTH: u32 = 32;

/// Size (in bytes) of the client's nonce
pub const NONCE_LENGTH: u32 = 64;

/// Size (in bytes) of an Ed25519 signature
pub const SIGNATURE_LENGTH: u32 = 64;

/// Size (in bytes) of a SHA-512 hash
pub const HASH_LENGTH: u32 = 64;

/// Size (in bytes) of server's timestamp value
pub const TIMESTAMP_LENGTH: u32 = 8;

/// Size (in bytes) of server's time uncertainty value
pub const RADIUS_LENGTH: u32 = 4;

/// Prefixed to the server's certificate before generating or verifying certificate's signature
pub const CERTIFICATE_CONTEXT: &str = "RoughTime v1 delegation signature--\x00";

/// Prefixed to the server's response before generating or verifying the server's signature
pub const SIGNED_RESPONSE_CONTEXT: &str = "RoughTime v1 response signature\x00";

/// Value prepended to leaves prior to hashing
pub const TREE_LEAF_TWEAK: &[u8] = &[0x00];

/// Value prepended to nodes prior to hashing
pub const TREE_NODE_TWEAK: &[u8] = &[0x01];
<commit_msg>Bump version in lib.rs<commit_after>// Copyright 2017-2018 int08h LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//!
//! An implementation of the [Roughtime](https://roughtime.googlesource.com/roughtime)
//! secure time synchronization protocol.
//!
//! Roughtime aims to achieve rough time synchronisation in a secure way that doesn't
//! depend on any particular time server, and in such a way that, if a time server does
//! misbehave, clients end up with cryptographic proof of it.
//!
//! # Protocol
//!
//! Roughtime messages are represented by [`RtMessage`](struct.RtMessage.html) which
//! implements the mapping of Roughtime `u32` [`tags`](enum.Tag.html) to byte-strings.
//!
//! # Client
//!
//! A Roughtime client can be found in `src/bin/client.rs`. To run the client:
//!
//! ```bash
//! $ cargo run --release --bin client roughtime.int08h.com 2002
//! ```
//!
//! Consult the client's `--help` output for all runtime options.
//!
//! # Server
//!
//! The Roughtime server implementation is in `src/bin/server.rs`. The server is
//! configured via a YAML config file. See [FileConfig](config/struct.FileConfig.html)
//! for details of the configuration parameters.
//!
//! To run the server:
//!
//! ```bash
//! $ cargo run --release --bin server /path/to/config.file
//! ```
//!

extern crate byteorder;
extern crate core;
extern crate time;
extern crate yaml_rust;

mod error;
mod message;
mod tag;

pub mod config;
pub mod keys;
pub mod merkle;
pub mod sign;

pub use error::Error;
pub use message::RtMessage;
pub use tag::Tag;

/// Version of Roughenough
pub const VERSION: &str = "1.1.0";

//  Constants and magic numbers of the Roughtime protocol

/// Minimum size (in bytes) of a client request
pub const MIN_REQUEST_LENGTH: u32 = 1024;

/// Minimum size (in bytes) of seeds used to derive private keys
pub const MIN_SEED_LENGTH: u32 = 32;

/// Size (in bytes) of an Ed25519 public key
pub const PUBKEY_LENGTH: u32 = 32;

/// Size (in bytes) of the client's nonce
pub const NONCE_LENGTH: u32 = 64;

/// Size (in bytes) of an Ed25519 signature
pub const SIGNATURE_LENGTH: u32 = 64;

/// Size (in bytes) of a SHA-512 hash
pub const HASH_LENGTH: u32 = 64;

/// Size (in bytes) of server's timestamp value
pub const TIMESTAMP_LENGTH: u32 = 8;

/// Size (in bytes) of server's time uncertainty value
pub const RADIUS_LENGTH: u32 = 4;

/// Prefixed to the server's certificate before generating or verifying certificate's signature
pub const CERTIFICATE_CONTEXT: &str = "RoughTime v1 delegation signature--\x00";

/// Prefixed to the server's response before generating or verifying the server's signature
pub const SIGNED_RESPONSE_CONTEXT: &str = "RoughTime v1 response signature\x00";

/// Value prepended to leaves prior to hashing
pub const TREE_LEAF_TWEAK: &[u8] = &[0x00];

/// Value prepended to nodes prior to hashing
pub const TREE_NODE_TWEAK: &[u8] = &[0x01];
<|endoftext|>


<commit_before>#![crate_type = "lib"]
#![crate_name = "gst"]

pub use self::appsink::AppSink;
pub use self::appsrc::AppSrc;
pub use self::sample::Sample;
pub use self::caps::Caps;
pub use self::buffer::Buffer;
pub use self::mapinfo::MapInfo;
pub use self::mapinfo::Map;
pub use self::element::Element;
pub use self::bus::Bus;
pub use self::bin::Bin;
pub use self::pipeline::Pipeline;
pub use self::playbin::PlayBin;
pub use self::message::Message;
pub use self::mainloop::MainLoop;
pub use self::error::Error;
pub use self::error::Result;
pub use self::videoframe::VideoFrame;
pub use self::videoframe::VideoPlane;
pub use self::videoframe::VideoComponent;
pub use self::videoinfo::VideoInfo;
pub use self::buffer_pool::BufferPool;
pub use self::pad::Pad;
pub use self::structure::Structure;
pub use self::iterator::Iter;

use self::reference::Reference;

pub use ffi::*;
use std::ptr;
use std::mem;
use std::ffi::CString;
use std::str;
use std::ffi::CStr;
use std::ops::{Deref, DerefMut};
use std::convert::{From, AsRef, AsMut};

#[macro_use] mod util;
pub mod ffi;

/// Easy way for applications to extract samples from a pipeline.
pub mod appsink;

/// Easy way for applications to inject buffers into a pipeline.
pub mod appsrc;
mod sample;
mod caps;
mod buffer;
mod element;
pub mod bus;
mod bin;
mod pipeline;
mod playbin;
mod message;
pub mod mainloop;
mod error;
mod videoframe;
mod videoinfo;
mod mapinfo;
mod buffer_pool;
mod pad;
mod structure;
mod iterator;
mod reference;
#[cfg(target_os="linux")]
mod link_linux;
#[cfg(target_os="macos")]
mod link_osx;
#[cfg(target_os="windows")]
mod link_windows;

pub fn init(){
    unsafe{
        gst_init(ptr::null::<i32>() as *mut i32, ptr::null_mut::<i8>() as *mut *mut *mut i8);
    }
}

pub fn filename_to_uri(filename: &str) -> Result<String>{
    let cfilename = CString::new(filename).unwrap();
    unsafe{
        if gst_uri_is_valid(cfilename.as_ptr())==1{
            return Ok(filename.to_string())
        }
        let err: *mut GError = ptr::null_mut();
        let c_uri = gst_filename_to_uri(cfilename.as_ptr(), mem::transmute(&err));
        if err != ptr::null_mut(){
            Err(Error::new(0, 0, from_c_str!(mem::transmute((*err).message))))
        }else{
            let uri = from_c_str!(mem::transmute(c_uri)).to_string();
            g_free(mem::transmute(c_uri));
            Ok(uri)
        }
    }
}

pub fn uri_get_protocol(uri: &str) -> Result<String>{
    let curi = CString::new(uri).unwrap();
    unsafe{
        if gst_uri_is_valid(curi.as_ptr())==1{
            Ok(from_c_str!(mem::transmute(gst_uri_get_protocol(curi.as_ptr()))).to_string())
        }else{
            Err(Error::new(0,0,"not a valid URI"))
        }
    }
}

pub trait Transfer<PtrType=GstElement>{
    /// Consumes the current object and transfers ownership of the raw pointer
    /// Used to transfer ownership to ffi functions, should be used when an ffi
    /// function expects full transfer of an object to avoid the original object
    /// to be unreferenced in the process
    unsafe fn transfer(self) -> *mut PtrType;
}

pub trait FromGValue{
    fn from_gvalue(value: &GValue) -> Option<Self> where Self:Sized;
}

pub struct Ref<T>{
    value: T
}

impl<T:Reference> Ref<T>{
    pub fn new(t: &T) -> Ref<T>{
        Ref{ value: t.reference() }
    }
}

impl<T> Deref for Ref<T>{
    type Target = T;
    fn deref(&self) -> &T{
        &self.value
    }
}

impl<T> DerefMut for Ref<T>{
    fn deref_mut(&mut self) -> &mut T{
        &mut self.value
    }
}

impl<T:Reference> From<T> for Ref<T>{
    fn from(t: T) -> Ref<T>{
        Ref{ value: t }
    }
}

impl<T> AsRef<T> for Ref<T>{
    fn as_ref(&self) -> &T{
        &self.value
    }
}

impl<T> AsMut<T> for Ref<T>{
    fn as_mut(&mut self) -> &mut T{
        &mut self.value
    }
}
<commit_msg>impl Clone for Ref<commit_after>#![crate_type = "lib"]
#![crate_name = "gst"]

pub use self::appsink::AppSink;
pub use self::appsrc::AppSrc;
pub use self::sample::Sample;
pub use self::caps::Caps;
pub use self::buffer::Buffer;
pub use self::mapinfo::MapInfo;
pub use self::mapinfo::Map;
pub use self::element::Element;
pub use self::bus::Bus;
pub use self::bin::Bin;
pub use self::pipeline::Pipeline;
pub use self::playbin::PlayBin;
pub use self::message::Message;
pub use self::mainloop::MainLoop;
pub use self::error::Error;
pub use self::error::Result;
pub use self::videoframe::VideoFrame;
pub use self::videoframe::VideoPlane;
pub use self::videoframe::VideoComponent;
pub use self::videoinfo::VideoInfo;
pub use self::buffer_pool::BufferPool;
pub use self::pad::Pad;
pub use self::structure::Structure;
pub use self::iterator::Iter;

use self::reference::Reference;

pub use ffi::*;
use std::ptr;
use std::mem;
use std::ffi::CString;
use std::str;
use std::ffi::CStr;
use std::ops::{Deref, DerefMut};
use std::convert::{From, AsRef, AsMut};

#[macro_use] mod util;
pub mod ffi;

/// Easy way for applications to extract samples from a pipeline.
pub mod appsink;

/// Easy way for applications to inject buffers into a pipeline.
pub mod appsrc;
mod sample;
mod caps;
mod buffer;
mod element;
pub mod bus;
mod bin;
mod pipeline;
mod playbin;
mod message;
pub mod mainloop;
mod error;
mod videoframe;
mod videoinfo;
mod mapinfo;
mod buffer_pool;
mod pad;
mod structure;
mod iterator;
mod reference;
#[cfg(target_os="linux")]
mod link_linux;
#[cfg(target_os="macos")]
mod link_osx;
#[cfg(target_os="windows")]
mod link_windows;

pub fn init(){
    unsafe{
        gst_init(ptr::null::<i32>() as *mut i32, ptr::null_mut::<i8>() as *mut *mut *mut i8);
    }
}

pub fn filename_to_uri(filename: &str) -> Result<String>{
    let cfilename = CString::new(filename).unwrap();
    unsafe{
        if gst_uri_is_valid(cfilename.as_ptr())==1{
            return Ok(filename.to_string())
        }
        let err: *mut GError = ptr::null_mut();
        let c_uri = gst_filename_to_uri(cfilename.as_ptr(), mem::transmute(&err));
        if err != ptr::null_mut(){
            Err(Error::new(0, 0, from_c_str!(mem::transmute((*err).message))))
        }else{
            let uri = from_c_str!(mem::transmute(c_uri)).to_string();
            g_free(mem::transmute(c_uri));
            Ok(uri)
        }
    }
}

pub fn uri_get_protocol(uri: &str) -> Result<String>{
    let curi = CString::new(uri).unwrap();
    unsafe{
        if gst_uri_is_valid(curi.as_ptr())==1{
            Ok(from_c_str!(mem::transmute(gst_uri_get_protocol(curi.as_ptr()))).to_string())
        }else{
            Err(Error::new(0,0,"not a valid URI"))
        }
    }
}

pub trait Transfer<PtrType=GstElement>{
    /// Consumes the current object and transfers ownership of the raw pointer
    /// Used to transfer ownership to ffi functions, should be used when an ffi
    /// function expects full transfer of an object to avoid the original object
    /// to be unreferenced in the process
    unsafe fn transfer(self) -> *mut PtrType;
}

pub trait FromGValue{
    fn from_gvalue(value: &GValue) -> Option<Self> where Self:Sized;
}

pub struct Ref<T>{
    value: T
}

impl<T:Reference> Clone for Ref<T>{
    fn clone(&self) -> Ref<T>{
        Ref{ value: self.value.reference() }
    }
}

impl<T:Reference> Ref<T>{
    pub fn new(t: &T) -> Ref<T>{
        Ref{ value: t.reference() }
    }
}

impl<T> Deref for Ref<T>{
    type Target = T;
    fn deref(&self) -> &T{
        &self.value
    }
}

impl<T> DerefMut for Ref<T>{
    fn deref_mut(&mut self) -> &mut T{
        &mut self.value
    }
}

impl<T:Reference> From<T> for Ref<T>{
    fn from(t: T) -> Ref<T>{
        Ref{ value: t }
    }
}

impl<T> AsRef<T> for Ref<T>{
    fn as_ref(&self) -> &T{
        &self.value
    }
}

impl<T> AsMut<T> for Ref<T>{
    fn as_mut(&mut self) -> &mut T{
        &mut self.value
    }
}
<|endoftext|>


<commit_before>use std::str::FromStr;
use std::error::Error;

pub fn puzzle(input: &str) -> Result<usize, Box<Error>> {
    let mut row: Row = input.trim().parse()?;
    let mut result = 0;

    for _ in 0..40 {
        result += row.num_safe_tiles();
        row = row.next();
    }

    Ok(result)
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Tile {
    Safe,
    Trap,
}

pub fn next_tile(left: Tile, center: Tile, right: Tile) -> Tile {
    use Tile::*;
    match (left, center, right) {
        (Trap, Trap, Safe) => Trap,
        (Safe, Trap, Trap) => Trap,
        (Trap, Safe, Safe) => Trap,
        (Safe, Safe, Trap) => Trap,
        _ => Safe,
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Row(Vec<Tile>);

impl Row {
    fn next(&self) -> Row {
        let mut x = vec![Tile::Safe];
        x.extend_from_slice(&self.0);
        x.push(Tile::Safe);

        Row(x.windows(3).map(|tiles| {
            next_tile(tiles[0], tiles[1], tiles[2])
        }).collect())
    }

    fn num_safe_tiles(&self) -> usize {
        self.0.iter().filter(|&&t| t == Tile::Safe).count()
    }
}

impl Tile {
    fn from_char(c: char) -> Result<Tile, Box<Error>> {
        Ok(match c {
            '.' => Tile::Safe,
            '^' => Tile::Trap,
            _ => return Err(format!("unknown tile character {}", c).into()),
        })
    }
}

impl FromStr for Row {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Row, Self::Err> {
        s.chars().map(Tile::from_char).collect::<Result<_, _>>().map(Row)
    }
}

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

    #[test]
    fn safe() {
        assert_eq!(next_tile(Tile::Safe, Tile::Safe, Tile::Safe), Tile::Safe);
        assert_eq!(next_tile(Tile::Safe, Tile::Trap, Tile::Safe), Tile::Safe);
        assert_eq!(next_tile(Tile::Trap, Tile::Safe, Tile::Trap), Tile::Safe);
        assert_eq!(next_tile(Tile::Trap, Tile::Trap, Tile::Trap), Tile::Safe);
    }

    #[test]
    fn first_rule() {
        assert_eq!(next_tile(Tile::Trap, Tile::Trap, Tile::Safe), Tile::Trap);
    }

    #[test]
    fn second_rule() {
        assert_eq!(next_tile(Tile::Safe, Tile::Trap, Tile::Trap), Tile::Trap);
    }

    #[test]
    fn third_rule() {
        assert_eq!(next_tile(Tile::Trap, Tile::Safe, Tile::Safe), Tile::Trap);
    }

    #[test]
    fn fourth_rule() {
        assert_eq!(next_tile(Tile::Safe, Tile::Safe, Tile::Trap), Tile::Trap);
    }

    fn string_to_row(s: &str) -> Row {
        s.parse().expect("Couldn't create Row")
    }

    #[test]
    fn row_at_a_time() {
        assert_eq!(string_to_row("..^^.").next(), string_to_row(".^^^^"));
    }

}
<commit_msg>Part 2 - more rows<commit_after>use std::str::FromStr;
use std::error::Error;

pub fn puzzle(input: &str) -> Result<usize, Box<Error>> {
    let mut row: Row = input.trim().parse()?;
    let mut result = 0;

    for _ in 0..400_000 {
        result += row.num_safe_tiles();
        row = row.next();
    }

    Ok(result)
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Tile {
    Safe,
    Trap,
}

pub fn next_tile(left: Tile, center: Tile, right: Tile) -> Tile {
    use Tile::*;
    match (left, center, right) {
        (Trap, Trap, Safe) => Trap,
        (Safe, Trap, Trap) => Trap,
        (Trap, Safe, Safe) => Trap,
        (Safe, Safe, Trap) => Trap,
        _ => Safe,
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Row(Vec<Tile>);

impl Row {
    fn next(&self) -> Row {
        let mut x = vec![Tile::Safe];
        x.extend_from_slice(&self.0);
        x.push(Tile::Safe);

        Row(x.windows(3).map(|tiles| {
            next_tile(tiles[0], tiles[1], tiles[2])
        }).collect())
    }

    fn num_safe_tiles(&self) -> usize {
        self.0.iter().filter(|&&t| t == Tile::Safe).count()
    }
}

impl Tile {
    fn from_char(c: char) -> Result<Tile, Box<Error>> {
        Ok(match c {
            '.' => Tile::Safe,
            '^' => Tile::Trap,
            _ => return Err(format!("unknown tile character {}", c).into()),
        })
    }
}

impl FromStr for Row {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Row, Self::Err> {
        s.chars().map(Tile::from_char).collect::<Result<_, _>>().map(Row)
    }
}

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

    #[test]
    fn safe() {
        assert_eq!(next_tile(Tile::Safe, Tile::Safe, Tile::Safe), Tile::Safe);
        assert_eq!(next_tile(Tile::Safe, Tile::Trap, Tile::Safe), Tile::Safe);
        assert_eq!(next_tile(Tile::Trap, Tile::Safe, Tile::Trap), Tile::Safe);
        assert_eq!(next_tile(Tile::Trap, Tile::Trap, Tile::Trap), Tile::Safe);
    }

    #[test]
    fn first_rule() {
        assert_eq!(next_tile(Tile::Trap, Tile::Trap, Tile::Safe), Tile::Trap);
    }

    #[test]
    fn second_rule() {
        assert_eq!(next_tile(Tile::Safe, Tile::Trap, Tile::Trap), Tile::Trap);
    }

    #[test]
    fn third_rule() {
        assert_eq!(next_tile(Tile::Trap, Tile::Safe, Tile::Safe), Tile::Trap);
    }

    #[test]
    fn fourth_rule() {
        assert_eq!(next_tile(Tile::Safe, Tile::Safe, Tile::Trap), Tile::Trap);
    }

    fn string_to_row(s: &str) -> Row {
        s.parse().expect("Couldn't create Row")
    }

    #[test]
    fn row_at_a_time() {
        assert_eq!(string_to_row("..^^.").next(), string_to_row(".^^^^"));
    }

}
<|endoftext|>


<commit_before>#![feature(llvm_asm, const_fn, lang_items)]
#![feature(allocator_api)]
#![feature(global_asm)]
#![feature(panic_info_message)]
#![feature(naked_functions)]
#![feature(abi_x86_interrupt)]
#![feature(specialization)]
#![feature(linked_list_cursors)]
#![no_std]

extern crate alloc;
extern crate spin;
#[cfg(target_arch = "x86_64")]
extern crate x86;
#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate num_traits;

// These need to be visible to the linker, so we need to export them.
#[cfg(target_arch = "x86_64")]
pub use arch::processor::*;
use core::panic::PanicInfo;
pub use logging::*;

#[macro_use]
pub mod macros;
#[macro_use]
pub mod logging;
pub mod arch;
pub mod console;
pub mod consts;
pub mod errno;
pub mod fs;
pub mod mm;
pub mod rlib;
pub mod scheduler;
pub mod synch;
pub mod syscall;

#[global_allocator]
static ALLOCATOR: &'static mm::allocator::Allocator = &mm::allocator::Allocator;

/// This function is called on panic.
#[cfg(not(test))]
#[panic_handler]
pub fn panic(info: &PanicInfo) -> ! {
	let tid = scheduler::get_current_taskid();

	print!("[!!!PANIC from task {}!!!] ", tid);

	if let Some(location) = info.location() {
		print!("{}:{}: ", location.file(), location.line());
	}

	if let Some(message) = info.message() {
		print!("{}", message);
	}

	print!("\n");

	loop {
		halt();
	}
}
<commit_msg>enable rust feature "const_fn_fn_ptr_basics"<commit_after>#![feature(llvm_asm, const_fn, lang_items)]
#![feature(allocator_api)]
#![feature(global_asm)]
#![feature(panic_info_message)]
#![feature(naked_functions)]
#![feature(abi_x86_interrupt)]
#![feature(specialization)]
#![feature(linked_list_cursors)]
#![feature(const_fn_fn_ptr_basics)]
#![no_std]

extern crate alloc;
extern crate spin;
#[cfg(target_arch = "x86_64")]
extern crate x86;
#[macro_use]
extern crate bitflags;
extern crate goblin;
extern crate num_traits;

// These need to be visible to the linker, so we need to export them.
#[cfg(target_arch = "x86_64")]
pub use arch::processor::*;
use core::panic::PanicInfo;
pub use logging::*;

#[macro_use]
pub mod macros;
#[macro_use]
pub mod logging;
pub mod arch;
pub mod console;
pub mod consts;
pub mod errno;
pub mod fs;
pub mod mm;
pub mod rlib;
pub mod scheduler;
pub mod synch;
pub mod syscall;

#[global_allocator]
static ALLOCATOR: &'static mm::allocator::Allocator = &mm::allocator::Allocator;

/// This function is called on panic.
#[cfg(not(test))]
#[panic_handler]
pub fn panic(info: &PanicInfo) -> ! {
	let tid = scheduler::get_current_taskid();

	print!("[!!!PANIC from task {}!!!] ", tid);

	if let Some(location) = info.location() {
		print!("{}:{}: ", location.file(), location.line());
	}

	if let Some(message) = info.message() {
		print!("{}", message);
	}

	print!("\n");

	loop {
		halt();
	}
}
<|endoftext|>


<commit_before>struct Triangle {
    normal: [f32, ..3],
    v1: [f32, ..3],
    v2: [f32, ..3],
    v3: [f32, ..3],
    attr_byte_count: u16
}

struct BinaryStlHeader {
    header: [u8, ..80],
    num_triangles: u32
}

struct BinaryStlFile {
    header: BinaryStlHeader,
    triangles: [Triangle]
}

#[test]
fn it_works() {
}
<commit_msg>This should read basic binary STL files.<commit_after>use std::io::{IoResult};

struct Triangle {
    normal: [f32, ..3],
    v1: [f32, ..3],
    v2: [f32, ..3],
    v3: [f32, ..3],
    attr_byte_count: u16
}

static EMPTY_TRIANGLE : Triangle = Triangle {
    normal: [0f32, 0f32, 0f32],
    v1: [0f32, 0f32, 0f32],
    v2: [0f32, 0f32, 0f32],
    v3: [0f32, 0f32, 0f32],
    attr_byte_count: 0
};

struct BinaryStlHeader {
    header: [u8, ..80],
    num_triangles: u32
}

pub struct BinaryStlFile {
    header: BinaryStlHeader,
    triangles: Vec<Triangle>
}

fn read_point<T: Reader>(input: &mut T) -> IoResult<[f32, ..3]> {
    let x1 = try!(input.read_le_f32());
    let x2 = try!(input.read_le_f32());
    let x3 = try!(input.read_le_f32());

    Ok([x1, x2, x3])
}

fn read_triangle<T: Reader>(input: &mut T) -> IoResult<Triangle> {
    let normal = try!(read_point(input));
    let v1 = try!(read_point(input));
    let v2 = try!(read_point(input));
    let v3 = try!(read_point(input));
    let attr_count = try!(input.read_le_u16());

    Ok(Triangle { normal: normal,
                  v1: v1, v2: v2, v3: v3,
                  attr_byte_count: attr_count })
}

pub fn read_stl<T: Reader>(input: &mut T) -> IoResult<BinaryStlFile> {
    let mut header = BinaryStlHeader { header: [0u8, ..80],
                                       num_triangles: 0 };

    // read the header
    try!(input.read_at_least(header.header.len(), &mut header.header));

    // TODO: check the header to make sure whether this is a binary
    // STL file.

    header.num_triangles = try!(input.read_le_u32());

    let mut triangles = Vec::new();
    for _ in range(0, header.num_triangles) {
        triangles.push(try!(read_triangle(input)));
    }

    Ok(BinaryStlFile {
        header: header,
        triangles: triangles
    })
}

#[test]
fn it_works() {
}
<|endoftext|>


<commit_before>use std::sync::mpsc::{Sender, channel, Receiver};
use std::thread::{JoinHandle, spawn};

pub trait Source <TOUT: Send> : 'static + Send {
    fn fanin(&mut self, sink: Sender<TOUT>);
}

pub fn start_multiplex<TOUT: 'static + Send> (sources: Vec<Box<Source<TOUT>>>) -> Receiver<TOUT>
    where Source<TOUT>: Send {
    let (sink, fanout) = channel();
    let _ = sources.into_iter().map(|mut src| {
        let sink = sink.clone();
        spawn(move || {
            src.fanin(sink)
        })
    }).collect::<Vec<_>>();
    return fanout;
}

#[test]
fn it_works() {
    use std::sync::mpsc::{channel, Receiver, Sender};
    use std::thread;
    use std::intrinsics::{type_name};
    use std::error;
    use std::net::{TcpStream, TcpListener};
    use std::io::{Read, Write};

    #[derive(PartialEq,Eq,Debug)]
    struct A;
    #[derive(PartialEq,Eq,Debug)]
    struct B;
    #[derive(PartialEq,Eq,Debug)]
    struct C(String);
    #[derive(PartialEq,Eq,Debug)]
    enum ABC {
        A(A),
        B(B),
        C(C),
    }

    impl Source<ABC> for Receiver<A> {
        fn fanin(&mut self, sink: Sender<ABC>) {
            loop {
                if let Ok(x) = self.recv() {
                    sink.send(ABC::A(x));
                } else {
                    return;
                }
            }
        }
    }

    impl Source<ABC> for Receiver<B> {
        fn fanin(&mut self, sink: Sender<ABC>) {
            loop {
                if let Ok(x) = self.recv() {
                    sink.send(ABC::B(x));
                } else {
                    return;
                }
            }
        }
    }

    impl Source<ABC> for TcpStream {
        fn fanin(&mut self, sink: Sender<ABC>) {
            loop {
                let mut b = [0; 128];
                match self.read(&mut b) {
                    Ok(n) => {
                        sink.send(ABC::C(C(String::from_utf8_lossy(&b[0..n]).into_owned())));
                    }
                    Err(e) => {
                        println!("{:?}", e);
                    }
                }
            }
        }
    }

    let (input_a, _src_a) = channel::<A>();
    let (input_b, _src_b) = channel::<B>();

    // start echo server
    thread::spawn(|| {
        let lis = TcpListener::bind("0.0.0.0:54321").unwrap();
        for x in lis.incoming() {
            if let Ok(mut stream) = x {
                let mut buf = [0; 128];
                if let Ok(n) = stream.read(&mut buf) {
                    stream.write(&buf[0..n]);
                }
            }
        }
    });

    // start echo client
    let mut tcp_client = TcpStream::connect("127.0.0.1:54321").unwrap();

    let mut src_a: Box<Source<ABC>> = Box::new(_src_a);
    let mut src_b: Box<Source<ABC>> = Box::new(_src_b);
    let mut src_c: Box<Source<ABC>> = Box::new(tcp_client.try_clone().unwrap());

    let fanout = start_multiplex(vec![src_a, src_b, src_c]);

    input_a.send(A);
    thread::sleep_ms(100);
    input_b.send(B);
    thread::sleep_ms(100);
    tcp_client.write("1234".as_bytes());
    thread::sleep_ms(100);

    let a = fanout.recv().unwrap();
    let b = fanout.recv().unwrap();
    let c = fanout.recv().unwrap();

    assert_eq!(a, ABC::A(A));
    assert_eq!(b, ABC::B(B));
    assert_eq!(c, ABC::C(C("1234".to_string())));

}
<commit_msg>removed no need mut<commit_after>use std::sync::mpsc::{Sender, channel, Receiver};
use std::thread::{JoinHandle, spawn};

pub trait Source <TOUT: Send> : 'static + Send {
    fn fanin(&mut self, sink: Sender<TOUT>);
}

pub fn start_multiplex<TOUT: 'static + Send> (sources: Vec<Box<Source<TOUT>>>) -> Receiver<TOUT>
    where Source<TOUT>: Send {
    let (sink, fanout) = channel();
    let _ = sources.into_iter().map(|mut src| {
        let sink = sink.clone();
        spawn(move || {
            src.fanin(sink)
        })
    }).collect::<Vec<_>>();
    return fanout;
}

#[test]
fn it_works() {
    use std::sync::mpsc::{channel, Receiver, Sender};
    use std::thread;
    use std::intrinsics::{type_name};
    use std::error;
    use std::net::{TcpStream, TcpListener};
    use std::io::{Read, Write};

    #[derive(PartialEq,Eq,Debug)]
    struct A;
    #[derive(PartialEq,Eq,Debug)]
    struct B;
    #[derive(PartialEq,Eq,Debug)]
    struct C(String);
    #[derive(PartialEq,Eq,Debug)]
    enum ABC {
        A(A),
        B(B),
        C(C),
    }

    impl Source<ABC> for Receiver<A> {
        fn fanin(&mut self, sink: Sender<ABC>) {
            loop {
                if let Ok(x) = self.recv() {
                    sink.send(ABC::A(x));
                } else {
                    return;
                }
            }
        }
    }

    impl Source<ABC> for Receiver<B> {
        fn fanin(&mut self, sink: Sender<ABC>) {
            loop {
                if let Ok(x) = self.recv() {
                    sink.send(ABC::B(x));
                } else {
                    return;
                }
            }
        }
    }

    impl Source<ABC> for TcpStream {
        fn fanin(&mut self, sink: Sender<ABC>) {
            loop {
                let mut b = [0; 128];
                match self.read(&mut b) {
                    Ok(n) => {
                        sink.send(ABC::C(C(String::from_utf8_lossy(&b[0..n]).into_owned())));
                    }
                    Err(e) => {
                        println!("{:?}", e);
                    }
                }
            }
        }
    }

    let (input_a, _src_a) = channel::<A>();
    let (input_b, _src_b) = channel::<B>();

    // start echo server
    thread::spawn(|| {
        let lis = TcpListener::bind("0.0.0.0:54321").unwrap();
        for x in lis.incoming() {
            if let Ok(mut stream) = x {
                let mut buf = [0; 128];
                if let Ok(n) = stream.read(&mut buf) {
                    stream.write(&buf[0..n]);
                }
            }
        }
    });

    // start echo client
    let mut tcp_client = TcpStream::connect("127.0.0.1:54321").unwrap();

    let src_a: Box<Source<ABC>> = Box::new(_src_a);
    let src_b: Box<Source<ABC>> = Box::new(_src_b);
    let src_c: Box<Source<ABC>> = Box::new(tcp_client.try_clone().unwrap());

    let fanout = start_multiplex(vec![src_a, src_b, src_c]);

    input_a.send(A);
    thread::sleep_ms(100);
    input_b.send(B);
    thread::sleep_ms(100);
    tcp_client.write("1234".as_bytes());
    thread::sleep_ms(100);

    let a = fanout.recv().unwrap();
    let b = fanout.recv().unwrap();
    let c = fanout.recv().unwrap();

    assert_eq!(a, ABC::A(A));
    assert_eq!(b, ABC::B(B));
    assert_eq!(c, ABC::C(C("1234".to_string())));

}
<|endoftext|>


<commit_before>#![feature(macro_rules)]
#![allow(unused_imports)]
extern crate serialize;
extern crate rest_client;

/// Reexported types
pub use self::ferrite::{
    JsonError,
    RestClient,
    RestError,
    decode,
    APIError,
    RestErr,
    StatusErr,
    JsonErr
};

mod ferrite {
    pub use serialize::json::DecoderError as JsonError;
    pub use rest_client::{RestClient, RestError};
    pub use serialize::json::decode;

    #[deriving(Show)]
    pub enum APIError {
        RestErr(RestError),
        StatusErr(String),
        JsonErr(JsonError),
    }
}

macro_rules! rest(
    ($method:ident $url:expr: fn $fn_name:ident {$($param:ident: $p_ty: ty),*}($($arg:ident: $a_ty:ty),*) -> $ret:ty) => (
        fn $fn_name($($param: $p_ty),* $($arg: $a_ty),*) -> Result<$ret, APIError> {
            use ferrite::{
                JsonError,
                RestClient,
                RestError,
                decode,
                APIError,
                RestErr,
                StatusErr,
                JsonErr
            };

            pair!()

            let url = format!($url, $($param),*);

            let owned: Vec<(&str, String)> = vec![$((stringify!($arg), $arg.to_string())),*];
            let params: Vec<(&str, &str)> = owned.iter().map(pair).collect();

            let response = try!(RestClient::$method(url.as_slice(), params.as_slice()).map_err(|e| RestErr(e)));

            if response.body.is_empty() {
                Err(StatusErr(response.status.to_string()))
            } else {
                decode::<$ret>(response.body.as_slice()).map_err(|e| JsonErr(e))
            }
        }
    );
    ($method:ident $url:expr: fn $fn_name:ident ($($arg:ident: $a_ty:ty),*) -> $ret:ty) => (
        rest!($method $url fn $fn_name{}($($arg: $a_ty),*) -> $ret)
    )
)

macro_rules! pair(
    () => (
        fn pair<'a>(tup: &'a (&'a str, String)) -> (&'a str, &'a str) {
            let (ref a, ref b) = *tup;
            (*a, b.as_slice())
        }
    )
)

#[macro_export]
macro_rules! get(
    ($url:expr: fn $fn_name:ident {$($param:ident: $p_ty: ty),*}($($arg:ident: $a_ty:ty),*) -> $ret:ty) => (
        rest!(get_with_params $url:
            fn $fn_name{$($param: $p_ty),*}($($arg: $a_ty),*) -> $ret
        )
    );
    ($url:expr: fn $fn_name:ident ($($arg:ident: $a_ty:ty),*) -> $ret:ty) => (
        rest!(get_with_params $url:
            fn $fn_name{}($($arg: $a_ty),*) -> $ret
        )
    )
)

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

    #[deriving(Decodable)]
    struct Test {
        hello: String,
    }

    // TODO: Host these on GitHub-Pages or a local test server
    get!("https://raw.githubusercontent.com/cybergeek94/ferrite/master/json/hello_world.json": fn hello_world() -> Test)

    get!("https://raw.githubusercontent.com/cybergeek94/ferrite/master/json/hello_vec.json": fn hello_vec() -> Vec<Test>)

    get!("https://raw.githubusercontent.com/cybergeek94/ferrite/master/json/hello_{}.json": fn hello{val: &str}() -> Test)

    #[test]
    fn test_hello_world() {
        let test = hello_world().unwrap();

        assert!(test.hello.as_slice() == "world");
    }

    #[test]
    fn test_hello() {
        let test = hello("world").unwrap();

        assert!(test.hello.as_slice() == "world");
    }

    #[test]
    fn test_hello_vec() {
        let test_vec = hello_vec().unwrap();
        let mut test_iter = test_vec.iter();

        assert!(test_iter.next().unwrap().hello.as_slice() == "world");
        assert!(test_iter.next().unwrap().hello.as_slice() == "nation");
        assert!(test_iter.next().unwrap().hello.as_slice() == "city");
        assert!(test_iter.next().unwrap().hello.as_slice() == "person");
        assert!(test_iter.next().is_none());
    }

}
<commit_msg>Implement and test POST urlencoded<commit_after>#![feature(macro_rules)]
#![allow(unused_imports)]
extern crate serialize;
extern crate rest_client;

/// Reexported types
pub use self::ferrite::{
    JsonError,
    RestClient,
    RestError,
    decode,
    APIError,
    RestErr,
    StatusErr,
    JsonErr
};

mod ferrite {
    pub use serialize::json::DecoderError as JsonError;
    pub use rest_client::{RestClient, RestError};
    pub use serialize::json::decode;

    #[deriving(Show)]
    pub enum APIError {
        RestErr(RestError),
        StatusErr(String),
        JsonErr(JsonError),
    }
}

macro_rules! rest(
    ($method:ident $url:expr: fn $fn_name:ident {$($param:ident: $p_ty: ty),*}($($arg:ident: $a_ty:ty),*) -> $ret:ty) => (
        fn $fn_name($($param: $p_ty),* $($arg: $a_ty),*) -> Result<$ret, APIError> {
            use ferrite::{
                JsonError,
                RestClient,
                RestError,
                decode,
                APIError,
                RestErr,
                StatusErr,
                JsonErr
            };

            pair!()

            let url = format!($url, $($param),*);

            let owned: Vec<(&str, String)> = vec![$((stringify!($arg), $arg.to_string())),*];
            let params: Vec<(&str, &str)> = owned.iter().map(pair).collect();

            let response = try!(RestClient::$method(url.as_slice(), params.as_slice()).map_err(|e| RestErr(e)));

            if response.body.is_empty() {
                Err(StatusErr(response.status.to_string()))
            } else {
                decode::<$ret>(response.body.as_slice()).map_err(|e| JsonErr(e))
            }
        }
    );
    ($method:ident $url:expr: fn $fn_name:ident ($($arg:ident: $a_ty:ty),*) -> $ret:ty) => (
        rest!($method $url fn $fn_name{}($($arg: $a_ty),*) -> $ret)
    )
)

macro_rules! pair(
    () => (
        fn pair<'a>(tup: &'a (&'a str, String)) -> (&'a str, &'a str) {
            let (ref a, ref b) = *tup;
            (*a, b.as_slice())
        }
    )
)

#[macro_export]
macro_rules! get(
    ($url:expr: fn $fn_name:ident {$($param:ident: $p_ty: ty),*}($($arg:ident: $a_ty:ty),*) -> $ret:ty) => (
        rest!(get_with_params $url:
            fn $fn_name{$($param: $p_ty),*}($($arg: $a_ty),*) -> $ret
        )
    );
    ($url:expr: fn $fn_name:ident ($($arg:ident: $a_ty:ty),*) -> $ret:ty) => (
        rest!(get_with_params $url:
            fn $fn_name{}($($arg: $a_ty),*) -> $ret
        )
    )
)

#[macro_export]
macro_rules! post(
    ($url:expr: fn $fn_name:ident {$($param:ident: $p_ty: ty),*}($($arg:ident: $a_ty:ty),*) -> $ret:ty) => (
        rest!(post_with_params $url:
            fn $fn_name{$($param: $p_ty),*}($($arg: $a_ty),*) -> $ret
        )
    );
    ($url:expr: fn $fn_name:ident ($($arg:ident: $a_ty:ty),*) -> $ret:ty) => (
        rest!(post_with_params $url:
            fn $fn_name{}($($arg: $a_ty),*) -> $ret
        )
    )
)

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

    #[deriving(Decodable)]
    struct Test {
        hello: String,
    }

    // TODO: Host these on GitHub-Pages or a local test server
    get!("https://raw.githubusercontent.com/cybergeek94/ferrite/master/json/hello_world.json": fn hello_world() -> Test)

    get!("https://raw.githubusercontent.com/cybergeek94/ferrite/master/json/hello_vec.json": fn hello_vec() -> Vec<Test>)

    get!("https://raw.githubusercontent.com/cybergeek94/ferrite/master/json/hello_{}.json": fn hello{val: &str}() -> Test)

    #[test]
    fn test_hello_world() {
        let test = hello_world().unwrap();

        assert!(test.hello.as_slice() == "world");
    }

    #[test]
    fn test_hello() {
        let test = hello("world").unwrap();

        assert!(test.hello.as_slice() == "world");
    }

    #[test]
    fn test_hello_vec() {
        let test_vec = hello_vec().unwrap();
        let mut test_iter = test_vec.iter();

        assert!(test_iter.next().unwrap().hello.as_slice() == "world");
        assert!(test_iter.next().unwrap().hello.as_slice() == "nation");
        assert!(test_iter.next().unwrap().hello.as_slice() == "city");
        assert!(test_iter.next().unwrap().hello.as_slice() == "person");
        assert!(test_iter.next().is_none());
    }

    post!("https://raw.githubusercontent.com/cybergeek94/ferrite/master/json/hello_world.json":
        fn post_hello_world() -> Test)

    #[test]
    fn test_post_please_ignore() {
        let test = post_hello_world().unwrap();

        assert!(test.hello.as_slice() == "world");
    }
}
<|endoftext|>