<commit_before>use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::PathBuf;
use std::process::{Command, Output, ExitStatus};
use std::thread::JoinHandle;

mod pipe;

pub fn cmd<T: AsRef<OsStr>>(argv: &[T]) -> Expression {
    let argv_vec = argv.iter().map(|arg| arg.as_ref().to_owned()).collect();
    Expression {
        inner: ExpressionInner::ArgvCommand(argv_vec),
        ioargs: IoArgs::new(),
    }
}

pub fn sh<T: AsRef<OsStr>>(command: T) -> Expression {
    Expression {
        inner: ExpressionInner::ShCommand(command.as_ref().to_owned()),
        ioargs: IoArgs::new(),
    }
}

pub fn pipe(left: Expression, right: Expression) -> Expression {
    Expression {
        inner: ExpressionInner::Pipe(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

pub fn then(left: Expression, right: Expression) -> Expression {
    Expression {
        inner: ExpressionInner::Then(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

#[derive(Clone, Debug)]
pub struct Expression {
    // TODO: Make these private.
    pub inner: ExpressionInner,
    pub ioargs: IoArgs,
}

// TODO: Make this private.
#[derive(Clone, Debug)]
pub enum ExpressionInner {
    ArgvCommand(Vec<OsString>),
    ShCommand(OsString),
    Pipe(Box<Expression>, Box<Expression>),
    Then(Box<Expression>, Box<Expression>),
}

impl Expression {
    pub fn run(&self) -> Result<Output, Error> {
        unreachable!();
    }

    pub fn read(&self) -> Result<String, Error> {
        let (handle, reader) = pipe_with_reader_thread();
        let mut context = IoContext::new();
        context.stdout = handle;
        let status = try!(self.exec(context));
        let stdout_vec = try!(reader.join().unwrap());
        if !status.success() {
            return Err(Error::Status(Output {
                status: status,
                stdout: stdout_vec,
                stderr: Vec::new(),
            }));
        }
        let stdout_string = try!(std::str::from_utf8(&stdout_vec))
                                .trim_right_matches('\n')
                                .to_owned();
        Ok(stdout_string)
    }

    fn exec(&self, parent_context: IoContext) -> io::Result<ExitStatus> {
        self.ioargs.with_child_context(parent_context, |context| {
            match self.inner {
                ExpressionInner::ArgvCommand(ref argv) => exec_argv(argv, context),
                ExpressionInner::ShCommand(ref command) => exec_sh(command, context),
                ExpressionInner::Pipe(ref left, ref right) => exec_pipe(left, right, context),
                ExpressionInner::Then(ref left, ref right) => exec_then(left, right, context),
            }
        })
    }
}

fn exec_argv(argv: &Vec<OsString>, context: IoContext) -> io::Result<ExitStatus> {
    let mut command = Command::new(&argv[0]);
    command.args(&argv[1..]);
    command.stdin(context.stdin.to_stdio());
    command.stdout(context.stdout.to_stdio());
    command.stderr(context.stderr.to_stdio());
    command.status()
}

fn exec_sh(command: &OsStr, context: IoContext) -> io::Result<ExitStatus> {
    // TODO: What shell should we be using here, really?
    // TODO: Figure out how cmd.exe works on Windows.
    let mut argv = Vec::new();
    argv.push("bash".into());
    argv.push("-c".into());
    argv.push(command.to_owned());
    exec_argv(&argv, context)
}

fn exec_pipe(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let left_context = IoContext {
        stdin: context.stdin,
        stdout: write_pipe,
        stderr: context.stderr.clone(),
    };
    let right_context = IoContext {
        stdin: read_pipe,
        stdout: context.stdout,
        stderr: context.stderr,
    };
    // TODO: Use a scoped thread here, to avoid this stupid clone.
    let left_expression_clone = left.clone();
    let thread = std::thread::spawn(move || left_expression_clone.exec(left_context));
    let right_status = try!(right.exec(right_context));
    let left_status = try!(thread.join().unwrap());
    if !right_status.success() {
        Ok(right_status)
    } else {
        Ok(left_status)
    }
}

fn exec_then(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let status = try!(left.exec(context.clone()));
    if !status.success() {
        Ok(status)
    } else {
        right.exec(context)
    }
}

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Utf8(std::str::Utf8Error),
    Status(Output),
}

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

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

// IoArgs store the redirections and other settings associated with an expression. At execution
// time, IoArgs are used to modify an IoContext, which contains the actual pipes that child process
// TODO: Make this private.
#[derive(Clone, Debug)]
pub struct IoArgs {
    stdin: InputArg,
    stdout: OutputArg,
    stderr: OutputArg,
}

impl IoArgs {
    fn new() -> IoArgs {
        IoArgs {
            stdin: InputArg::Inherit,
            stdout: OutputArg::Inherit,
            stderr: OutputArg::Inherit,
        }
    }

    fn with_child_context<F, T>(&self, parent_context: IoContext, inner: F) -> io::Result<T>
        where F: FnOnce(IoContext) -> io::Result<T>
    {
        let (stdin, maybe_stdin_thread) = try!(self.stdin.update_handle(parent_context.stdin));
        let stdout = try!(self.stdout.update_handle(parent_context.stdout));
        let stderr = try!(self.stderr.update_handle(parent_context.stderr));
        let child_context = IoContext {
            stdin: stdin,
            stdout: stdout,
            stderr: stderr,
        };

        let result = try!(inner(child_context));

        if let Some(thread) = maybe_stdin_thread {
            try!(thread.join().unwrap());
        }

        Ok(result)
    }
}

#[derive(Clone, Debug)]
enum InputArg {
    Inherit,
    Null,
    Path(PathBuf),
    Bytes(Vec<u8>),
}

impl InputArg {
    fn update_handle(&self,
                     parent_handle: pipe::Handle)
                     -> io::Result<(pipe::Handle, Option<JoinHandle<io::Result<()>>>)> {
        let mut maybe_thread = None;
        let handle = match self {
            &InputArg::Inherit => parent_handle,
            &InputArg::Null => pipe::Handle::from_file(try!(File::open("/dev/null"))),  // TODO: Windows
            &InputArg::Path(ref p) => pipe::Handle::from_file(try!(File::open(&p))),
            &InputArg::Bytes(ref v) => {
                // TODO: figure out a way to get rid of this clone
                let (handle, thread) = pipe_with_writer_thread(v.clone());
                maybe_thread = Some(thread);
                handle
            }
        };
        Ok((handle, maybe_thread))
    }
}

#[derive(  Clone, Debug)]
enum OutputArg {
    Inherit,
    Null,
    Path(PathBuf), // TODO: stdout/stderr swaps
}

impl OutputArg {
    fn update_handle(&self, parent_handle: pipe::Handle) -> io::Result<pipe::Handle> {
        let handle = match self {
            &OutputArg::Inherit => parent_handle,
            &OutputArg::Null => pipe::Handle::from_file(try!(File::create("/dev/null"))),  // TODO: Windows
            &OutputArg::Path(ref p) => pipe::Handle::from_file(try!(File::create(&p))),
        };
        Ok(handle)
    }
}

// An IoContext represents the file descriptors child processes are talking to at execution time.
// It's initialized in run(), with dups of the stdin/stdout/stderr pipes, and then passed down to
// sub-expressions. Compound expressions will clone() it, and pipes/redirections will modify it
// according to their IoArgs.
#[derive(Clone, Debug)]
pub struct IoContext {
    stdin: pipe::Handle,
    stdout: pipe::Handle,
    stderr: pipe::Handle,
}

impl IoContext {
    fn new() -> IoContext {
        IoContext {
            stdin: pipe::Handle::stdin(),
            stdout: pipe::Handle::stdout(),
            stderr: pipe::Handle::stderr(),
        }
    }
}

fn pipe_with_reader_thread() -> (pipe::Handle, JoinHandle<io::Result<Vec<u8>>>) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = std::thread::spawn(move || {
        let mut read_file = read_pipe.to_file();
        let mut output = Vec::new();
        try!(read_file.read_to_end(&mut output));
        Ok(output)
    });
    (write_pipe, thread)
}

fn pipe_with_writer_thread(input: Vec<u8>) -> (pipe::Handle, JoinHandle<io::Result<()>>) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = std::thread::spawn(move || {
        let mut write_file = write_pipe.to_file();
        try!(write_file.write_all(&input));
        Ok(())
    });
    (read_pipe, thread)
}

#[cfg(test)]
mod test {
    use super::{cmd, sh, pipe, then, InputArg, OutputArg};
    use std::fs::File;
    use std::io::prelude::*;
    use std::path::Path;

    #[test]
    fn test_cmd() {
        let output = cmd(&["echo", "hi"]).read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_sh() {
        let output = sh("echo hi").read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_pipe() {
        let output = pipe(sh("echo hi"), sh("sed s/i/o/")).read().unwrap();
        assert_eq!("ho", output);
    }

    #[test]
    fn test_then() {
        let output = then(sh("echo -n hi"), sh("echo lo")).read().unwrap();
        assert_eq!("hilo", output);
    }

    #[test]
    fn test_input() {
        let mut expr = sh("sed s/f/g/");
        expr.ioargs.stdin = InputArg::Bytes(b"foo".to_vec());
        let output = expr.read().unwrap();
        assert_eq!("goo", output);
    }

    #[test]
    fn test_null() {
        let mut expr = cmd(&["cat"]);
        expr.ioargs.stdin = InputArg::Null;
        expr.ioargs.stdout = OutputArg::Null;
        let output = expr.read().unwrap();
        assert_eq!("", output);
    }

    #[test]
    fn test_path() {
        let input_path = sh("mktemp").read().unwrap();
        let output_path = sh("mktemp").read().unwrap();
        println!("Here are the paths: {:?} {:?}", &input_path, &output_path);
        File::create(&input_path).unwrap().write_all(b"foo").unwrap();
        let mut expr = sh("sed s/o/a/g");
        expr.ioargs.stdin = InputArg::Path(input_path.into());
        expr.ioargs.stdout = OutputArg::Path(output_path.clone().into());
        let output = expr.read().unwrap();
        assert_eq!("", output);
        let mut file_output = String::new();
        File::open(&output_path).unwrap().read_to_string(&mut file_output).unwrap();
        assert_eq!("faa", file_output);
    }
}
<commit_msg>stdin/stdout/stderr methods<commit_after>use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::PathBuf;
use std::process::{Command, Output, ExitStatus};
use std::thread::JoinHandle;

mod pipe;

pub fn cmd<T: AsRef<OsStr>>(argv: &[T]) -> Expression {
    let argv_vec = argv.iter().map(|arg| arg.as_ref().to_owned()).collect();
    Expression {
        inner: ExpressionInner::ArgvCommand(argv_vec),
        ioargs: IoArgs::new(),
    }
}

pub fn sh<T: AsRef<OsStr>>(command: T) -> Expression {
    Expression {
        inner: ExpressionInner::ShCommand(command.as_ref().to_owned()),
        ioargs: IoArgs::new(),
    }
}

pub fn pipe(left: Expression, right: Expression) -> Expression {
    Expression {
        inner: ExpressionInner::Pipe(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

pub fn then(left: Expression, right: Expression) -> Expression {
    Expression {
        inner: ExpressionInner::Then(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

#[derive(Clone, Debug)]
pub struct Expression {
    // TODO: Make these private.
    pub inner: ExpressionInner,
    pub ioargs: IoArgs,
}

// TODO: Make this private.
#[derive(Clone, Debug)]
pub enum ExpressionInner {
    ArgvCommand(Vec<OsString>),
    ShCommand(OsString),
    Pipe(Box<Expression>, Box<Expression>),
    Then(Box<Expression>, Box<Expression>),
}

impl Expression {
    pub fn run(&self) -> Result<Output, Error> {
        unreachable!();
    }

    pub fn read(&self) -> Result<String, Error> {
        let (handle, reader) = pipe_with_reader_thread();
        let mut context = IoContext::new();
        context.stdout = handle;
        let status = try!(self.exec(context));
        let stdout_vec = try!(reader.join().unwrap());
        if !status.success() {
            return Err(Error::Status(Output {
                status: status,
                stdout: stdout_vec,
                stderr: Vec::new(),
            }));
        }
        let stdout_string = try!(std::str::from_utf8(&stdout_vec))
                                .trim_right_matches('\n')
                                .to_owned();
        Ok(stdout_string)
    }

    fn exec(&self, parent_context: IoContext) -> io::Result<ExitStatus> {
        self.ioargs.with_child_context(parent_context, |context| {
            match self.inner {
                ExpressionInner::ArgvCommand(ref argv) => exec_argv(argv, context),
                ExpressionInner::ShCommand(ref command) => exec_sh(command, context),
                ExpressionInner::Pipe(ref left, ref right) => exec_pipe(left, right, context),
                ExpressionInner::Then(ref left, ref right) => exec_then(left, right, context),
            }
        })
    }

    pub fn stdin(&mut self, arg: InputArg) -> &mut Self {
        self.ioargs.stdin = arg;
        self
    }

    pub fn stdout(&mut self, arg: OutputArg) -> &mut Self {
        self.ioargs.stdout = arg;
        self
    }

    pub fn stderr(&mut self, arg: OutputArg) -> &mut Self {
        self.ioargs.stderr = arg;
        self
    }
}

fn exec_argv(argv: &Vec<OsString>, context: IoContext) -> io::Result<ExitStatus> {
    let mut command = Command::new(&argv[0]);
    command.args(&argv[1..]);
    command.stdin(context.stdin.to_stdio());
    command.stdout(context.stdout.to_stdio());
    command.stderr(context.stderr.to_stdio());
    command.status()
}

fn exec_sh(command: &OsStr, context: IoContext) -> io::Result<ExitStatus> {
    // TODO: What shell should we be using here, really?
    // TODO: Figure out how cmd.exe works on Windows.
    let mut argv = Vec::new();
    argv.push("bash".into());
    argv.push("-c".into());
    argv.push(command.to_owned());
    exec_argv(&argv, context)
}

fn exec_pipe(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let left_context = IoContext {
        stdin: context.stdin,
        stdout: write_pipe,
        stderr: context.stderr.clone(),
    };
    let right_context = IoContext {
        stdin: read_pipe,
        stdout: context.stdout,
        stderr: context.stderr,
    };
    // TODO: Use a scoped thread here, to avoid this stupid clone.
    let left_expression_clone = left.clone();
    let thread = std::thread::spawn(move || left_expression_clone.exec(left_context));
    let right_status = try!(right.exec(right_context));
    let left_status = try!(thread.join().unwrap());
    if !right_status.success() {
        Ok(right_status)
    } else {
        Ok(left_status)
    }
}

fn exec_then(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let status = try!(left.exec(context.clone()));
    if !status.success() {
        Ok(status)
    } else {
        right.exec(context)
    }
}

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Utf8(std::str::Utf8Error),
    Status(Output),
}

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

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

// IoArgs store the redirections and other settings associated with an expression. At execution
// time, IoArgs are used to modify an IoContext, which contains the actual pipes that child process
// TODO: Make this private.
#[derive(Clone, Debug)]
pub struct IoArgs {
    stdin: InputArg,
    stdout: OutputArg,
    stderr: OutputArg,
}

impl IoArgs {
    fn new() -> IoArgs {
        IoArgs {
            stdin: InputArg::Inherit,
            stdout: OutputArg::Inherit,
            stderr: OutputArg::Inherit,
        }
    }

    fn with_child_context<F, T>(&self, parent_context: IoContext, inner: F) -> io::Result<T>
        where F: FnOnce(IoContext) -> io::Result<T>
    {
        let (stdin, maybe_stdin_thread) = try!(self.stdin.update_handle(parent_context.stdin));
        let stdout = try!(self.stdout.update_handle(parent_context.stdout));
        let stderr = try!(self.stderr.update_handle(parent_context.stderr));
        let child_context = IoContext {
            stdin: stdin,
            stdout: stdout,
            stderr: stderr,
        };

        let result = try!(inner(child_context));

        if let Some(thread) = maybe_stdin_thread {
            try!(thread.join().unwrap());
        }

        Ok(result)
    }
}

#[derive(Clone, Debug)]
pub enum InputArg {
    Inherit,
    Null,
    Path(PathBuf),
    Bytes(Vec<u8>),
}

impl InputArg {
    fn update_handle(&self,
                     parent_handle: pipe::Handle)
                     -> io::Result<(pipe::Handle, Option<JoinHandle<io::Result<()>>>)> {
        let mut maybe_thread = None;
        let handle = match self {
            &InputArg::Inherit => parent_handle,
            &InputArg::Null => pipe::Handle::from_file(try!(File::open("/dev/null"))),  // TODO: Windows
            &InputArg::Path(ref p) => pipe::Handle::from_file(try!(File::open(&p))),
            &InputArg::Bytes(ref v) => {
                // TODO: figure out a way to get rid of this clone
                let (handle, thread) = pipe_with_writer_thread(v.clone());
                maybe_thread = Some(thread);
                handle
            }
        };
        Ok((handle, maybe_thread))
    }
}

#[derive(  Clone, Debug)]
pub enum OutputArg {
    Inherit,
    Null,
    Path(PathBuf), // TODO: stdout/stderr swaps
}

impl OutputArg {
    fn update_handle(&self, parent_handle: pipe::Handle) -> io::Result<pipe::Handle> {
        let handle = match self {
            &OutputArg::Inherit => parent_handle,
            &OutputArg::Null => pipe::Handle::from_file(try!(File::create("/dev/null"))),  // TODO: Windows
            &OutputArg::Path(ref p) => pipe::Handle::from_file(try!(File::create(&p))),
        };
        Ok(handle)
    }
}

// An IoContext represents the file descriptors child processes are talking to at execution time.
// It's initialized in run(), with dups of the stdin/stdout/stderr pipes, and then passed down to
// sub-expressions. Compound expressions will clone() it, and pipes/redirections will modify it
// according to their IoArgs.
#[derive(Clone, Debug)]
pub struct IoContext {
    stdin: pipe::Handle,
    stdout: pipe::Handle,
    stderr: pipe::Handle,
}

impl IoContext {
    fn new() -> IoContext {
        IoContext {
            stdin: pipe::Handle::stdin(),
            stdout: pipe::Handle::stdout(),
            stderr: pipe::Handle::stderr(),
        }
    }
}

fn pipe_with_reader_thread() -> (pipe::Handle, JoinHandle<io::Result<Vec<u8>>>) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = std::thread::spawn(move || {
        let mut read_file = read_pipe.to_file();
        let mut output = Vec::new();
        try!(read_file.read_to_end(&mut output));
        Ok(output)
    });
    (write_pipe, thread)
}

fn pipe_with_writer_thread(input: Vec<u8>) -> (pipe::Handle, JoinHandle<io::Result<()>>) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = std::thread::spawn(move || {
        let mut write_file = write_pipe.to_file();
        try!(write_file.write_all(&input));
        Ok(())
    });
    (read_pipe, thread)
}

#[cfg(test)]
mod test {
    use super::{cmd, sh, pipe, then, InputArg, OutputArg};
    use std::fs::File;
    use std::io::prelude::*;

    #[test]
    fn test_cmd() {
        let output = cmd(&["echo", "hi"]).read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_sh() {
        let output = sh("echo hi").read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_pipe() {
        let output = pipe(sh("echo hi"), sh("sed s/i/o/")).read().unwrap();
        assert_eq!("ho", output);
    }

    #[test]
    fn test_then() {
        let output = then(sh("echo -n hi"), sh("echo lo")).read().unwrap();
        assert_eq!("hilo", output);
    }

    #[test]
    fn test_input() {
        let mut expr = sh("sed s/f/g/");
        expr.stdin(InputArg::Bytes(b"foo".to_vec()));
        let output = expr.read().unwrap();
        assert_eq!("goo", output);
    }

    #[test]
    fn test_null() {
        let mut expr = cmd(&["cat"]);
        expr.stdin(InputArg::Null);
        expr.stdout(OutputArg::Null);
        let output = expr.read().unwrap();
        assert_eq!("", output);
    }

    #[test]
    fn test_path() {
        let input_path = sh("mktemp").read().unwrap();
        let output_path = sh("mktemp").read().unwrap();
        println!("Here are the paths: {:?} {:?}", &input_path, &output_path);
        File::create(&input_path).unwrap().write_all(b"foo").unwrap();
        let mut expr = sh("sed s/o/a/g");
        expr.stdin(InputArg::Path(input_path.into()));
        expr.stdout(OutputArg::Path(output_path.clone().into()));
        let output = expr.read().unwrap();
        assert_eq!("", output);
        let mut file_output = String::new();
        File::open(&output_path).unwrap().read_to_string(&mut file_output).unwrap();
        assert_eq!("faa", file_output);
    }
}
<|endoftext|>


<commit_before>#![warn(missing_docs)]

//! A `Pinboard` is a shared, mutable, eventually consistent, lock-free data-structure.  This
//! allows multiple threads to communicate in a decoupled way by publishing data to the pinboard
//! which other threads can then read in an eventually consistent way.
//!
//! This is not a silver bullet though, there are various limitations of `Pinboard` that trade off
//! the nice behaviour described above.
//!
//! * Eventual consistency:
//!     * Writes from one thread are not guaranteed to be seen by reads from another thread
//!     * Writes from one thread can overwrite writes from another thread
//! * No in-place mutation:
//!     * The only write primitive completely overwrites the data on the `Pinboard`
//! * Requires `Clone`:
//!     * All reads return a clone of the data, decoupling the lifetime of the read value from the
//!     data stored in the global reference.

extern crate crossbeam;

use crossbeam::mem::epoch::{Atomic, Owned, pin};
use std::sync::atomic::Ordering::*;

use std::ops::Deref;

/// An instance of a `Pinboard`, holds a shared, mutable, eventually-consistent reference to a `T`.
pub struct Pinboard<T: Clone>(Atomic<T>);

impl<T: Clone> Pinboard<T> {
    /// Create a new `Pinboard` instance holding the given value.
    pub fn new(t: T) -> Pinboard<T> {
        let t = Owned::new(t);
        let p = Pinboard::default();
        p.0.store(Some(t), Release);
        p
    }

    /// Update the value stored in the `Pinboard`.
    pub fn set(&self, t: T) {
        let guard = pin();
        let t = Owned::new(t);
        if let Some(t) = self.0.swap(Some(t), Release, &guard) {
            unsafe {
                guard.unlinked(t);
            }
        }
    }

    /// Clear out the `Pinboard` so its no longer holding any data.
    pub fn clear(&self) {
        let guard = pin();
        if let Some(t) = self.0.swap(None, Release, &guard) {
            unsafe {
                guard.unlinked(t);
            }
        }
    }

    /// Get a copy of the latest (well, recent) version of the posted data.
    pub fn read(&self) -> Option<T> {
        let guard = pin();
        let t = self.0.load(Acquire, &guard);
        t.map(|t| -> &T { t.deref() }).cloned()
    }
}

impl<T: Clone> Default for Pinboard<T> {
    fn default() -> Pinboard<T> {
        Pinboard(Atomic::null())
    }
}

impl<T: Clone> Drop for Pinboard<T> {
    fn drop(&mut self) {
        // Make sure any stored data is marked for deletion
        self.clear();
    }
}

/// An wrapper around a `Pinboard` which provides the guarantee it is never empty.
pub struct NonEmptyPinboard<T: Clone>(Pinboard<T>);

impl<T: Clone> NonEmptyPinboard<T> {
    /// Create a new `NonEmptyPinboard` instance holding the given value.
    pub fn new(t: T) -> NonEmptyPinboard<T> {
        NonEmptyPinboard(Pinboard::new(t))
    }

    /// Update the value stored in the `NonEmptyPinboard`.
    #[inline]
    pub fn set(&self, t: T) {
        self.0.set(t)
    }

    /// Get a copy of the latest (well, recent) version of the posted data.
    #[inline]
    pub fn read(&self) -> T {
        // Unwrap the option returned by the inner `Pinboard`. This will never panic, because it's
        // impossible for this `Pinboard` to be empty (though it's not possible to prove this to the
        // compiler).
        match self.0.read() {
            Some(t) => t,
            None => unreachable!("Inner pointer was unexpectedly null"),
        }
    }
}

macro_rules! debuggable {
    ($struct:ident, $trait:ident) => {
        impl<T: Clone> ::std::fmt::$trait for $struct<T> where T: ::std::fmt::$trait {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
                write!(f, "{}(", stringify!($struct))?;
                ::std::fmt::$trait::fmt(&self.read(), f)?;
                write!(f, ")")
            }
        }
    }
}

debuggable!(Pinboard, Debug);
debuggable!(NonEmptyPinboard, Debug);
debuggable!(NonEmptyPinboard, Binary);
debuggable!(NonEmptyPinboard, Display);
debuggable!(NonEmptyPinboard, LowerExp);
debuggable!(NonEmptyPinboard, LowerHex);
debuggable!(NonEmptyPinboard, Octal);
debuggable!(NonEmptyPinboard, Pointer);
debuggable!(NonEmptyPinboard, UpperExp);
debuggable!(NonEmptyPinboard, UpperHex);

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

    fn consume<T: Clone + Display>(t: &Pinboard<T>) {
        loop {
            match t.read() {
                Some(_) => {}
                None => break,
            }
            std::thread::sleep(std::time::Duration::from_millis(1));
        }
    }

    fn produce(t: &Pinboard<u32>) {
        for i in 1..100 {
            t.set(i);
            std::thread::sleep(std::time::Duration::from_millis(2));
        }
        t.clear();
    }

    #[test]
    fn it_works() {
        let t = Pinboard::<u32>::default();
        assert_eq!(None, t.read());
        t.set(3);
        assert_eq!(Some(3), t.read());
        t.clear();
        assert_eq!(None, t.read());
    }

    #[test]
    fn single_producer_single_consumer() {
        let t = Pinboard::<u32>::new(0);

        crossbeam::scope(|scope| {
                             scope.spawn(|| produce(&t));
                             scope.spawn(|| consume(&t));
                         })
    }

    #[test]
    fn multi_producer_single_consumer() {
        let t = Pinboard::<u32>::new(0);

        crossbeam::scope(|scope| {
                             scope.spawn(|| produce(&t));
                             scope.spawn(|| produce(&t));
                             scope.spawn(|| produce(&t));
                             scope.spawn(|| consume(&t));
                         })
    }

    #[test]
    fn single_producer_multi_consumer() {
        let t = Pinboard::<u32>::new(0);

        crossbeam::scope(|scope| {
                             scope.spawn(|| produce(&t));
                             scope.spawn(|| consume(&t));
                             scope.spawn(|| consume(&t));
                             scope.spawn(|| consume(&t));
                         })
    }

    #[test]
    fn multi_producer_multi_consumer() {
        let t = Pinboard::<u32>::new(0);

        crossbeam::scope(|scope| {
                             scope.spawn(|| produce(&t));
                             scope.spawn(|| produce(&t));
                             scope.spawn(|| produce(&t));
                             scope.spawn(|| consume(&t));
                             scope.spawn(|| consume(&t));
                             scope.spawn(|| consume(&t));
                         })
    }

    #[test]
    fn non_empty_pinboard() {
        let t = NonEmptyPinboard::<u32>::new(3);
        assert_eq!(3, t.read());
        t.set(4);
        assert_eq!(4, t.read());
    }
}
<commit_msg>Add test<commit_after>#![warn(missing_docs)]

//! A `Pinboard` is a shared, mutable, eventually consistent, lock-free data-structure.  This
//! allows multiple threads to communicate in a decoupled way by publishing data to the pinboard
//! which other threads can then read in an eventually consistent way.
//!
//! This is not a silver bullet though, there are various limitations of `Pinboard` that trade off
//! the nice behaviour described above.
//!
//! * Eventual consistency:
//!     * Writes from one thread are not guaranteed to be seen by reads from another thread
//!     * Writes from one thread can overwrite writes from another thread
//! * No in-place mutation:
//!     * The only write primitive completely overwrites the data on the `Pinboard`
//! * Requires `Clone`:
//!     * All reads return a clone of the data, decoupling the lifetime of the read value from the
//!     data stored in the global reference.

extern crate crossbeam;

use crossbeam::mem::epoch::{Atomic, Owned, pin};
use std::sync::atomic::Ordering::*;

use std::ops::Deref;

/// An instance of a `Pinboard`, holds a shared, mutable, eventually-consistent reference to a `T`.
pub struct Pinboard<T: Clone>(Atomic<T>);

impl<T: Clone> Pinboard<T> {
    /// Create a new `Pinboard` instance holding the given value.
    pub fn new(t: T) -> Pinboard<T> {
        let t = Owned::new(t);
        let p = Pinboard::default();
        p.0.store(Some(t), Release);
        p
    }

    /// Update the value stored in the `Pinboard`.
    pub fn set(&self, t: T) {
        let guard = pin();
        let t = Owned::new(t);
        if let Some(t) = self.0.swap(Some(t), Release, &guard) {
            unsafe {
                guard.unlinked(t);
            }
        }
    }

    /// Clear out the `Pinboard` so its no longer holding any data.
    pub fn clear(&self) {
        let guard = pin();
        if let Some(t) = self.0.swap(None, Release, &guard) {
            unsafe {
                guard.unlinked(t);
            }
        }
    }

    /// Get a copy of the latest (well, recent) version of the posted data.
    pub fn read(&self) -> Option<T> {
        let guard = pin();
        let t = self.0.load(Acquire, &guard);
        t.map(|t| -> &T { t.deref() }).cloned()
    }
}

impl<T: Clone> Default for Pinboard<T> {
    fn default() -> Pinboard<T> {
        Pinboard(Atomic::null())
    }
}

impl<T: Clone> Drop for Pinboard<T> {
    fn drop(&mut self) {
        // Make sure any stored data is marked for deletion
        self.clear();
    }
}

/// An wrapper around a `Pinboard` which provides the guarantee it is never empty.
pub struct NonEmptyPinboard<T: Clone>(Pinboard<T>);

impl<T: Clone> NonEmptyPinboard<T> {
    /// Create a new `NonEmptyPinboard` instance holding the given value.
    pub fn new(t: T) -> NonEmptyPinboard<T> {
        NonEmptyPinboard(Pinboard::new(t))
    }

    /// Update the value stored in the `NonEmptyPinboard`.
    #[inline]
    pub fn set(&self, t: T) {
        self.0.set(t)
    }

    /// Get a copy of the latest (well, recent) version of the posted data.
    #[inline]
    pub fn read(&self) -> T {
        // Unwrap the option returned by the inner `Pinboard`. This will never panic, because it's
        // impossible for this `Pinboard` to be empty (though it's not possible to prove this to the
        // compiler).
        match self.0.read() {
            Some(t) => t,
            None => unreachable!("Inner pointer was unexpectedly null"),
        }
    }
}

macro_rules! debuggable {
    ($struct:ident, $trait:ident) => {
        impl<T: Clone> ::std::fmt::$trait for $struct<T> where T: ::std::fmt::$trait {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
                write!(f, "{}(", stringify!($struct))?;
                ::std::fmt::$trait::fmt(&self.read(), f)?;
                write!(f, ")")
            }
        }
    }
}

debuggable!(Pinboard, Debug);
debuggable!(NonEmptyPinboard, Debug);
debuggable!(NonEmptyPinboard, Binary);
debuggable!(NonEmptyPinboard, Display);
debuggable!(NonEmptyPinboard, LowerExp);
debuggable!(NonEmptyPinboard, LowerHex);
debuggable!(NonEmptyPinboard, Octal);
debuggable!(NonEmptyPinboard, Pointer);
debuggable!(NonEmptyPinboard, UpperExp);
debuggable!(NonEmptyPinboard, UpperHex);

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

    fn consume<T: Clone + Display>(t: &Pinboard<T>) {
        loop {
            match t.read() {
                Some(_) => {}
                None => break,
            }
            std::thread::sleep(std::time::Duration::from_millis(1));
        }
    }

    fn produce(t: &Pinboard<u32>) {
        for i in 1..100 {
            t.set(i);
            std::thread::sleep(std::time::Duration::from_millis(2));
        }
        t.clear();
    }

    fn check_debug<T: ::std::fmt::Debug>(_: T) {}

    #[test]
    fn it_works() {
        let t = Pinboard::<u32>::default();
        assert_eq!(None, t.read());
        t.set(3);
        assert_eq!(Some(3), t.read());
        t.clear();
        assert_eq!(None, t.read());
    }

    #[test]
    fn single_producer_single_consumer() {
        let t = Pinboard::<u32>::new(0);

        crossbeam::scope(|scope| {
                             scope.spawn(|| produce(&t));
                             scope.spawn(|| consume(&t));
                         })
    }

    #[test]
    fn multi_producer_single_consumer() {
        let t = Pinboard::<u32>::new(0);

        crossbeam::scope(|scope| {
                             scope.spawn(|| produce(&t));
                             scope.spawn(|| produce(&t));
                             scope.spawn(|| produce(&t));
                             scope.spawn(|| consume(&t));
                         })
    }

    #[test]
    fn single_producer_multi_consumer() {
        let t = Pinboard::<u32>::new(0);

        crossbeam::scope(|scope| {
                             scope.spawn(|| produce(&t));
                             scope.spawn(|| consume(&t));
                             scope.spawn(|| consume(&t));
                             scope.spawn(|| consume(&t));
                         })
    }

    #[test]
    fn multi_producer_multi_consumer() {
        let t = Pinboard::<u32>::new(0);

        crossbeam::scope(|scope| {
                             scope.spawn(|| produce(&t));
                             scope.spawn(|| produce(&t));
                             scope.spawn(|| produce(&t));
                             scope.spawn(|| consume(&t));
                             scope.spawn(|| consume(&t));
                             scope.spawn(|| consume(&t));
                         })
    }

    #[test]
    fn non_empty_pinboard() {
        let t = NonEmptyPinboard::<u32>::new(3);
        assert_eq!(3, t.read());
        t.set(4);
        assert_eq!(4, t.read());
    }

    #[test]
    fn debuggable() {
        let t = Pinboard::<i32>::new(3);
        check_debug(t);
        let t = NonEmptyPinboard::<i32>::new(2);
        check_debug(t);
    }
}
<|endoftext|>


<commit_before>
#![crate_name="mclient"]

#![feature(globs)]
use std::io::*;
use std::io::net::ip::SocketAddr;
use std::from_str::FromStr;
use std::time::Duration;
use std::default::Default;

pub trait Mclient {
    fn get(&mut self,key:&str) -> Result<String,Error> ;
}

pub struct Client {
    addr : SocketAddr,
    conn : Option<TcpStream>
}

#[deriving(PartialEq, Eq, Clone, Show)]
pub enum ErrorKind {
    InvalidHost,
    InvalidResponse,
    InterIoErr(IoError)
}

#[deriving(PartialEq, Eq, Clone, Show)]
pub struct Error {
    desc : &'static str,
    detail: Option<String>,
    kind : ErrorKind
}

pub fn new(host:&str,port:u16) -> Result<Client,Error> {
    let ipo : Option<IpAddr> = FromStr::from_str(host);
    match ipo {
        Some(ip) => {
            Ok(Client{addr:SocketAddr{ip:ip,port:port},conn:None})
        },
        None => {
            Err(Error{
                desc : "invalid host",
                kind : InvalidHost,
                detail : None
            })
        }
    }
}

impl Mclient for Client {
    fn get(&mut self,key:&str) -> Result<String,Error> {
        assert!(!key.contains(" "));
        assert!(!key.contains_char('\t'));
        assert!(!key.contains_char('\n'));
        let cmd = String::from_str("get ") + key.into_string() + "\r\n".into_string();
        if self.conn.is_none() {
            match TcpStream::connect_timeout(self.addr,Duration::seconds(1)) {
                Ok(c) => {
                    self.conn = Some(c);
                },
                Err(e) => {
                    return Err(Error{
                        desc : "fail to conn",
                        detail : None,
                        kind : InterIoErr(e)
                    })
                }
            }
        }

        let mut tc = self.conn.unwrap();
        tc.write_str(cmd.as_slice());
        let mut ret = [0u8,..1024];
        match tc.read_at_least(5,ret) {
            Ok(nread) => {
                let back = ret.slice_to(nread).clone();
                let first5 = back.slice_to(5);
                match first5 {

                    "END\r\n".as_bytes() {
                        Ok("".into_string())
                    },

                    _ => {
                        Err(Error{
                            desc : "invalid Response",
                            detail : None,
                            kind : InvalidResponse
                        })
                    }
                }
            },
            Err(err) => {
                Err(Error{
                    desc : "fail to read",
                    detail : None,
                    kind : InterIoErr(err)
                })
            }
        }
    }
}

#[test]
fn test_get() {
    let mut c = new("127.0.0.1",11211);
    assert!(c.is_ok());
    match c {
        Ok(mut mc) => { let ret = mc.get("foo");println!("ret {}",ret); }
        Err(e) => { fail!("not ok"); }
    }
}

<commit_msg>add enum Mc req & res<commit_after>
#![crate_name="mclient"]

#![feature(globs)]
use std::io::*;
use std::io::net::ip::SocketAddr;
use std::from_str::FromStr;
use std::time::Duration;
use std::default::Default;

pub trait Mclient {
    fn get(&mut self,key:&str) -> Result<String,Error> ;
}

pub struct Client {
    addr : SocketAddr,
    conn : Option<TcpStream>
}

#[deriving(PartialEq, Eq, Clone, Show)]
pub enum ErrorKind {
    InvalidHost,
    InvalidResponse,
    InterIoErr(IoError)
}

#[deriving(PartialEq, Eq, Clone, Show)]
struct Val {
    key : String,
    flag : u16,
    len : u64,
    v : Vec<u8>
}

#[deriving(PartialEq, Eq, Clone, Show)]
enum Mcresponse {
    Stored,
    NotStored,
    Deleted,
    NotFound,
    End,
    Value(Val)
}

enum Mcrequest {
    Get(&str),
    Set()
}

#[deriving(PartialEq, Eq, Clone, Show)]
pub struct Error {
    desc : &'static str,
    detail: Option<String>,
    kind : ErrorKind
}

pub fn new(host:&str,port:u16) -> Result<Client,Error> {
    let ipo : Option<IpAddr> = FromStr::from_str(host);
    match ipo {
        Some(ip) => {
            Ok(Client{addr:SocketAddr{ip:ip,port:port},conn:None})
        },
        None => {
            Err(Error{
                desc : "invalid host",
                kind : InvalidHost,
                detail : None
            })
        }
    }
}

impl Mclient for Client {
    fn get(&mut self,key:&str) -> Result<String,Error> {
        assert!(!key.contains(" "));
        assert!(!key.contains_char('\t'));
        assert!(!key.contains_char('\n'));
        let cmd = String::from_str("get ") + key.into_string() + "\r\n".into_string();
        if self.conn.is_none() {
            match TcpStream::connect_timeout(self.addr,Duration::seconds(1)) {
                Ok(c) => {
                    self.conn = Some(c);
                },
                Err(e) => {
                    return Err(Error{
                        desc : "fail to conn",
                        detail : None,
                        kind : InterIoErr(e)
                    })
                }
            }
        }

        let mut tc = self.conn.unwrap();
        tc.write_str(cmd.as_slice());
        let mut ret = [0u8,..1024];
        match tc.read_at_least(5,ret) {
            Ok(nread) => {
                let back = ret.slice_to(nread).clone();
                let first5 = back.slice_to(5);
                match first5 {

                    "END\r\n".as_bytes() {
                        Ok("".into_string())
                    },

                    _ => {
                        Err(Error{
                            desc : "invalid Response",
                            detail : None,
                            kind : InvalidResponse
                        })
                    }
                }
            },
            Err(err) => {
                Err(Error{
                    desc : "fail to read",
                    detail : None,
                    kind : InterIoErr(err)
                })
            }
        }
    }
}

#[test]
fn test_get() {
    let mut c = new("127.0.0.1",11211);
    assert!(c.is_ok());
    match c {
        Ok(mut mc) => { let ret = mc.get("foo");println!("ret {}",ret); }
        Err(e) => { fail!("not ok"); }
    }
}

<|endoftext|>


<commit_before>#![feature(macro_rules)]
#![allow(unused_variable)]
#![allow(dead_code)]

extern crate serialize;
extern crate url;
extern crate time;

use std::iter::Peekable;
use std::vec::MoveItems;

use self::client::{JsonClient, Client, JsonResult};
use self::sub::Subreddit;
use self::user::{User, Message};

use self::time::{Timespec, Tm, at_utc};
use self::url::Url;

mod client;
pub mod user;
pub mod sub;
pub mod post;

pub static BASE_URL: &'static str = "https://www.reddit.com/";

pub type RedditResult<T> = Result<T, RedditError>;

static CLIENT: Client = self::client::Client;

#[deriving(Show)]
pub enum RedditError {
    /// Authentication failed. Possibly because of an invalid username/password combo,
    /// or an expired session cookie. Contains exact error message from the reddit API.
    AuthError(String),
    /// The user is not allowed to access that resource (HTTP 403).
    PermissionDenied,
    /// The requested resource was not found (HTTP 404).
    NotFound,
    /// This API call requires a modhash
    NeedModhash,
    /// The submission failed because reddit is requiring the user to solve a captcha.
    NeedCaptcha,
}

/// The global reddit instance that holds the client and modhash.
/// All API endpoints require an instance of this struct to read or update the modhash.

// Sucks we can't init this
local_data_key!(batch_size: u32)

/// Get the batch size or a sensible default
pub fn get_batch_size() -> u32 {
    batch_size.get().map_or(50u32, |val| *val)
}

pub fn set_batch_size(val: u32) {
    batch_size.replace(Some(50));
}

/// Login to reddit. Returns `Ok(Session)` on success, `Err(AuthError("reason"))` on failure.
pub fn login(user: &str, pass: &str, remain: bool) -> RedditResult<Session> {
    let params = params! {
        "user": user,
        "pass": pass,
        "rem": remain,
    };

    unimplemented!();
}

/// Resume a session with the given cookie string; does not make a request
pub fn resume_session(cookie: &str) -> Session {
    Session {
        cookie: cookie.into_string(),
    }
}

/// Find the subreddit with the given /r/ value
pub fn sub(sub: &str) -> RedditResult<Subreddit> {
    let url = {
        let url = format!("{}r/{}/about.json", BASE_URL, sub);
        Url::parse(url.as_slice()).unwrap()
    };

    let data = CLIENT.get(&url);

    println!("{}", data);

    unimplemented!();

}

/// Find a user with the given /u/ value
pub fn user(user: &str) -> RedditResult<User> {
    unimplemented!();
}

/// Struct representing an authenticated user session;
/// required by any API endpoint that submits changes to reddit, such as posting to subreddits, replying to comments, etc.
pub struct Session {
    cookie: String,
}

impl Session {
    /// Return info about the current user, retaining the modhash on `self`.
    pub fn me(&self) -> User {
        unimplemented!();
    }

    /// Get the session cookie to be restored later
    /// This consumes the Session
    pub fn cookie(self) -> String {
        self.cookie
    }

    pub fn inbox(&self) -> BatchedIter<Message> {
        unimplemented!();
    }

    pub fn unread(&self) -> BatchedIter<Message> {
        unimplemented!();
    }

    pub fn sent(&self) -> BatchedIter<Message> {
        unimplemented!();
    }

    pub fn needs_captcha(&self) -> bool {
        unimplemented!();
    }
}

/// An iterator that fetches items in batches from an underlying data source.
/// Its item type must implement `Batched`.
pub struct BatchedIter<T> {
    size: u32,
    current: Peekable<T, MoveItems<T>>,
}

impl<T: Batched> Iterator<T> for BatchedIter<T> {
    fn next(&mut self) -> Option<T> {
        let next = self.current.next();

        if self.current.peek().is_none() {
            let batch = Batched::batch(next.as_ref(), self.size);

            if !batch.is_empty() {
                self.current = batch.move_iter().peekable();
            }
        }

        next
    }
}

/// A trait for data types that should be fetched in batches, if possible.
pub trait Batched {
    /// Get the next batch of length `size` or smaller,
    /// starting after `last` if provided, the beginning if not.
    /// If no (more) results are available, return an empty vector.
    fn batch(last: Option<&Self>, size: u32) -> Vec<Self>;
}

/// Convert POSIX time (seconds since January 1, 1970 12:00 AM)
/// to Tm (UTC)
pub fn posix_to_utc(seconds: u64) -> Tm {
    // This cast is a bit dangerous,
    // as it may result in a negative value due to overflow,
    // indicating a pre-epoch time instead of the intended time.
    // However, the point at which POSIX time will overflow a 64-bit integer
    // is, according to Wolfram|Alpha, about 300 billion years in the future.
    // I think it's safe to say that we can deal with this later.
    let tmspec = Timespec::new(seconds as i64, 0);
    at_utc(tmspec)
}

/// Lightweight utilities for working with `serialize::json::Json`.
pub mod json {
    use serialize::json::Json;

    /// Get a u64 from the given JSON and key, convert
    /// it to a Tm in UTC, assuming it is POSIX time
    pub fn find_utc(json: &Json, key: &str) -> Option<Tm> {
        find_u64(json, key).map(super::posix_to_utc)
    }

    #[inline]
    pub fn find<'a>(json: &'a Json, key: &str) -> Option<&'a Json> {
        json.find(&(key.into_string()));
    }

    pub fn find_string(json: &Json, key: &str) -> Option<String> {
        find(json, key).and_then(|j| j.as_string()).map(|s| j.into_string())
    }

    pub fn find_u64(json: &Json, key: &str) -> Option<u64> {
        json_find(json, key).and_then(|j| j.as_u64());
    }

    pub fn find_u32(json: &Json, key: &str) -> Option<u32> {
        json_find(json, key).and_then(|j| j.as_u32());
    }

    /// A lighter-weight implementation alternative of Decodable for
    /// structs that just want to deserialize from JSON
    /// TODO: Implement this using a streaming parser
    pub trait FromJson {
        fn from_json(json: &Json) -> Option<Self>;
    }
}
#[test]
fn it_works() {
}
<commit_msg>Remove dangling docstring<commit_after>#![feature(macro_rules)]
#![allow(unused_variable)]
#![allow(dead_code)]

extern crate serialize;
extern crate url;
extern crate time;

use std::iter::Peekable;
use std::vec::MoveItems;

use self::client::{JsonClient, Client, JsonResult};
use self::sub::Subreddit;
use self::user::{User, Message};

use self::time::{Timespec, Tm, at_utc};
use self::url::Url;

mod client;
pub mod user;
pub mod sub;
pub mod post;

pub static BASE_URL: &'static str = "https://www.reddit.com/";

pub type RedditResult<T> = Result<T, RedditError>;

static CLIENT: Client = self::client::Client;

#[deriving(Show)]
pub enum RedditError {
    /// Authentication failed. Possibly because of an invalid username/password combo,
    /// or an expired session cookie. Contains exact error message from the reddit API.
    AuthError(String),
    /// The user is not allowed to access that resource (HTTP 403).
    PermissionDenied,
    /// The requested resource was not found (HTTP 404).
    NotFound,
    /// This API call requires a modhash
    NeedModhash,
    /// The submission failed because reddit is requiring the user to solve a captcha.
    NeedCaptcha,
}

// Sucks we can't init this
local_data_key!(batch_size: u32)

/// Get the batch size or a sensible default
pub fn get_batch_size() -> u32 {
    batch_size.get().map_or(50u32, |val| *val)
}

pub fn set_batch_size(val: u32) {
    batch_size.replace(Some(50));
}

/// Login to reddit. Returns `Ok(Session)` on success, `Err(AuthError("reason"))` on failure.
pub fn login(user: &str, pass: &str, remain: bool) -> RedditResult<Session> {
    let params = params! {
        "user": user,
        "pass": pass,
        "rem": remain,
    };

    unimplemented!();
}

/// Resume a session with the given cookie string; does not make a request
pub fn resume_session(cookie: &str) -> Session {
    Session {
        cookie: cookie.into_string(),
    }
}

/// Find the subreddit with the given /r/ value
pub fn sub(sub: &str) -> RedditResult<Subreddit> {
    let url = {
        let url = format!("{}r/{}/about.json", BASE_URL, sub);
        Url::parse(url.as_slice()).unwrap()
    };

    let data = CLIENT.get(&url);

    println!("{}", data);

    unimplemented!();

}

/// Find a user with the given /u/ value
pub fn user(user: &str) -> RedditResult<User> {
    unimplemented!();
}

/// Struct representing an authenticated user session;
/// required by any API endpoint that submits changes to reddit, such as posting to subreddits, replying to comments, etc.
pub struct Session {
    cookie: String,
}

impl Session {
    /// Return info about the current user, retaining the modhash on `self`.
    pub fn me(&self) -> User {
        unimplemented!();
    }

    /// Get the session cookie to be restored later
    /// This consumes the Session
    pub fn cookie(self) -> String {
        self.cookie
    }

    pub fn inbox(&self) -> BatchedIter<Message> {
        unimplemented!();
    }

    pub fn unread(&self) -> BatchedIter<Message> {
        unimplemented!();
    }

    pub fn sent(&self) -> BatchedIter<Message> {
        unimplemented!();
    }

    pub fn needs_captcha(&self) -> bool {
        unimplemented!();
    }
}

/// An iterator that fetches items in batches from an underlying data source.
/// Its item type must implement `Batched`.
pub struct BatchedIter<T> {
    size: u32,
    current: Peekable<T, MoveItems<T>>,
}

impl<T: Batched> Iterator<T> for BatchedIter<T> {
    fn next(&mut self) -> Option<T> {
        let next = self.current.next();

        if self.current.peek().is_none() {
            let batch = Batched::batch(next.as_ref(), self.size);

            if !batch.is_empty() {
                self.current = batch.move_iter().peekable();
            }
        }

        next
    }
}

/// A trait for data types that should be fetched in batches, if possible.
pub trait Batched {
    /// Get the next batch of length `size` or smaller,
    /// starting after `last` if provided, the beginning if not.
    /// If no (more) results are available, return an empty vector.
    fn batch(last: Option<&Self>, size: u32) -> Vec<Self>;
}

/// Convert POSIX time (seconds since January 1, 1970 12:00 AM)
/// to Tm (UTC)
pub fn posix_to_utc(seconds: u64) -> Tm {
    // This cast is a bit dangerous,
    // as it may result in a negative value due to overflow,
    // indicating a pre-epoch time instead of the intended time.
    // However, the point at which POSIX time will overflow a 64-bit integer
    // is, according to Wolfram|Alpha, about 300 billion years in the future.
    // I think it's safe to say that we can deal with this later.
    let tmspec = Timespec::new(seconds as i64, 0);
    at_utc(tmspec)
}

/// Lightweight utilities for working with `serialize::json::Json`.
pub mod json {
    use serialize::json::Json;

    /// Get a u64 from the given JSON and key, convert
    /// it to a Tm in UTC, assuming it is POSIX time
    pub fn find_utc(json: &Json, key: &str) -> Option<Tm> {
        find_u64(json, key).map(super::posix_to_utc)
    }

    #[inline]
    pub fn find<'a>(json: &'a Json, key: &str) -> Option<&'a Json> {
        json.find(&(key.into_string()));
    }

    pub fn find_string(json: &Json, key: &str) -> Option<String> {
        find(json, key).and_then(|j| j.as_string()).map(|s| j.into_string())
    }

    pub fn find_u64(json: &Json, key: &str) -> Option<u64> {
        json_find(json, key).and_then(|j| j.as_u64());
    }

    pub fn find_u32(json: &Json, key: &str) -> Option<u32> {
        json_find(json, key).and_then(|j| j.as_u32());
    }

    /// A lighter-weight implementation alternative of Decodable for
    /// structs that just want to deserialize from JSON
    /// TODO: Implement this using a streaming parser
    pub trait FromJson {
        fn from_json(json: &Json) -> Option<Self>;
    }
}
#[test]
fn it_works() {
}
<|endoftext|>


<commit_before>//! Compression middleware for Iron.

extern crate flate2;
extern crate iron;

use std::io::prelude::*;

use flate2::Compression;
use flate2::write::GzEncoder;

use iron::{AfterMiddleware, IronResult, IronError, Request, Response};
use iron::headers::{ContentEncoding, Encoding};

#[derive(Clone)]
pub enum Type {
    Deflate,
    Gzip
}

/// The EncoderWriter is used from the flate2 crate.
pub struct Compressor {
    engine: Type
}

impl Compressor {
    pub fn new(compression: Type) -> Compressor {
        Compressor { engine: compression }
    }
}

impl AfterMiddleware for Compressor {
    fn after(&self, _: &mut Request, mut res: Response) -> IronResult<(Response)> {
        let mut ce_opts = Vec::new();

        match self.engine {
            Type::Deflate => {
                ce_opts.push(Encoding::Deflate);
                res.headers.set(ContentEncoding(ce_opts));
            },
            Type::Gzip => {
                ce_opts.push(Encoding::Gzip);
                res.headers.set(ContentEncoding(ce_opts));
            }
        }

        Ok(res)
    }

    fn catch(&self, _: &mut Request, err: IronError) -> IronResult<Response> {
        Err(err)
    }
}
<commit_msg>still trying to figure out the proper types<commit_after>//! Compression middleware for Iron.

extern crate flate2;
extern crate iron;

use std::io::Read;

use flate2::Compression;
use flate2::read::{DeflateEncoder, GzEncoder};

use iron::{AfterMiddleware, IronResult, IronError, Request, Response};
use iron::headers::{AcceptEncoding, ContentEncoding, Encoding};

#[derive(Clone)]
pub enum Type {
    Deflate,
    Gzip
}

/// The EncoderWriter is used from the flate2 crate.
pub struct Compressor {
    engine: Type
}

impl Compressor {
    pub fn new(compression: Type) -> Compressor {
        Compressor { engine: compression }
    }
}

impl AfterMiddleware for Compressor {
    fn after(&self, req: &mut Request, mut res: Response) -> IronResult<(Response)> {
        if !req.headers.has::<AcceptEncoding>() {
            return Ok(res);
        }

        let mut ce_opts = Vec::new();

        match self.engine {
            Type::Deflate => {
                ce_opts.push(Encoding::Deflate);
                res.headers.set(ContentEncoding(ce_opts));
                res.body = Some(Box::new(DeflateEncoder::new(res.body.unwrap(), Compression::Best)));
            },
            Type::Gzip => {
                ce_opts.push(Encoding::Gzip);
                res.headers.set(ContentEncoding(ce_opts));
                res.body = Some(Box::new(GzEncoder::new(res.body.unwrap(), Compression::Best)));
            }
        }

        Ok(res)
    }

    fn catch(&self, _: &mut Request, err: IronError) -> IronResult<Response> {
        Err(err)
    }
}
<|endoftext|>


<commit_before>//! Clutter is a GObject based library for creating fast, visually rich,
//! graphical user interfaces.
//!
//! ---------------------------------------------------------------------------
//!
//! This library is free software; you can redistribute it and/or modify it
//! under the terms of the GNU Library General Public License as published by
//! the Free Software Foundation; either version 2 of the License, or (at your
//! option) any later version.
//!
//! This library is distributed in the hope that it will be useful, but WITHOUT
//! ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
//! FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
//! License for more details.
//!
//! You may obtain a copy of the GNU Library General Public License from the
//! Free Software Foundation by visiting their Web site or by writing to:
//!
//!     Free Software Foundation, Inc.
//!     59 Temple Place - Suite 330
//!     Boston, MA 02111-1307
//!     USA
//!
//! ---------------------------------------------------------------------------
//!
//! Permission is granted to copy, distribute and/or modify this documentation
//! under the terms of the GNU Free Documentation License, Version 1.1 or any
//! later version published by the Free Software Foundation with no Invariant
//! Sections, no Front-Cover Texts, and no Back-Cover Texts. You may obtain a
//! copy of the GNU Free Documentation License from the Free Software
//! Foundation by visiting their Web site or by writing to the address above.

extern crate cairo;
extern crate libc;

#[link(name = "gobject-2.0")] extern {}
#[link(name = "clutter-1.0")] extern {}

pub mod actor;
pub mod canvas;
pub mod color;
pub mod constraint;
pub mod content;
pub mod scaling;
pub mod stage;
pub mod text;

/// Initialises everything needed to operate with Clutter.
///
/// It is safe to call this function multiple times.
///
/// This function will not abort in case of errors during initialization;
/// `init()` will print out the error message on stderr, and will return an
/// error code. It is up to the application code to handle this case.
pub fn init() {
  unsafe {
    clutter_init(std::ptr::null_mut(), std::ptr::null_mut());
  }
}

/// Starts the Clutter mainloop.
pub fn main() {
  unsafe {
    clutter_main();
  }
}

/// Terminates the Clutter mainloop.
pub fn main_quit() {
  unsafe {
    clutter_main_quit();
  }
}

extern {
  fn clutter_init(argc: *mut i32, argv: *mut i32);
  fn clutter_main();
  fn clutter_main_quit();
}
<commit_msg>Fix address in prelude<commit_after>//! Clutter is a GObject based library for creating fast, visually rich,
//! graphical user interfaces.
//!
//! ---------------------------------------------------------------------------
//!
//! This library is free software; you can redistribute it and/or modify it
//! under the terms of the GNU Library General Public License as published by
//! the Free Software Foundation; either version 2 of the License, or (at your
//! option) any later version.
//!
//! This library is distributed in the hope that it will be useful, but WITHOUT
//! ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
//! FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
//! License for more details.
//!
//! You may obtain a copy of the GNU Library General Public License from the
//! Free Software Foundation by visiting their Web site or by writing to:
//!
//! Free Software Foundation, Inc.
//! 59 Temple Place - Suite 330
//! Boston, MA 02111-1307
//! USA
//!
//! ---------------------------------------------------------------------------
//!
//! Permission is granted to copy, distribute and/or modify this documentation
//! under the terms of the GNU Free Documentation License, Version 1.1 or any
//! later version published by the Free Software Foundation with no Invariant
//! Sections, no Front-Cover Texts, and no Back-Cover Texts. You may obtain a
//! copy of the GNU Free Documentation License from the Free Software
//! Foundation by visiting their Web site or by writing to the address above.

extern crate cairo;
extern crate libc;

#[link(name = "gobject-2.0")] extern {}
#[link(name = "clutter-1.0")] extern {}

pub mod actor;
pub mod canvas;
pub mod color;
pub mod constraint;
pub mod content;
pub mod scaling;
pub mod stage;
pub mod text;

/// Initialises everything needed to operate with Clutter.
///
/// It is safe to call this function multiple times.
///
/// This function will not abort in case of errors during initialization;
/// `init()` will print out the error message on stderr, and will return an
/// error code. It is up to the application code to handle this case.
pub fn init() {
  unsafe {
    clutter_init(std::ptr::null_mut(), std::ptr::null_mut());
  }
}

/// Starts the Clutter mainloop.
pub fn main() {
  unsafe {
    clutter_main();
  }
}

/// Terminates the Clutter mainloop.
pub fn main_quit() {
  unsafe {
    clutter_main_quit();
  }
}

extern {
  fn clutter_init(argc: *mut i32, argv: *mut i32);
  fn clutter_main();
  fn clutter_main_quit();
}
<|endoftext|>


<commit_before>#![crate_name = "static_file"]
#![deny(missing_doc)]
#![feature(phase)]

//! Static file-serving handler.

#[phase(plugin)]
extern crate regex_macros;
extern crate regex;

extern crate http;
extern crate iron;
#[phase(plugin, link)]
extern crate log;
extern crate mount;

use iron::{Request, Response, Url, Handler, Error, IronResult};
use iron::status;
use mount::OriginalUrl;
use std::io::IoError;

/// The static file-serving `Handler`.
///
/// This handler serves files from a single filesystem path, which may be absolute or relative.
/// Incoming requests are mapped onto the filesystem by appending their URL path to the handler's
/// root path. If the filesystem path corresponds to a regular file, the handler will attempt to
/// serve it. Otherwise, if the path corresponds to a directory containing an `index.html`,
/// the handler will attempt to serve that instead. If the path doesn't match any real object
/// in the filesystem, the handler will return `Err(Box<NoFile>)`. If an IO error occurs
/// whilst attempting to serve a file, `Err(Box<FileError(IoError)>)` will be returned.
#[deriving(Clone)]
pub struct Static {
    root_path: Path
}

/// The error returned when a requested URL doesn't map to a real file.
#[deriving(Show)]
pub struct NoFile;

/// The error returned when an IoError occurs during file serving.
#[deriving(Show)]
pub struct FileError(IoError);

impl Error for NoFile {
    fn name(&self) -> &'static str { "No File" }
}

impl Error for FileError {
    fn name(&self) -> &'static str {
        let &FileError(ref error) = self;
        error.desc
    }
}

impl Static {
    /// Create a new instance of `Static` with a given root path.
    ///
    /// If `Path::new("")` is given, files will be served from the current directory.
    pub fn new(root_path: Path) -> Static {
        Static {
            root_path: root_path
        }
    }
}

impl Handler for Static {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        // Get the URL path as a slice of Strings.
        let url_path: &[String] = req.url.path.as_slice();

        // Create a file path by combining the handler's root path and the URL path.
        let requested_path = self.root_path.join(Path::new("").join_many(url_path));

        // If the requested path matches a real file, serve it.
        if requested_path.is_file() {
            match Response::from_file(&requested_path) {
                Ok(response) => {
                    debug!("Serving static file at {}", requested_path.display());
                    return Ok(response);
                },
                Err(err) => {
                    return Err(box FileError(err) as Box<Error + Send>);
                }
            }
        }

        // If the requested path is a directory containing an index.html, serve it.
        let index_path = requested_path.join("index.html");
        if index_path.is_file() {
            // If the URL ends in a slash, serve the file directly.
            // As per servo/rust-url/serialize_path, URLs ending in a slash have
            // an empty string stored as the last component of their path.
            // Rust-url even ensures that url.path is non-empty by
            // appending a forward slash to URLs like http://example.com
            // Some middleware may mutate the URL's path to violate this property,
            // so the empty list case is handled as a redirect.
            match url_path.last().as_ref().map(|s| s.as_slice()) {
                Some("") => {
                    match Response::from_file(&index_path) {
                        Ok(response) => {
                            debug!("Serving static file at {}.", index_path.display());
                            return Ok(response);
                        },
                        Err(err) => {
                            return Err(box FileError(err) as Box<Error + Send>);
                        }
                    }
                },
                // Otherwise, redirect to the directory equivalent of the URL, ala Apache.
                // Some(_) corresponds to a path without a trailing slash, whilst None
                // corresponds to a path that has been mutated by Middleware into the empty list.
                Some(_) | None => {}
            }

            // Perform an HTTP 301 Redirect.
            let redirect_path = match req.extensions.find::<OriginalUrl, Url>() {
                Some(original_url) => format!("{}/", original_url),
                None => format!("{}/", req.url)
            };
            let mut res = Response::with(status::MovedPermanently,
                            format!("Redirecting to {}", redirect_path));
            res.headers.extensions.insert("Location".to_string(), redirect_path);
            return Ok(res);
        }

        // If no file is found, return an appropriate error.
        Err(box NoFile as Box<Error + Send>)
    }
}
<commit_msg>(cleanup) Use Error::abstract.<commit_after>#![crate_name = "static_file"]
#![deny(missing_doc)]
#![feature(phase)]

//! Static file-serving handler.

#[phase(plugin)]
extern crate regex_macros;
extern crate regex;

extern crate http;
extern crate iron;
#[phase(plugin, link)]
extern crate log;
extern crate mount;

use iron::{Request, Response, Url, Handler, Error, IronResult};
use iron::status;
use mount::OriginalUrl;
use std::io::IoError;

/// The static file-serving `Handler`.
///
/// This handler serves files from a single filesystem path, which may be absolute or relative.
/// Incoming requests are mapped onto the filesystem by appending their URL path to the handler's
/// root path. If the filesystem path corresponds to a regular file, the handler will attempt to
/// serve it. Otherwise, if the path corresponds to a directory containing an `index.html`,
/// the handler will attempt to serve that instead. If the path doesn't match any real object
/// in the filesystem, the handler will return `Err(Box<NoFile>)`. If an IO error occurs
/// whilst attempting to serve a file, `Err(Box<FileError(IoError)>)` will be returned.
#[deriving(Clone)]
pub struct Static {
    root_path: Path
}

/// The error returned when a requested URL doesn't map to a real file.
#[deriving(Show)]
pub struct NoFile;

/// The error returned when an IoError occurs during file serving.
#[deriving(Show)]
pub struct FileError(IoError);

impl Error for NoFile {
    fn name(&self) -> &'static str { "No File" }
}

impl Error for FileError {
    fn name(&self) -> &'static str {
        let &FileError(ref error) = self;
        error.desc
    }
}

impl Static {
    /// Create a new instance of `Static` with a given root path.
    ///
    /// If `Path::new("")` is given, files will be served from the current directory.
    pub fn new(root_path: Path) -> Static {
        Static {
            root_path: root_path
        }
    }
}

impl Handler for Static {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        // Get the URL path as a slice of Strings.
        let url_path: &[String] = req.url.path.as_slice();

        // Create a file path by combining the handler's root path and the URL path.
        let requested_path = self.root_path.join(Path::new("").join_many(url_path));

        // If the requested path matches a real file, serve it.
        if requested_path.is_file() {
            match Response::from_file(&requested_path) {
                Ok(response) => {
                    debug!("Serving static file at {}", requested_path.display());
                    return Ok(response);
                },
                Err(err) => {
                    return Err(FileError(err).abstract());
                }
            }
        }

        // If the requested path is a directory containing an index.html, serve it.
        let index_path = requested_path.join("index.html");
        if index_path.is_file() {
            // If the URL ends in a slash, serve the file directly.
            // As per servo/rust-url/serialize_path, URLs ending in a slash have
            // an empty string stored as the last component of their path.
            // Rust-url even ensures that url.path is non-empty by
            // appending a forward slash to URLs like http://example.com
            // Some middleware may mutate the URL's path to violate this property,
            // so the empty list case is handled as a redirect.
            match url_path.last().as_ref().map(|s| s.as_slice()) {
                Some("") => {
                    match Response::from_file(&index_path) {
                        Ok(response) => {
                            debug!("Serving static file at {}.", index_path.display());
                            return Ok(response);
                        },
                        Err(err) => {
                            return Err(FileError(err).abstract());
                        }
                    }
                },
                // Otherwise, redirect to the directory equivalent of the URL, ala Apache.
                // Some(_) corresponds to a path without a trailing slash, whilst None
                // corresponds to a path that has been mutated by Middleware into the empty list.
                Some(_) | None => {}
            }

            // Perform an HTTP 301 Redirect.
            let redirect_path = match req.extensions.find::<OriginalUrl, Url>() {
                Some(original_url) => format!("{}/", original_url),
                None => format!("{}/", req.url)
            };
            let mut res = Response::with(status::MovedPermanently,
                            format!("Redirecting to {}", redirect_path));
            res.headers.extensions.insert("Location".to_string(), redirect_path);
            return Ok(res);
        }

        // If no file is found, return an appropriate error.
        Err(NoFile.abstract())
    }
}
<|endoftext|>


<commit_before>//! Rust friendly bindings to the various *nix system functions.
//!
//! Modules are structured according to the C header file that they would be
//! defined in.
#![crate_name = "nix"]
#![cfg(unix)]
#![allow(non_camel_case_types)]
// latest bitflags triggers a rustc bug with cross-crate macro expansions causing dead_code
// warnings even though the macro expands into something with allow(dead_code)
#![allow(dead_code)]
#![deny(warnings)]

#[macro_use]
extern crate bitflags;

extern crate libc;

#[cfg(test)]
extern crate nix_test as nixtest;

// Re-exports
pub use libc::{c_int, c_void};
pub use errno::Errno;

pub mod errno;
pub mod features;
pub mod fcntl;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod mount;

#[cfg(any(target_os = "linux"))]
pub mod mqueue;

#[cfg(any(target_os = "linux", target_os = "macos"))]
pub mod poll;

pub mod net;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod sched;

pub mod sys;
pub mod unistd;

/*
 *
 * ===== Result / Error =====
 *
 */

use libc::c_char;
use std::{ptr, result};
use std::ffi::{CStr, OsStr};
use std::path::{Path, PathBuf};
use std::os::unix::ffi::OsStrExt;
use std::io;
use std::fmt;
use std::error;
use libc::PATH_MAX;

pub type Result<T> = result::Result<T, Error>;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Error {
    Sys(errno::Errno),
    InvalidPath,
}

impl Error {
    pub fn from_errno(errno: errno::Errno) -> Error {
        Error::Sys(errno)
    }

    pub fn last() -> Error {
        Error::Sys(errno::Errno::last())
    }

    pub fn invalid_argument() -> Error {
        Error::Sys(errno::EINVAL)
    }

    pub fn errno(&self) -> errno::Errno {
        match *self {
            Error::Sys(errno) => errno,
            Error::InvalidPath => errno::Errno::EINVAL,
        }
    }
}

impl From<errno::Errno> for Error {
    fn from(errno: errno::Errno) -> Error { Error::from_errno(errno) }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self {
            &Error::InvalidPath => "Invalid path",
            &Error::Sys(ref errno) => errno.desc(),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::InvalidPath => write!(f, "Invalid path"),
            &Error::Sys(errno) => write!(f, "{:?}: {}", errno, errno.desc()),
        }
    }
}

impl From<Error> for io::Error {
    fn from(err: Error) -> Self {
        match err {
            Error::InvalidPath => io::Error::new(io::ErrorKind::InvalidInput, err),
            Error::Sys(errno) => io::Error::from_raw_os_error(errno as i32),
        }
    }
}

pub trait NixPath {
    fn len(&self) -> usize;

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
        where F: FnOnce(&CStr) -> T;
}

impl NixPath for str {
    fn len(&self) -> usize {
        NixPath::len(OsStr::new(self))
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
        where F: FnOnce(&CStr) -> T {
            OsStr::new(self).with_nix_path(f)
        }
}

impl NixPath for OsStr {
    fn len(&self) -> usize {
        self.as_bytes().len()
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
        where F: FnOnce(&CStr) -> T {
            self.as_bytes().with_nix_path(f)
        }
}

impl NixPath for CStr {
    fn len(&self) -> usize {
        self.to_bytes().len()
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
            where F: FnOnce(&CStr) -> T {
        // Equivalence with the [u8] impl.
        if self.len() >= PATH_MAX as usize {
            return Err(Error::InvalidPath);
        }

        Ok(f(self))
    }
}

impl NixPath for [u8] {
    fn len(&self) -> usize {
        self.len()
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
            where F: FnOnce(&CStr) -> T {
        let mut buf = [0u8; PATH_MAX as usize];

        if self.len() >= PATH_MAX as usize {
            return Err(Error::InvalidPath);
        }

        match self.iter().position(|b| *b == 0) {
            Some(_) => Err(Error::InvalidPath),
            None => {
                unsafe {
                    // TODO: Replace with bytes::copy_memory. rust-lang/rust#24028
                    ptr::copy_nonoverlapping(self.as_ptr(), buf.as_mut_ptr(), self.len());
                    Ok(f(CStr::from_ptr(buf.as_ptr() as *const c_char)))
                }

            }
        }
    }
}

impl NixPath for Path {
    fn len(&self) -> usize {
        NixPath::len(self.as_os_str())
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
        self.as_os_str().with_nix_path(f)
    }
}

impl NixPath for PathBuf {
    fn len(&self) -> usize {
        NixPath::len(self.as_os_str())
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
        self.as_os_str().with_nix_path(f)
    }
}

/// Treats `None` as an empty string.
impl<'a, NP: ?Sized + NixPath>  NixPath for Option<&'a NP> {
    fn len(&self) -> usize {
        self.map_or(0, NixPath::len)
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
        if let Some(nix_path) = *self {
            nix_path.with_nix_path(f)
        } else {
            unsafe { CStr::from_ptr("\0".as_ptr() as *const _).with_nix_path(f) }
        }
    }
}
<commit_msg>Auto merge of #284 - fiveop:fix_build, r=posborne<commit_after>//! Rust friendly bindings to the various *nix system functions.
//!
//! Modules are structured according to the C header file that they would be
//! defined in.
#![crate_name = "nix"]
#![cfg(unix)]
#![allow(non_camel_case_types)]
// latest bitflags triggers a rustc bug with cross-crate macro expansions causing dead_code
// warnings even though the macro expands into something with allow(dead_code)
#![allow(dead_code)]
#![deny(warnings)]

#[macro_use]
extern crate bitflags;

pub extern crate libc;

#[cfg(test)]
extern crate nix_test as nixtest;

// Re-exports
pub use libc::{c_int, c_void};
pub use errno::Errno;

pub mod errno;
pub mod features;
pub mod fcntl;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod mount;

#[cfg(any(target_os = "linux"))]
pub mod mqueue;

#[cfg(any(target_os = "linux", target_os = "macos"))]
pub mod poll;

pub mod net;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod sched;

pub mod sys;
pub mod unistd;

/*
 *
 * ===== Result / Error =====
 *
 */

use libc::c_char;
use std::{ptr, result};
use std::ffi::{CStr, OsStr};
use std::path::{Path, PathBuf};
use std::os::unix::ffi::OsStrExt;
use std::io;
use std::fmt;
use std::error;
use libc::PATH_MAX;

pub type Result<T> = result::Result<T, Error>;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Error {
    Sys(errno::Errno),
    InvalidPath,
}

impl Error {
    pub fn from_errno(errno: errno::Errno) -> Error {
        Error::Sys(errno)
    }

    pub fn last() -> Error {
        Error::Sys(errno::Errno::last())
    }

    pub fn invalid_argument() -> Error {
        Error::Sys(errno::EINVAL)
    }

    pub fn errno(&self) -> errno::Errno {
        match *self {
            Error::Sys(errno) => errno,
            Error::InvalidPath => errno::Errno::EINVAL,
        }
    }
}

impl From<errno::Errno> for Error {
    fn from(errno: errno::Errno) -> Error { Error::from_errno(errno) }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self {
            &Error::InvalidPath => "Invalid path",
            &Error::Sys(ref errno) => errno.desc(),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::InvalidPath => write!(f, "Invalid path"),
            &Error::Sys(errno) => write!(f, "{:?}: {}", errno, errno.desc()),
        }
    }
}

impl From<Error> for io::Error {
    fn from(err: Error) -> Self {
        match err {
            Error::InvalidPath => io::Error::new(io::ErrorKind::InvalidInput, err),
            Error::Sys(errno) => io::Error::from_raw_os_error(errno as i32),
        }
    }
}

pub trait NixPath {
    fn len(&self) -> usize;

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
        where F: FnOnce(&CStr) -> T;
}

impl NixPath for str {
    fn len(&self) -> usize {
        NixPath::len(OsStr::new(self))
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
        where F: FnOnce(&CStr) -> T {
            OsStr::new(self).with_nix_path(f)
        }
}

impl NixPath for OsStr {
    fn len(&self) -> usize {
        self.as_bytes().len()
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
        where F: FnOnce(&CStr) -> T {
            self.as_bytes().with_nix_path(f)
        }
}

impl NixPath for CStr {
    fn len(&self) -> usize {
        self.to_bytes().len()
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
            where F: FnOnce(&CStr) -> T {
        // Equivalence with the [u8] impl.
        if self.len() >= PATH_MAX as usize {
            return Err(Error::InvalidPath);
        }

        Ok(f(self))
    }
}

impl NixPath for [u8] {
    fn len(&self) -> usize {
        self.len()
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
            where F: FnOnce(&CStr) -> T {
        let mut buf = [0u8; PATH_MAX as usize];

        if self.len() >= PATH_MAX as usize {
            return Err(Error::InvalidPath);
        }

        match self.iter().position(|b| *b == 0) {
            Some(_) => Err(Error::InvalidPath),
            None => {
                unsafe {
                    // TODO: Replace with bytes::copy_memory. rust-lang/rust#24028
                    ptr::copy_nonoverlapping(self.as_ptr(), buf.as_mut_ptr(), self.len());
                    Ok(f(CStr::from_ptr(buf.as_ptr() as *const c_char)))
                }

            }
        }
    }
}

impl NixPath for Path {
    fn len(&self) -> usize {
        NixPath::len(self.as_os_str())
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
        self.as_os_str().with_nix_path(f)
    }
}

impl NixPath for PathBuf {
    fn len(&self) -> usize {
        NixPath::len(self.as_os_str())
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
        self.as_os_str().with_nix_path(f)
    }
}

/// Treats `None` as an empty string.
impl<'a, NP: ?Sized + NixPath>  NixPath for Option<&'a NP> {
    fn len(&self) -> usize {
        self.map_or(0, NixPath::len)
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
        if let Some(nix_path) = *self {
            nix_path.with_nix_path(f)
        } else {
            unsafe { CStr::from_ptr("\0".as_ptr() as *const _).with_nix_path(f) }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(alloc)]
#![cfg_attr(test, feature(test, step_by))]

extern crate alloc;

use self::alloc::arc;

use std::cmp::min;
use std::fmt::{Formatter, Debug};
use std::fmt::Error as FmtError;
use std::sync::Arc;
use std::mem;
use std::ops;

/// A vector that can be operated on concurrently via non-overlapping slices.
///
/// Get a `ParVec` and a vector of slices via `new()`, send the slices to other threads
/// and mutate them, then get the mutated vector with `into_inner()` when finished.
pub struct ParVec<T> {
    data: Arc<Vec<T>>,
}

impl<T: 'static + Send + Sync> ParVec<T> {
    /// Create a new `ParVec`, returning it and a vector of slices that can be sent
    /// to other threads and mutated concurrently.
    pub fn new(vec: Vec<T>, slices: usize) -> (ParVec<T>, Vec<ParSlice<T>>) {
        let data = Arc::new(vec);

        let par_slices = sub_slices(&data[..], slices).into_iter()
            .map(|slice|
                ParSlice {
                    _vec: data.clone(),
                    data: unsafe { mem::transmute(slice) },
                }
            ).collect();

        let par_vec = ParVec {
            data: data,
        };

        (par_vec, par_slices)
    }

    /// Take the inner `Vec` if there are no slices remaining.
    /// Returns `Err(self)` if there are still slices out there.
    pub fn into_inner_opt(self) -> Result<Vec<T>, ParVec<T>> {
        // Unwrap if we hold a unique reference
        // (we don't use weak refs so ignore those)
        if arc::strong_count(&self.data) == 1 {
            let vec_ptr: &mut Vec<T> = unsafe { mem::transmute(&*self.data) };
            Ok(mem::replace(vec_ptr, Vec::new()))
        } else {
            Err(self)
        }
    }

    /// Take the inner `Vec`, waiting until all slices have been freed.
    pub fn into_inner(mut self) -> Vec<T> {
        loop {
            match self.into_inner_opt() {
                Ok(vec) => return vec,
                Err(new_self) => self = new_self,
            }
        }
    }
}

fn sub_slices<T>(parent: &[T], slice_count: usize) -> Vec<&[T]> {
    let mut slices = Vec::new();

    let len = parent.len();
    let mut start = 0;

    for curr in (1 .. slice_count + 1).rev() {
        let slice_len = (len - start) / curr;
        let end = min(start + slice_len, len);

        slices.push(&parent[start..end]);
        start += slice_len;
    }

    slices
}

/// A slice of `ParVec` that can be sent to another task for processing.
/// Automatically releases the slice on drop.
pub struct ParSlice<T: Send + 'static> {
    // Just to keep the source vector alive while the slice is,
    // since the ParVec can die asynchronously.
    _vec: Arc<Vec<T>>,
    // This isn't actually &'static but we're guarding it so it's safe.
    data: &'static mut [T],
}

impl<T: Send> ops::Deref for ParSlice<T> {
    type Target = [T];

    fn deref<'a>(&'a self) -> &'a [T] {
        self.data
    }
}

impl<T: Send> ops::DerefMut for ParSlice<T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut [T] {
        self.data
    }
}

impl<T: Send> Debug for ParSlice<T> where T: Debug {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        write!(f, "{:?}", self.data)
    }
}

#[cfg(test)]
mod test {
    extern crate rand;
    extern crate threadpool;
    extern crate test;

    use super::ParVec;

    use std::mem;

    use self::rand::{thread_rng, Rng};
    use self::test::Bencher;
    use self::threadpool::ThreadPool;

    const TEST_SLICES: usize = 8;
    const TEST_MAX: u32 = 1000;

    #[test]
    fn test_unwrap_safely() {
        let (vec, slices) = ParVec::new([5u32; TEST_MAX as usize].to_vec(), TEST_SLICES);
        mem::drop(slices);

        let vec = vec.into_inner();

        assert_eq!(&*vec, &[5u32; TEST_MAX as usize][..]);
    }

    #[test]
    fn test_slices() {
        let (_, slices) = ParVec::new((1u32 .. TEST_MAX).collect(), TEST_SLICES);

        assert_eq!(slices.len(), TEST_SLICES);
    }

    #[bench]
    fn seq_prime_factors_1000(b: &mut Bencher) {
        let vec: Vec<u32> = (1 .. TEST_MAX).collect();

        b.iter(|| {
            let _: Vec<(u32, Vec<u32>)> = vec.iter()
                .map(|&x| (x, get_prime_factors(x)))
                .collect();
        });
    }

    #[bench]
    fn par_prime_factors_1000(b: &mut Bencher) {
        let mut rng = thread_rng();
        let pool = ThreadPool::new(TEST_SLICES);

        b.iter(|| {
            let mut vec: Vec<(u32, Vec<u32>)> = (1 .. TEST_MAX)
                .map(|x| (x, Vec::new())).collect();

            // Shuffle so each thread gets an even distribution of work.
            // Otherwise, the lower threads will quit early.
            rng.shuffle(&mut *vec);

            let (par_vec, par_slices) = ParVec::new(vec, TEST_SLICES);

            for mut slice in par_slices.into_iter() {
                pool.execute(move ||
                    for pair in slice.iter_mut() {
                        let (x, ref mut x_primes) = *pair;
                        *x_primes = get_prime_factors(x);
                    }
                );
            }

            let mut vec = par_vec.into_inner();
            // Sort so they're in the same order as sequential.
            vec.sort();
        });
    }

    fn get_prime_factors(x: u32) -> Vec<u32> {
        (1 .. x).filter(|&y| x % y == 0 && is_prime(y)).collect()
    }

    fn is_prime(x: u32) -> bool {
        if x < 3 { return true; }

        if x & 1 == 0 { return false; }

        for i in (3 .. x).step_by(2) {
            if x % i == 0 { return false; }
        }

        true
    }

}

<commit_msg>Remove `'static + Sync` bounds from `ParVec` and `ParSlice`<commit_after>#![feature(alloc, core)]
#![cfg_attr(test, feature(test, step_by))]

extern crate alloc;

use self::alloc::arc;

use std::fmt::{Formatter, Debug};
use std::fmt::Error as FmtError;
use std::raw::Slice as RawSlice;
use std::sync::Arc;
use std::mem;
use std::ops;

/// A vector that can be operated on concurrently via non-overlapping slices.
struct RacyCell<T>(T);
unsafe impl<T: Send> Sync for RacyCell<T> {}
///
/// Get a `ParVec` and a vector of slices via `new()`, send the slices to other threads
/// and mutate them, then get the mutated vector with `into_inner()` when finished.
pub struct ParVec<T> {
    data: Arc<RacyCell<Vec<T>>>,
}

impl<T: Send> ParVec<T> {
    /// Create a new `ParVec`, returning it and a vector of slices that can be sent
    /// to other threads and mutated concurrently.
    pub fn new(vec: Vec<T>, slices: usize) -> (ParVec<T>, Vec<ParSlice<T>>) {
        let slices = sub_slices(&vec, slice_count);
        let data = Arc::new(RacyCell(vec));

        let par_slices = slices.into_iter().map(|slice|
                ParSlice {
                    _vec: data.clone(),
                    data: slice,
                }
            ).collect();

        let par_vec = ParVec {
            data: data,
        };

        (par_vec, par_slices)
    }

    /// Take the inner `Vec` if there are no slices remaining.
    /// Returns `Err(self)` if there are still slices out there.
    pub fn into_inner_opt(self) -> Result<Vec<T>, ParVec<T>> {
        // Unwrap if we hold a unique reference
        // (we don't use weak refs so ignore those)
        if arc::strong_count(&self.data) == 1 {
            let vec_ptr: &mut Vec<T> = unsafe { mem::transmute(&*self.data) };
            Ok(mem::replace(vec_ptr, Vec::new()))
        } else {
            Err(self)
        }
    }

    /// Take the inner `Vec`, waiting until all slices have been freed.
    pub fn into_inner(mut self) -> Vec<T> {
        loop {
            match self.into_inner_opt() {
                Ok(vec) => return vec,
                Err(new_self) => self = new_self,
            }
        }
    }
}

fn sub_slices<T>(parent: &[T], slice_count: usize) -> Vec<RawSlice<T>> {
    use std::cmp;
    use std::raw::Repr;

    let mut start = 0;

    (1 .. slice_count + 1).rev().map(|curr| {
        let slice_len = (len - start) / curr;
        let end = cmp::min(start + slice_len, len);

        let slice = parent[start..end].repr();
        start += slice_len;

        slice
    }).collect()
}

/// A slice of `ParVec` that can be sent to another task for processing.
/// Automatically releases the slice on drop.
pub struct ParSlice<T: Send> {
    // Just to keep the source vector alive while the slice is,
    // since the ParVec can die asynchronously.
    _vec: Arc<RacyCell<Vec<T>>>,
    data: RawSlice<T>,
}

unsafe impl<T: Send> Send for ParSlice<T> {}

impl<T: Send> ops::Deref for ParSlice<T> {
    type Target = [T];

    fn deref<'a>(&'a self) -> &'a [T] {
        unsafe { mem::transmute(self.data) }
    }
}

impl<T: Send> ops::DerefMut for ParSlice<T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut [T] {
        unsafe { mem::transmute(self.data) }
    }
}

impl<T: Send> Debug for ParSlice<T> where T: Debug {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        write!(f, "{:?}", &*self)
    }
}

#[cfg(test)]
mod test {
    extern crate rand;
    extern crate threadpool;
    extern crate test;

    use super::ParVec;

    use std::mem;

    use self::rand::{thread_rng, Rng};
    use self::test::Bencher;
    use self::threadpool::ThreadPool;

    const TEST_SLICES: usize = 8;
    const TEST_MAX: u32 = 1000;

    #[test]
    fn test_unwrap_safely() {
        let (vec, slices) = ParVec::new([5u32; TEST_MAX as usize].to_vec(), TEST_SLICES);
        mem::drop(slices);

        let vec = vec.into_inner();

        assert_eq!(&*vec, &[5u32; TEST_MAX as usize][..]);
    }

    #[test]
    fn test_slices() {
        let (_, slices) = ParVec::new((1u32 .. TEST_MAX).collect(), TEST_SLICES);

        assert_eq!(slices.len(), TEST_SLICES);
    }

    #[bench]
    fn seq_prime_factors_1000(b: &mut Bencher) {
        let vec: Vec<u32> = (1 .. TEST_MAX).collect();

        b.iter(|| {
            let _: Vec<(u32, Vec<u32>)> = vec.iter()
                .map(|&x| (x, get_prime_factors(x)))
                .collect();
        });
    }

    #[bench]
    fn par_prime_factors_1000(b: &mut Bencher) {
        let mut rng = thread_rng();
        let pool = ThreadPool::new(TEST_SLICES);

        b.iter(|| {
            let mut vec: Vec<(u32, Vec<u32>)> = (1 .. TEST_MAX)
                .map(|x| (x, Vec::new())).collect();

            // Shuffle so each thread gets an even distribution of work.
            // Otherwise, the lower threads will quit early.
            rng.shuffle(&mut *vec);

            let (par_vec, par_slices) = ParVec::new(vec, TEST_SLICES);

            for mut slice in par_slices.into_iter() {
                pool.execute(move ||
                    for pair in slice.iter_mut() {
                        let (x, ref mut x_primes) = *pair;
                        *x_primes = get_prime_factors(x);
                    }
                );
            }

            let mut vec = par_vec.into_inner();
            // Sort so they're in the same order as sequential.
            vec.sort();
        });
    }

    fn get_prime_factors(x: u32) -> Vec<u32> {
        (1 .. x).filter(|&y| x % y == 0 && is_prime(y)).collect()
    }

    fn is_prime(x: u32) -> bool {
        if x < 3 { return true; }

        if x & 1 == 0 { return false; }

        for i in (3 .. x).step_by(2) {
            if x % i == 0 { return false; }
        }

        true
    }

}

<|endoftext|>