<commit_before>//! A small library which provides convenient, non-panicking error handling for small CLI scripts.
#![deny(missing_docs)]
#![deny(unused)]

use std::fmt::{Display, Formatter, Result as FmtResult};
use std::error::Error as StdError;
use std::path::Path;
use std::env;
use std::io::{self, Write};
use std::process;
use std::borrow::Cow;

/// A minimalist error type to use in CLI scripts: it wraps an arbitrary cause which implements
/// `std::error::Error` and a description for the `Display` implementation.
#[derive(Debug)]
pub struct Error {
    description: Option<Cow<'static, str>>,
    cause: Option<Box<StdError>>,
}

impl Error {
    /// Creates a new `Error` with a description and a cause.
    ///
    /// In most cases you'll want to use the convenient `DescribeErr` trait or the `ctry`
    /// and `ccheck` macros.
    ///
    /// With a `&'static str`:
    ///
    /// ```
    ///    # use clierr::Error;
    ///    # let some_error = Error::with_description("x");
    /// Error::new("oh no!", some_error);
    /// ```
    ///
    /// With a `String`:
    ///
    /// ```
    ///    # use clierr::Error;
    ///    # let some_error = Error::with_description("x");
    ///    # let filename = "file.txt";
    /// Error::new(format!("should not have tried to open '{}'!", filename), some_error);
    /// ```
    pub fn new<S, E>(description: S, cause: E) -> Error
        where S: Into<Cow<'static, str>>,
              E: StdError + 'static
    {
        Error {
            description: Some(description.into()),
            cause: Some(Box::new(cause)),
        }
    }

    /// Creates a new error with a descrption but no cause. Useful for validation specific
    /// errors where there's no underlying error (e.g. CLI timeout argument must be
    /// greater than zero).
    pub fn with_description<S: Into<Cow<'static, str>>>(description: S) -> Error {
        Error {
            description: Some(description.into()),
            cause: None,
        }
    }

    /// Creates a new error with a cause, but no description. The `Display` implementation
    /// forwards to that of `cause` in this case.
    ///
    /// In most cases you'll want to use the convenient `DescribeErr` trait or the `ctry`
    /// and `ccheck` macros instead.
    pub fn caused_by<E: StdError + 'static>(cause: E) -> Error {
        Error {
            description: None,
            cause: Some(Box::new(cause)),
        }
    }
}

/// A trait which enables adding a description to any `Result` by wrapping its error type in an
/// `Error`
///
/// An implementation is provided for `Result<S, E: std::errror::Error` and it's not really meant to
/// be implemented for anything else (unless you're using some kind of custom `Result` type).
pub trait DescribeErr: Sized {
    /// The result of describing the `Result`'s error.
    type Described;

    /// Wraps the error contained by `Self` in an `Error` with the given description.
    fn describe_err<D>(self, description: D) -> Self::Described where D: Into<Cow<'static, str>>;

    /// Same as `describe_err`, but defer the construction of the description until it's actually
    /// needed (i.e. only in the error case for a `Result`).
    fn describe_err_with<F, D>(self, with: F) -> Self::Described
        where F: FnOnce() -> D,
              D: Into<Cow<'static, str>>;
}

impl<S, E: StdError + 'static> DescribeErr for Result<S, E> {
    type Described = Result<S, Error>;

    fn describe_err<D: Into<Cow<'static, str>>>(self, description: D) -> Result<S, Error> {
        self.map_err(|cause| Error::new(description, cause))
    }

    fn describe_err_with<F, D>(self, with: F) -> Result<S, Error>
        where F: FnOnce() -> D,
              D: Into<Cow<'static, str>>
    {
        self.map_err(|cause| Error::new(with(), cause))
    }
}

impl Display for Error {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        if let Some(description) = self.description.as_ref() {
            write!(fmt, "{}", description)
        } else if let Some(cause) = self.cause() {
            write!(fmt, "{}", cause)
        } else {
            write!(fmt, "<unknown error>")
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        if let Some(description) = self.description.as_ref() {
            description
        } else if let Some(cause) = self.cause() {
            cause.description()
        } else {
            ""
        }
    }

    fn cause(&self) -> Option<&StdError> {
        self.cause.as_ref().map(|e| &**e)
    }
}

const MAX_CAUSE_RECURSION: usize = 32;

fn print_cause(prefix: &str, error: &StdError, max_recursion: usize) {
    if max_recursion == 0 {
        // We've recursed too many times; don't want to overflow so bail here. Ignore any errors.
        let _ = writeln!(io::stderr(), "{}:    ...", prefix);
    } else if let Some(cause) = error.cause() {
        // Display the current cause, and recurse if (a) the current cause is caused by another
        // error and (b) the write to stderr didn't fail the first time.
        if writeln!(io::stderr(), "{}:    caused by: {}", prefix, cause).is_err() {
            return;
        }

        // Hopefully tail recursive, but not a big deal if not.
        print_cause(prefix, cause, max_recursion - 1);
    }
}

fn run_impl<E, F>(main: F) -> i32
    where F: FnOnce() -> Result<(), E>,
          E: StdError
{
    if let Err(error) = main() {
        let argv0 = env::args().next();
        let program_name = argv0.as_ref()
                                .and_then(|s| Path::new(s).file_name())
                                .map(|os| os.to_string_lossy());
        let prefix = program_name.as_ref().map(|s| &**s).unwrap_or("<unknown>");

        if writeln!(io::stderr(), "{}: {}", prefix, error).is_ok() {
            print_cause(prefix, &error, MAX_CAUSE_RECURSION);
        }
        1
    } else {
        0
    }
}

/// Runs a `Result`-returning function and exits the process with 0 if successful.
///
/// If `main` returns an error, it displays it (and all its causes recursively) to `stderr` and
/// exists the process with 1.
///
/// Example:
///
/// ```norust
///     use clierr::Error;
///
///     fn foo() -> bool { false }
///
///     fn run() -> Result<(), Error> {
///         if foo() {
///             Ok(())
///         } else {
///             Error::with_description("couldn't foo!")
///         }
///     }
///
///     fn main() {
///         // Any vars defined here won't have their destructors run, so better keep `main()`
///         // dumb.
///         run_and_exit(run)
///     }
/// ```
pub fn run_and_exit<E, F>(main: F) -> !
    where F: FnOnce() -> Result<(), E>,
          E: StdError
{
    process::exit(run_impl(main))
}

/// Like `try!`, but in the error case the error is wrapped in an `Error` with a given description
/// (which can be specified using `format_args!` syntax).
///
/// Example:
///
/// ```norust
///     ctry!(File::open(filename), "could not open output file {}", filename)
/// ```
///
/// Note: If you don't like macros, the `DescribeErr` trait already cuts on a lot of verbosity.
macro_rules! ctry {
    ($e:expr, $fmt:expr) => {{
        use $crate::DescribeErr;
        try!($e.describe_err_with(|| $fmt))
    }};
    ($e:expr, $fmt:expr, $($arg:tt)*) => {{
        use $crate::DescribeErr;
        try!($e.describe_err_with(|| format!($fmt, $($arg)*)))
    }}
}

/// Like `assert!` but instead of panicking it early-returns an `Error` with a given description
/// (which can be specified using `format_args!` syntax).
///
/// Example:
///
/// ```norust
///     ccheck!(value(key) == 42, "value of {} was not 42 ({})", key, value(key))
/// ```
///
/// Note: If you don't like macros, the `DescribeErr` trait already cuts on a lot of verbosity.
macro_rules! ccheck {
    ($e:expr, $fmt:expr) => {
        if !($e) {
            return Err(Error::with_description($fmt)).into();
        }
    };
    ($e:expr, $fmt:expr, $($arg:tt)*) => {
        if !($e) {
            return Err(Error::with_description(format!($fmt, $($arg)*))).into();
        }
    }
}

#[cfg(test)]
mod test {
    use super::{Error, DescribeErr, run_impl};
    use std::error::Error as StdError;
    use std::cell::Cell;

    fn ok() -> Result<(), Error> {
        Ok(())
    }

    fn err() -> Result<(), Error> {
        Err(Error::with_description("test"))
    }

    #[test]
    fn error() {
        let with_static = Error::new("test", Error::with_description("cause"));
        let with_owned = Error::new("test2".to_owned(),
                                    Error::caused_by(Error::with_description("cause2")));

        assert_eq!(&format!("{}", with_static), "test");
        assert_eq!(&format!("{}", with_owned), "test2");
        assert_eq!(with_static.description(), "test");
        assert_eq!(with_owned.description(), "test2");

        assert_eq!(with_static.cause().map(|c| c.description()), Some("cause"));
        assert!(with_static.cause().unwrap().cause().is_none());

        assert_eq!(with_owned.cause().map(|c| c.description()), Some("cause2"));
        assert!(with_owned.cause().unwrap().cause().unwrap().cause().is_none());
        assert_eq!(with_owned.cause().map(|c| format!("{}", c)),
                   Some("cause2".to_owned()));
        assert_eq!(with_owned.cause().and_then(|c| c.cause()).map(|c| c.description()),
                   Some("cause2"));
    }

    #[test]
    fn describe_err() {
        let counter = Cell::new(0);
        let inc = || {
            counter.set(counter.get() + 1);
            "wrapper"
        };

        assert!(ok().describe_err("wrapper").is_ok());
        assert!(ok().describe_err_with(&inc).is_ok());
        assert_eq!(counter.get(), 0);

        let described = err().describe_err("wrapper");
        match described {
            Err(error) => {
                assert_eq!(error.description(), "wrapper");
                assert_eq!(error.cause().map(|c| c.description()), Some("test"));
            }
            Ok(()) => panic!("failed: {:?}", described),
        }

        let described = err().describe_err_with(&inc);
        assert_eq!(counter.get(), 1);
        match described {
            Err(error) => {
                assert_eq!(error.description(), "wrapper");
                assert_eq!(error.cause().map(|c| c.description()), Some("test"));
            }
            Ok(()) => panic!("failed: {:?}", described),
        }
    }

    #[test]
    fn ctry_ok() {
        fn foo() -> Result<u32, Error> {
            let _ = ctry!(ok(), "oh no!");
            Ok(42)
        }
        assert_eq!(foo().unwrap(), 42);
    }

    #[test]
    fn ctry_err() {
        fn foo() -> Result<u32, Error> {
            let _ = ctry!(err(), "help {}", "us");
            Ok(42)
        }
        match foo() {
            Err(e) => {
                assert_eq!(e.description(), "help us");
                assert_eq!(e.cause().unwrap().description(), "test");
            }
            Ok(x) => panic!("failed: {:?}", x),
        }
    }

    #[test]
    fn ccheck_ok() {
        fn foo() -> Result<u32, Error> {
            ccheck!(true, "oh no!");
            Ok(42)
        }
        assert_eq!(foo().unwrap(), 42);
    }

    #[test]
    fn ccheck_err() {
        fn foo() -> Result<u32, Error> {
            ccheck!(false, "help {}", "us");
            Ok(42)
        }
        match foo() {
            Err(e) => {
                assert_eq!(e.description(), "help us");
                assert!(e.cause().is_none());
            }
            Ok(x) => panic!("failed: {:?}", x),
        }
    }

    #[test]
    fn run_returns_zero_for_success() {
        assert_eq!(run_impl(ok), 0);
    }

    #[test]
    fn run_returns_one_for_error() {
        assert_eq!(run_impl(err), 1);
    }
}
<commit_msg>Marked macros with macro_export. D`oh<commit_after>//! A small library which provides convenient, non-panicking error handling for small CLI scripts.
#![deny(missing_docs)]
#![deny(unused)]

use std::fmt::{Display, Formatter, Result as FmtResult};
use std::error::Error as StdError;
use std::path::Path;
use std::env;
use std::io::{self, Write};
use std::process;
use std::borrow::Cow;

/// A minimalist error type to use in CLI scripts: it wraps an arbitrary cause which implements
/// `std::error::Error` and a description for the `Display` implementation.
#[derive(Debug)]
pub struct Error {
    description: Option<Cow<'static, str>>,
    cause: Option<Box<StdError>>,
}

impl Error {
    /// Creates a new `Error` with a description and a cause.
    ///
    /// In most cases you'll want to use the convenient `DescribeErr` trait or the `ctry`
    /// and `ccheck` macros.
    ///
    /// With a `&'static str`:
    ///
    /// ```
    ///    # use clierr::Error;
    ///    # let some_error = Error::with_description("x");
    /// Error::new("oh no!", some_error);
    /// ```
    ///
    /// With a `String`:
    ///
    /// ```
    ///    # use clierr::Error;
    ///    # let some_error = Error::with_description("x");
    ///    # let filename = "file.txt";
    /// Error::new(format!("should not have tried to open '{}'!", filename), some_error);
    /// ```
    pub fn new<S, E>(description: S, cause: E) -> Error
        where S: Into<Cow<'static, str>>,
              E: StdError + 'static
    {
        Error {
            description: Some(description.into()),
            cause: Some(Box::new(cause)),
        }
    }

    /// Creates a new error with a descrption but no cause. Useful for validation specific
    /// errors where there's no underlying error (e.g. CLI timeout argument must be
    /// greater than zero).
    pub fn with_description<S: Into<Cow<'static, str>>>(description: S) -> Error {
        Error {
            description: Some(description.into()),
            cause: None,
        }
    }

    /// Creates a new error with a cause, but no description. The `Display` implementation
    /// forwards to that of `cause` in this case.
    ///
    /// In most cases you'll want to use the convenient `DescribeErr` trait or the `ctry`
    /// and `ccheck` macros instead.
    pub fn caused_by<E: StdError + 'static>(cause: E) -> Error {
        Error {
            description: None,
            cause: Some(Box::new(cause)),
        }
    }
}

/// A trait which enables adding a description to any `Result` by wrapping its error type in an
/// `Error`
///
/// An implementation is provided for `Result<S, E: std::errror::Error` and it's not really meant to
/// be implemented for anything else (unless you're using some kind of custom `Result` type).
pub trait DescribeErr: Sized {
    /// The result of describing the `Result`'s error.
    type Described;

    /// Wraps the error contained by `Self` in an `Error` with the given description.
    fn describe_err<D>(self, description: D) -> Self::Described where D: Into<Cow<'static, str>>;

    /// Same as `describe_err`, but defer the construction of the description until it's actually
    /// needed (i.e. only in the error case for a `Result`).
    fn describe_err_with<F, D>(self, with: F) -> Self::Described
        where F: FnOnce() -> D,
              D: Into<Cow<'static, str>>;
}

impl<S, E: StdError + 'static> DescribeErr for Result<S, E> {
    type Described = Result<S, Error>;

    fn describe_err<D: Into<Cow<'static, str>>>(self, description: D) -> Result<S, Error> {
        self.map_err(|cause| Error::new(description, cause))
    }

    fn describe_err_with<F, D>(self, with: F) -> Result<S, Error>
        where F: FnOnce() -> D,
              D: Into<Cow<'static, str>>
    {
        self.map_err(|cause| Error::new(with(), cause))
    }
}

impl Display for Error {
    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
        if let Some(description) = self.description.as_ref() {
            write!(fmt, "{}", description)
        } else if let Some(cause) = self.cause() {
            write!(fmt, "{}", cause)
        } else {
            write!(fmt, "<unknown error>")
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        if let Some(description) = self.description.as_ref() {
            description
        } else if let Some(cause) = self.cause() {
            cause.description()
        } else {
            ""
        }
    }

    fn cause(&self) -> Option<&StdError> {
        self.cause.as_ref().map(|e| &**e)
    }
}

const MAX_CAUSE_RECURSION: usize = 32;

fn print_cause(prefix: &str, error: &StdError, max_recursion: usize) {
    if max_recursion == 0 {
        // We've recursed too many times; don't want to overflow so bail here. Ignore any errors.
        let _ = writeln!(io::stderr(), "{}:    ...", prefix);
    } else if let Some(cause) = error.cause() {
        // Display the current cause, and recurse if (a) the current cause is caused by another
        // error and (b) the write to stderr didn't fail the first time.
        if writeln!(io::stderr(), "{}:    caused by: {}", prefix, cause).is_err() {
            return;
        }

        // Hopefully tail recursive, but not a big deal if not.
        print_cause(prefix, cause, max_recursion - 1);
    }
}

fn run_impl<E, F>(main: F) -> i32
    where F: FnOnce() -> Result<(), E>,
          E: StdError
{
    if let Err(error) = main() {
        let argv0 = env::args().next();
        let program_name = argv0.as_ref()
                                .and_then(|s| Path::new(s).file_name())
                                .map(|os| os.to_string_lossy());
        let prefix = program_name.as_ref().map(|s| &**s).unwrap_or("<unknown>");

        if writeln!(io::stderr(), "{}: {}", prefix, error).is_ok() {
            print_cause(prefix, &error, MAX_CAUSE_RECURSION);
        }
        1
    } else {
        0
    }
}

/// Runs a `Result`-returning function and exits the process with 0 if successful.
///
/// If `main` returns an error, it displays it (and all its causes recursively) to `stderr` and
/// exists the process with 1.
///
/// Example:
///
/// ```norust
///     use clierr::Error;
///
///     fn foo() -> bool { false }
///
///     fn run() -> Result<(), Error> {
///         if foo() {
///             Ok(())
///         } else {
///             Error::with_description("couldn't foo!")
///         }
///     }
///
///     fn main() {
///         // Any vars defined here won't have their destructors run, so better keep `main()`
///         // dumb.
///         run_and_exit(run)
///     }
/// ```
pub fn run_and_exit<E, F>(main: F) -> !
    where F: FnOnce() -> Result<(), E>,
          E: StdError
{
    process::exit(run_impl(main))
}

/// Like `try!`, but in the error case the error is wrapped in an `Error` with a given description
/// (which can be specified using `format_args!` syntax).
///
/// Example:
///
/// ```norust
///     ctry!(File::open(filename), "could not open output file {}", filename)
/// ```
///
/// Note: If you don't like macros, the `DescribeErr` trait already cuts on a lot of verbosity.
#[macro_export]
macro_rules! ctry {
    ($e:expr, $fmt:expr) => {{
        use $crate::DescribeErr;
        try!($e.describe_err_with(|| $fmt))
    }};
    ($e:expr, $fmt:expr, $($arg:tt)*) => {{
        use $crate::DescribeErr;
        try!($e.describe_err_with(|| format!($fmt, $($arg)*)))
    }}
}

/// Like `assert!` but instead of panicking it early-returns an `Error` with a given description
/// (which can be specified using `format_args!` syntax).
///
/// Example:
///
/// ```norust
///     ccheck!(value(key) == 42, "value of {} was not 42 ({})", key, value(key))
/// ```
///
/// Note: If you don't like macros, the `DescribeErr` trait already cuts on a lot of verbosity.
#[macro_export]
macro_rules! ccheck {
    ($e:expr, $fmt:expr) => {
        if !($e) {
            return Err(Error::with_description($fmt)).into();
        }
    };
    ($e:expr, $fmt:expr, $($arg:tt)*) => {
        if !($e) {
            return Err(Error::with_description(format!($fmt, $($arg)*))).into();
        }
    }
}

#[cfg(test)]
mod test {
    use super::{Error, DescribeErr, run_impl};
    use std::error::Error as StdError;
    use std::cell::Cell;

    fn ok() -> Result<(), Error> {
        Ok(())
    }

    fn err() -> Result<(), Error> {
        Err(Error::with_description("test"))
    }

    #[test]
    fn error() {
        let with_static = Error::new("test", Error::with_description("cause"));
        let with_owned = Error::new("test2".to_owned(),
                                    Error::caused_by(Error::with_description("cause2")));

        assert_eq!(&format!("{}", with_static), "test");
        assert_eq!(&format!("{}", with_owned), "test2");
        assert_eq!(with_static.description(), "test");
        assert_eq!(with_owned.description(), "test2");

        assert_eq!(with_static.cause().map(|c| c.description()), Some("cause"));
        assert!(with_static.cause().unwrap().cause().is_none());

        assert_eq!(with_owned.cause().map(|c| c.description()), Some("cause2"));
        assert!(with_owned.cause().unwrap().cause().unwrap().cause().is_none());
        assert_eq!(with_owned.cause().map(|c| format!("{}", c)),
                   Some("cause2".to_owned()));
        assert_eq!(with_owned.cause().and_then(|c| c.cause()).map(|c| c.description()),
                   Some("cause2"));
    }

    #[test]
    fn describe_err() {
        let counter = Cell::new(0);
        let inc = || {
            counter.set(counter.get() + 1);
            "wrapper"
        };

        assert!(ok().describe_err("wrapper").is_ok());
        assert!(ok().describe_err_with(&inc).is_ok());
        assert_eq!(counter.get(), 0);

        let described = err().describe_err("wrapper");
        match described {
            Err(error) => {
                assert_eq!(error.description(), "wrapper");
                assert_eq!(error.cause().map(|c| c.description()), Some("test"));
            }
            Ok(()) => panic!("failed: {:?}", described),
        }

        let described = err().describe_err_with(&inc);
        assert_eq!(counter.get(), 1);
        match described {
            Err(error) => {
                assert_eq!(error.description(), "wrapper");
                assert_eq!(error.cause().map(|c| c.description()), Some("test"));
            }
            Ok(()) => panic!("failed: {:?}", described),
        }
    }

    #[test]
    fn ctry_ok() {
        fn foo() -> Result<u32, Error> {
            let _ = ctry!(ok(), "oh no!");
            Ok(42)
        }
        assert_eq!(foo().unwrap(), 42);
    }

    #[test]
    fn ctry_err() {
        fn foo() -> Result<u32, Error> {
            let _ = ctry!(err(), "help {}", "us");
            Ok(42)
        }
        match foo() {
            Err(e) => {
                assert_eq!(e.description(), "help us");
                assert_eq!(e.cause().unwrap().description(), "test");
            }
            Ok(x) => panic!("failed: {:?}", x),
        }
    }

    #[test]
    fn ccheck_ok() {
        fn foo() -> Result<u32, Error> {
            ccheck!(true, "oh no!");
            Ok(42)
        }
        assert_eq!(foo().unwrap(), 42);
    }

    #[test]
    fn ccheck_err() {
        fn foo() -> Result<u32, Error> {
            ccheck!(false, "help {}", "us");
            Ok(42)
        }
        match foo() {
            Err(e) => {
                assert_eq!(e.description(), "help us");
                assert!(e.cause().is_none());
            }
            Ok(x) => panic!("failed: {:?}", x),
        }
    }

    #[test]
    fn run_returns_zero_for_success() {
        assert_eq!(run_impl(ok), 0);
    }

    #[test]
    fn run_returns_one_for_error() {
        assert_eq!(run_impl(err), 1);
    }
}
<|endoftext|>


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

extern crate libc;

/// returns true if this is a tty
#[cfg(unix)]
pub fn is() -> bool {
  let r = unsafe { libc::isatty(libc::STDOUT_FILENO) };
  r != 0
}

/// returns true if this is a tty
#[cfg(windows)]
pub fn is() -> bool {
    extern crate kernel32;
    extern crate winapi;
    use std::ptr;
    let handle: winapi::HANDLE = unsafe {
        kernel32::CreateFileA(
            b"CONOUT$\0".as_ptr() as *const i8,
            winapi::GENERIC_READ | winapi::GENERIC_WRITE,
            winapi::FILE_SHARE_WRITE,
            ptr::null_mut(),
            winapi::OPEN_EXISTING,
            0,
            ptr::null_mut(),
            )
    };
    if handle == winapi::INVALID_HANDLE_VALUE {
        println!("handle was invalid");
    }
    let mut out = 0;
    unsafe { kernel32::GetConsoleMode(handle, &mut out) != 0 }
}

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

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

    #[test]
    fn is_test() {
        assert!(is())
    }
}
<commit_msg>apply rustfmt<commit_after>//! atty is a simple utility that answers one question
//! > is this a tty?
//!
//! usage is just as simple
//!
//! ```
//! if atty::is() {
//!   println!("i'm a tty")
//! }
//! ```
//!
//! ```
//! if atty::isnt() {
//!   println!("i'm not a tty")
//! }
//! ```

extern crate libc;

/// returns true if this is a tty
#[cfg(unix)]
pub fn is() -> bool {
    let r = unsafe { libc::isatty(libc::STDOUT_FILENO) };
    r != 0
}

/// returns true if this is a tty
#[cfg(windows)]
pub fn is() -> bool {
    extern crate kernel32;
    extern crate winapi;
    use std::ptr;
    let handle: winapi::HANDLE = unsafe {
        kernel32::CreateFileA(b"CONOUT$\0".as_ptr() as *const i8,
                              winapi::GENERIC_READ | winapi::GENERIC_WRITE,
                              winapi::FILE_SHARE_WRITE,
                              ptr::null_mut(),
                              winapi::OPEN_EXISTING,
                              0,
                              ptr::null_mut())
    };
    if handle == winapi::INVALID_HANDLE_VALUE {
        return false;
    }
    let mut out = 0;
    unsafe { kernel32::GetConsoleMode(handle, &mut out) != 0 }
}

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

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

    #[test]
    fn is_test() {
        assert!(is())
    }
}
<|endoftext|>


<commit_before>extern crate byteorder;
extern crate postgres;

use byteorder::{BigEndian, WriteBytesExt};
use postgres::error::Error;
use postgres::types::{Type, ToSql, SessionInfo, IsNull, ReadWithInfo};
use std::error;
use std::io::prelude::*;
use std::io::{self, Cursor};

pub trait StreamingIterator {
    type Item: ?Sized;

    fn next(&mut self) -> Option<&Self::Item>;
}

impl<'a, T: 'a+?Sized, I: Iterator<Item = &'a T>> StreamingIterator for I {
    type Item = T;

    fn next(&mut self) -> Option<&T> {
        unsafe { std::mem::transmute(Iterator::next(self)) }
    }
}

#[derive(Copy, Clone)]
enum ReadState {
    Header,
    Body(usize),
    Footer,
}

pub struct BinaryCopyReader<'a, I> {
    types: &'a [Type],
    state: ReadState,
    it: I,
    buf: Cursor<Vec<u8>>,
}

impl<'a, I> BinaryCopyReader<'a, I> where I: StreamingIterator<Item = ToSql> {
    pub fn new(types: &'a [Type], it: I) -> BinaryCopyReader<'a, I> {
        let mut buf = vec![];
        let _ = buf.write(b"PGCOPY\n\xff\r\n\0");
        let _ = buf.write_i32::<BigEndian>(0);
        let _ = buf.write_i32::<BigEndian>(0);

        BinaryCopyReader {
            types: types,
            state: ReadState::Header,
            it: it,
            buf: Cursor::new(buf),
        }
    }

    fn transition(&mut self, info: &SessionInfo) -> io::Result<()> {
        enum Op<'a> {
            Value(usize, &'a ToSql),
            Footer,
            Nothing,
        }

        self.buf.set_position(0);
        self.buf.get_mut().clear();

        let op = match (self.state, self.it.next()) {
            (ReadState::Header, Some(value)) => {
                self.state = ReadState::Body(0);
                Op::Value(0, value)
            }
            (ReadState::Body(old_idx), Some(value)) => {
                let idx = (old_idx + 1) % self.types.len();
                self.state = ReadState::Body(idx);
                Op::Value(idx, value)
            }
            (ReadState::Header, None) | (ReadState::Body(_), None) => {
                self.state = ReadState::Footer;
                Op::Footer
            }
            (ReadState::Footer, _) => Op::Nothing,
        };

        match op {
            Op::Value(idx, value) => {
                if idx == 0 {
                    let len = self.types.len();
                    let len = if len > i16::max_value() as usize {
                        let err: Box<error::Error+Sync+Send> = "value too large to transmit".into();
                        return Err(io::Error::new(io::ErrorKind::InvalidInput, Error::Conversion(err)));
                    } else {
                        len as i16
                    };
                    let _ = self.buf.write_i16::<BigEndian>(len);
                }

                let len_pos = self.buf.position();
                let _ = self.buf.write_i32::<BigEndian>(0); // space for length
                let len = match value.to_sql_checked(&self.types[idx], &mut self.buf, info) {
                    Ok(IsNull::Yes) => -1,
                    Ok(IsNull::No) => {
                        let len = self.buf.position() - 4 - len_pos;
                        if len > i32::max_value() as u64 {
                            let err: Box<error::Error+Sync+Send> = "value too large to transmit".into();
                            return Err(io::Error::new(io::ErrorKind::InvalidInput, Error::Conversion(err)));
                        } else {
                            len as i32
                        }
                    }
                    Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidInput, e)),
                };
                self.buf.set_position(len_pos);
                let _ = self.buf.write_i32::<BigEndian>(len);
            }
            Op::Footer => {
                let _ = self.buf.write_i16::<BigEndian>(-1);
            }
            Op::Nothing => {}
        }

        self.buf.set_position(0);
        Ok(())
    }
}

impl<'a, I> ReadWithInfo for BinaryCopyReader<'a, I> where I: StreamingIterator<Item = ToSql> {
    fn read_with_info(&mut self, buf: &mut [u8], info: &SessionInfo) -> io::Result<usize> {
        if self.buf.position() == self.buf.get_ref().len() as u64 {
            try!(self.transition(info));
        }
        self.buf.read(buf)
    }
}

#[cfg(test)]
mod test {
    use super::BinaryCopyReader;
    use postgres::{Connection, SslMode};
    use postgres::types::{Type, ToSql};

    #[test]
    fn basic() {
        let conn = Connection::connect("postgres://postgres@localhost", &SslMode::None).unwrap();
        conn.execute("CREATE TEMPORARY TABLE foo (id INT PRIMARY KEY, bar VARCHAR)", &[]).unwrap();

        let stmt = conn.prepare("COPY foo (id, bar) FROM STDIN BINARY").unwrap();

        let types = &[Type::Int4, Type::Varchar];
        let values: Vec<Box<ToSql>> = vec![Box::new(1i32), Box::new("foobar"),
                                           Box::new(2i32), Box::new("bizbuz")];
        let values = values.iter().map(|e| &**e);
        let mut reader = BinaryCopyReader::new(types, values);

        stmt.copy_in(&[], &mut reader).unwrap();

        let stmt = conn.prepare("SELECT id, bar FROM foo ORDER BY id").unwrap();
        assert_eq!(vec![(1i32, "foobar".to_string()), (2i32, "bizbuz".to_string())],
                   stmt.query(&[])
                        .unwrap()
                        .into_iter()
                        .map(|r| (r.get(0), r.get(1)))
                        .collect::<Vec<(i32, String)>>());
    }

    #[test]
    fn big() {
        let conn = Connection::connect("postgres://postgres@localhost", &SslMode::None).unwrap();
        conn.execute("CREATE TEMPORARY TABLE foo (id INT PRIMARY KEY, bar VARCHAR)", &[]).unwrap();

        let stmt = conn.prepare("COPY foo (id, bar) FROM STDIN BINARY").unwrap();

        let types = &[Type::Int4, Type::Varchar];
        let mut values: Vec<Box<ToSql>> = vec![];
        for i in 0..10000i32 {
            values.push(Box::new(i));
            values.push(Box::new(format!("the value for {}", i)));
        }

        let values = values.iter().map(|e| &**e);
        let mut reader = BinaryCopyReader::new(types, values);

        stmt.copy_in(&[], &mut reader).unwrap();

        let stmt = conn.prepare("SELECT id, bar FROM foo ORDER BY id").unwrap();
        let result = stmt.query(&[]).unwrap();
        assert_eq!(10000, result.len());
        for (i, row) in result.into_iter().enumerate() {
            assert_eq!(i as i32, row.get(0));
            assert_eq!(format!("the value for {}", i), row.get::<_, String>(1));
        }
    }
}
<commit_msg>A bit of cleanup and another test<commit_after>extern crate byteorder;
extern crate postgres;

use byteorder::{BigEndian, WriteBytesExt};
use postgres::error::Error;
use postgres::types::{Type, ToSql, SessionInfo, IsNull, ReadWithInfo};
use std::error;
use std::io::prelude::*;
use std::io::{self, Cursor};

pub trait StreamingIterator {
    type Item: ?Sized;

    fn next(&mut self) -> Option<&Self::Item>;
}

impl<'a, T: 'a+?Sized, I: Iterator<Item = &'a T>> StreamingIterator for I {
    type Item = T;

    fn next(&mut self) -> Option<&T> {
        unsafe { std::mem::transmute(Iterator::next(self)) }
    }
}

#[derive(Copy, Clone)]
enum ReadState {
    Header,
    Body(usize),
    Footer,
}

pub struct BinaryCopyReader<'a, I> {
    types: &'a [Type],
    state: ReadState,
    it: I,
    buf: Cursor<Vec<u8>>,
}

impl<'a, I> BinaryCopyReader<'a, I> where I: StreamingIterator<Item = ToSql> {
    pub fn new(types: &'a [Type], it: I) -> BinaryCopyReader<'a, I> {
        let mut buf = vec![];
        let _ = buf.write(b"PGCOPY\n\xff\r\n\0");
        let _ = buf.write_i32::<BigEndian>(0);
        let _ = buf.write_i32::<BigEndian>(0);

        BinaryCopyReader {
            types: types,
            state: ReadState::Header,
            it: it,
            buf: Cursor::new(buf),
        }
    }

    fn fill_buf(&mut self, info: &SessionInfo) -> io::Result<()> {
        enum Op<'a> {
            Value(usize, &'a ToSql),
            Footer,
            Nothing,
        }

        let op = match (self.state, self.it.next()) {
            (ReadState::Header, Some(value)) => {
                self.state = ReadState::Body(0);
                Op::Value(0, value)
            }
            (ReadState::Body(old_idx), Some(value)) => {
                let idx = (old_idx + 1) % self.types.len();
                self.state = ReadState::Body(idx);
                Op::Value(idx, value)
            }
            (ReadState::Header, None) | (ReadState::Body(_), None) => {
                self.state = ReadState::Footer;
                Op::Footer
            }
            (ReadState::Footer, _) => Op::Nothing,
        };

        self.buf.set_position(0);
        self.buf.get_mut().clear();

        match op {
            Op::Value(idx, value) => {
                if idx == 0 {
                    let len = self.types.len();
                    let len = if len > i16::max_value() as usize {
                        let err: Box<error::Error+Sync+Send> = "value too large to transmit".into();
                        return Err(io::Error::new(io::ErrorKind::InvalidInput, Error::Conversion(err)));
                    } else {
                        len as i16
                    };
                    let _ = self.buf.write_i16::<BigEndian>(len);
                }

                let len_pos = self.buf.position();
                let _ = self.buf.write_i32::<BigEndian>(0); // space for length
                let len = match value.to_sql_checked(&self.types[idx], &mut self.buf, info) {
                    Ok(IsNull::Yes) => -1,
                    Ok(IsNull::No) => {
                        let len = self.buf.position() - 4 - len_pos;
                        if len > i32::max_value() as u64 {
                            let err: Box<error::Error+Sync+Send> = "value too large to transmit".into();
                            return Err(io::Error::new(io::ErrorKind::InvalidInput, Error::Conversion(err)));
                        } else {
                            len as i32
                        }
                    }
                    Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidInput, e)),
                };
                self.buf.set_position(len_pos);
                let _ = self.buf.write_i32::<BigEndian>(len);
            }
            Op::Footer => {
                let _ = self.buf.write_i16::<BigEndian>(-1);
            }
            Op::Nothing => {}
        }

        self.buf.set_position(0);
        Ok(())
    }
}

impl<'a, I> ReadWithInfo for BinaryCopyReader<'a, I> where I: StreamingIterator<Item = ToSql> {
    fn read_with_info(&mut self, buf: &mut [u8], info: &SessionInfo) -> io::Result<usize> {
        if self.buf.position() == self.buf.get_ref().len() as u64 {
            try!(self.fill_buf(info));
        }
        self.buf.read(buf)
    }
}

#[cfg(test)]
mod test {
    use super::BinaryCopyReader;
    use postgres::{Connection, SslMode};
    use postgres::types::{Type, ToSql};

    #[test]
    fn basic() {
        let conn = Connection::connect("postgres://postgres@localhost", &SslMode::None).unwrap();
        conn.execute("CREATE TEMPORARY TABLE foo (id INT PRIMARY KEY, bar VARCHAR)", &[]).unwrap();

        let stmt = conn.prepare("COPY foo (id, bar) FROM STDIN BINARY").unwrap();

        let types = &[Type::Int4, Type::Varchar];
        let values: Vec<Box<ToSql>> = vec![Box::new(1i32), Box::new("foobar"),
                                           Box::new(2i32), Box::new("bizbuz")];
        let values = values.iter().map(|e| &**e);
        let mut reader = BinaryCopyReader::new(types, values);

        stmt.copy_in(&[], &mut reader).unwrap();

        let stmt = conn.prepare("SELECT id, bar FROM foo ORDER BY id").unwrap();
        assert_eq!(vec![(1i32, "foobar".to_string()), (2i32, "bizbuz".to_string())],
                   stmt.query(&[])
                        .unwrap()
                        .into_iter()
                        .map(|r| (r.get(0), r.get(1)))
                        .collect::<Vec<(i32, String)>>());
    }

    #[test]
    fn many_rows() {
        let conn = Connection::connect("postgres://postgres@localhost", &SslMode::None).unwrap();
        conn.execute("CREATE TEMPORARY TABLE foo (id INT PRIMARY KEY, bar VARCHAR)", &[]).unwrap();

        let stmt = conn.prepare("COPY foo (id, bar) FROM STDIN BINARY").unwrap();

        let types = &[Type::Int4, Type::Varchar];
        let mut values: Vec<Box<ToSql>> = vec![];
        for i in 0..10000i32 {
            values.push(Box::new(i));
            values.push(Box::new(format!("the value for {}", i)));
        }

        let values = values.iter().map(|e| &**e);
        let mut reader = BinaryCopyReader::new(types, values);

        stmt.copy_in(&[], &mut reader).unwrap();

        let stmt = conn.prepare("SELECT id, bar FROM foo ORDER BY id").unwrap();
        let result = stmt.query(&[]).unwrap();
        assert_eq!(10000, result.len());
        for (i, row) in result.into_iter().enumerate() {
            assert_eq!(i as i32, row.get(0));
            assert_eq!(format!("the value for {}", i), row.get::<_, String>(1));
        }
    }

    #[test]
    fn big_rows() {
        let conn = Connection::connect("postgres://postgres@localhost", &SslMode::None).unwrap();
        conn.execute("CREATE TEMPORARY TABLE foo (id INT PRIMARY KEY, bar BYTEA)", &[]).unwrap();

        let stmt = conn.prepare("COPY foo (id, bar) FROM STDIN BINARY").unwrap();

        let types = &[Type::Int4, Type::Bytea];
        let mut values: Vec<Box<ToSql>> = vec![];
        for i in 0..2i32 {
            values.push(Box::new(i));
            values.push(Box::new(vec![i as u8; 128 * 1024]));
        }

        let values = values.iter().map(|e| &**e);
        let mut reader = BinaryCopyReader::new(types, values);

        stmt.copy_in(&[], &mut reader).unwrap();

        let stmt = conn.prepare("SELECT id, bar FROM foo ORDER BY id").unwrap();
        let result = stmt.query(&[]).unwrap();
        assert_eq!(2, result.len());
        for (i, row) in result.into_iter().enumerate() {
            assert_eq!(i as i32, row.get(0));
            assert_eq!(vec![i as u8; 128 * 1024], row.get::<_, Vec<u8>>(1));
        }
    }
}
<|endoftext|>


<commit_before>extern crate libinspire;

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

use slog::DrainExt;

extern crate regex;
use regex::Regex;

pub struct Inspirer {
    logger: slog::Logger,
    pub inspire: libinspire::Api,
}

#[derive(Debug,PartialEq)]
pub enum Sources<'a> {
    Inspire(libinspire::RecID<'a>),
    Ads,
    Arxiv,
    None,
}

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

        Inspirer {
            logger: logger,
            // inspire: libinspire::Api::init(Some(logger)),
            inspire: libinspire::Api::init(None),
        }
    }

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

        let regex = Regex::new(r"(\\citation|\\abx@aux@cite)\{([a-zA-Z]+:\d{4}[a-z]{2,3})\}")
            .unwrap();

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

    ///  The blg2key function extracts missing references from bibtex logs
    pub fn blg2key(&self, input_data: String) -> Vec<String> {

        let regex = Regex::new(r#"(Warning--|WARN - )I didn't find a database entry for ["']([a-zA-Z]+:\d{4}[a-z]{2,3})["']"#)
            .unwrap();

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

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

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

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

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

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

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

        assert_eq!(Inspirer::init(None).aux2key(input),
                   vec!["Abramovici:1992ah", "Thorne:1992sdb"]);
    }
}
<commit_msg>Inspirer: Add methods to fetch from correct source<commit_after>extern crate libinspire;

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

use slog::DrainExt;

extern crate regex;
use regex::Regex;

pub struct Inspirer {
    logger: slog::Logger,
    pub inspire: libinspire::Api,
}

#[derive(Debug,PartialEq)]
pub enum Sources<'a> {
    Inspire(libinspire::RecID<'a>),
    Ads,
    Arxiv,
    None,
}

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

        Inspirer {
            logger: logger,
            // inspire: libinspire::Api::init(Some(logger)),
            inspire: libinspire::Api::init(None),
        }
    }

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

        let regex = Regex::new(r"(\\citation|\\abx@aux@cite)\{([a-zA-Z]+:\d{4}[a-z]{2,3})\}")
            .unwrap();

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

    ///  The blg2key function extracts missing references from bibtex logs
    pub fn blg2key(&self, input_data: String) -> Vec<String> {

        let regex = Regex::new(r#"(Warning--|WARN - )I didn't find a database entry for ["']([a-zA-Z]+:\d{4}[a-z]{2,3})["']"#)
            .unwrap();

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

    /// Fetch BibTeX entries
    pub fn bibtex(&self, key: &str) -> Option<String> {
        let key = self.classify(key);

        match key {
            Sources::Inspire(k) => {
                debug!(self.logger, "Got Inspire record"; "key" => k.id);
                self.inspire.fetch_bibtex_with_key(k)
            }
            _ => {
                // debug!(self.logger, "Unknown record source"; "key" => key);
                debug!(self.logger, "Unknown record source");
                None
            }
        }
    }

    /// Guess a likely source of BibTeX key
    ///
    /// # Examples
    /// ```
    /// extern crate inspirer;
    /// extern crate libinspire;
    /// let inspirer = inspirer::Inspirer::init(None);
    ///
    /// assert_eq!(
    ///     inspirer.classify("Randall:1999ee"),
    ///     inspirer::Sources::Inspire(libinspire::RecID::new("Randall:1999ee").unwrap())
    /// );
    /// ```
    pub fn classify<'a>(&self, s: &'a str) -> Sources<'a> {
        if libinspire::validate_recid(s) {
            debug!(self.logger, "Detected an Inspire record"; "key" => s);
            Sources::Inspire(libinspire::RecID::new(s).unwrap())
        } else {
            debug!(self.logger, "Unknown record type"; "key" => s);
            Sources::None
        }
    }
}

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

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

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

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

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

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

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


<commit_before>//! Lettre is an email library that allows creating and sending messages. It provides:
//!
//! * An easy to use email builder
//! * Pluggable email transports
//! * Unicode support
//! * Secure defaults
//! * Async support
//!
//! Lettre requires Rust 1.45 or newer.
//!
//! ## Optional features
//!
//! * **builder**: Message builder
//! * **file-transport**: Transport that writes messages into a file
//! * **file-transport-envelope**: Allow writing the envelope into a JSON file
//! * **smtp-transport**: Transport over SMTP
//! * **sendmail-transport**: Transport using the `sendmail` command
//! * **rustls-tls**: TLS support with the `rustls` crate
//! * **native-tls**: TLS support with the `native-tls` crate
//! * **tokio02**: Allow to asyncronously send emails using tokio 0.2.x
//! * **tokio02-rustls-tls**: Async TLS support with the `rustls` crate using tokio 0.2
//! * **tokio02-native-tls**: Async TLS support with the `native-tls` crate using tokio 0.2
//! * **tokio1**: Allow to asyncronously send emails using tokio 1.x
//! * **tokio1-rustls-tls**: Async TLS support with the `rustls` crate using tokio 1.x
//! * **tokio1-native-tls**: Async TLS support with the `native-tls` crate using tokio 1.x
//! * **async-std1**: Allow to asynchronously send emails using async-std 1.x
//! * NOTE: native-tls isn't supported with async-std at the moment
//! * **async-std1-rustls-tls**: Async TLS support with the `rustls` crate using async-std 1.x
//! * **r2d2**: Connection pool for SMTP transport
//! * **tracing**: Logging using the `tracing` crate
//! * **serde**: Serialization/Deserialization of entities
//! * **hostname**: Ability to try to use actual hostname in SMTP transaction

#![doc(html_root_url = "https://docs.rs/crate/lettre/0.10.0-beta.2")]
#![doc(html_favicon_url = "https://lettre.rs/favicon.ico")]
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/15113230?v=4")]
#![forbid(unsafe_code)]
#![deny(
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unstable_features,
    unused_import_braces,
    rust_2018_idioms
)]
#![cfg_attr(docsrs, feature(doc_cfg))]

pub mod address;
pub mod error;
#[cfg(any(feature = "tokio02", feature = "tokio1", feature = "async-std1"))]
mod executor;
#[cfg(feature = "builder")]
#[cfg_attr(docsrs, doc(cfg(feature = "builder")))]
pub mod message;
pub mod transport;

#[cfg(feature = "builder")]
#[macro_use]
extern crate hyperx;

#[cfg(feature = "async-std1")]
pub use self::executor::AsyncStd1Executor;
#[cfg(all(any(feature = "tokio02", feature = "tokio1", feature = "async-std1")))]
pub use self::executor::Executor;
#[cfg(feature = "tokio02")]
pub use self::executor::Tokio02Executor;
#[cfg(feature = "tokio1")]
pub use self::executor::Tokio1Executor;
#[cfg(all(any(feature = "tokio02", feature = "tokio1", feature = "async-std1")))]
#[doc(inline)]
pub use self::transport::AsyncTransport;
pub use crate::address::Address;
#[cfg(feature = "builder")]
#[doc(inline)]
pub use crate::message::Message;
#[cfg(all(
    feature = "file-transport",
    any(feature = "tokio02", feature = "tokio1", feature = "async-std1")
))]
#[doc(inline)]
pub use crate::transport::file::AsyncFileTransport;
#[cfg(feature = "file-transport")]
#[doc(inline)]
pub use crate::transport::file::FileTransport;
#[cfg(all(
    feature = "sendmail-transport",
    any(feature = "tokio02", feature = "tokio1", feature = "async-std1")
))]
#[doc(inline)]
pub use crate::transport::sendmail::AsyncSendmailTransport;
#[cfg(feature = "sendmail-transport")]
#[doc(inline)]
pub use crate::transport::sendmail::SendmailTransport;
#[cfg(all(
    feature = "smtp-transport",
    any(feature = "tokio02", feature = "tokio1")
))]
pub use crate::transport::smtp::AsyncSmtpTransport;
#[doc(inline)]
pub use crate::transport::Transport;
use crate::{address::Envelope, error::Error};

#[cfg(feature = "smtp-transport")]
pub use crate::transport::smtp::SmtpTransport;
use std::error::Error as StdError;

pub(crate) type BoxError = Box<dyn StdError + Send + Sync>;

#[cfg(test)]
#[cfg(feature = "builder")]
mod test {
    use super::*;
    use crate::message::{header, Mailbox, Mailboxes};
    use hyperx::header::Headers;
    use std::convert::TryFrom;

    #[test]
    fn envelope_from_headers() {
        let from = Mailboxes::new().with("kayo@example.com".parse().unwrap());
        let to = Mailboxes::new().with("amousset@example.com".parse().unwrap());

        let mut headers = Headers::new();
        headers.set(header::From(from));
        headers.set(header::To(to));

        assert_eq!(
            Envelope::try_from(&headers).unwrap(),
            Envelope::new(
                Some(Address::new("kayo", "example.com").unwrap()),
                vec![Address::new("amousset", "example.com").unwrap()]
            )
            .unwrap()
        );
    }

    #[test]
    fn envelope_from_headers_sender() {
        let from = Mailboxes::new().with("kayo@example.com".parse().unwrap());
        let sender = Mailbox::new(None, "kayo2@example.com".parse().unwrap());
        let to = Mailboxes::new().with("amousset@example.com".parse().unwrap());

        let mut headers = Headers::new();
        headers.set(header::From(from));
        headers.set(header::Sender(sender));
        headers.set(header::To(to));

        assert_eq!(
            Envelope::try_from(&headers).unwrap(),
            Envelope::new(
                Some(Address::new("kayo2", "example.com").unwrap()),
                vec![Address::new("amousset", "example.com").unwrap()]
            )
            .unwrap()
        );
    }

    #[test]
    fn envelope_from_headers_no_to() {
        let from = Mailboxes::new().with("kayo@example.com".parse().unwrap());
        let sender = Mailbox::new(None, "kayo2@example.com".parse().unwrap());

        let mut headers = Headers::new();
        headers.set(header::From(from));
        headers.set(header::Sender(sender));

        assert!(Envelope::try_from(&headers).is_err(),);
    }
}
<commit_msg>Fix missing re-export of AsyncSmtpTransport when using async-std1 feature (#573)<commit_after>//! Lettre is an email library that allows creating and sending messages. It provides:
//!
//! * An easy to use email builder
//! * Pluggable email transports
//! * Unicode support
//! * Secure defaults
//! * Async support
//!
//! Lettre requires Rust 1.45 or newer.
//!
//! ## Optional features
//!
//! * **builder**: Message builder
//! * **file-transport**: Transport that writes messages into a file
//! * **file-transport-envelope**: Allow writing the envelope into a JSON file
//! * **smtp-transport**: Transport over SMTP
//! * **sendmail-transport**: Transport using the `sendmail` command
//! * **rustls-tls**: TLS support with the `rustls` crate
//! * **native-tls**: TLS support with the `native-tls` crate
//! * **tokio02**: Allow to asyncronously send emails using tokio 0.2.x
//! * **tokio02-rustls-tls**: Async TLS support with the `rustls` crate using tokio 0.2
//! * **tokio02-native-tls**: Async TLS support with the `native-tls` crate using tokio 0.2
//! * **tokio1**: Allow to asyncronously send emails using tokio 1.x
//! * **tokio1-rustls-tls**: Async TLS support with the `rustls` crate using tokio 1.x
//! * **tokio1-native-tls**: Async TLS support with the `native-tls` crate using tokio 1.x
//! * **async-std1**: Allow to asynchronously send emails using async-std 1.x
//! * NOTE: native-tls isn't supported with async-std at the moment
//! * **async-std1-rustls-tls**: Async TLS support with the `rustls` crate using async-std 1.x
//! * **r2d2**: Connection pool for SMTP transport
//! * **tracing**: Logging using the `tracing` crate
//! * **serde**: Serialization/Deserialization of entities
//! * **hostname**: Ability to try to use actual hostname in SMTP transaction

#![doc(html_root_url = "https://docs.rs/crate/lettre/0.10.0-beta.2")]
#![doc(html_favicon_url = "https://lettre.rs/favicon.ico")]
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/15113230?v=4")]
#![forbid(unsafe_code)]
#![deny(
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unstable_features,
    unused_import_braces,
    rust_2018_idioms
)]
#![cfg_attr(docsrs, feature(doc_cfg))]

pub mod address;
pub mod error;
#[cfg(any(feature = "tokio02", feature = "tokio1", feature = "async-std1"))]
mod executor;
#[cfg(feature = "builder")]
#[cfg_attr(docsrs, doc(cfg(feature = "builder")))]
pub mod message;
pub mod transport;

#[cfg(feature = "builder")]
#[macro_use]
extern crate hyperx;

#[cfg(feature = "async-std1")]
pub use self::executor::AsyncStd1Executor;
#[cfg(all(any(feature = "tokio02", feature = "tokio1", feature = "async-std1")))]
pub use self::executor::Executor;
#[cfg(feature = "tokio02")]
pub use self::executor::Tokio02Executor;
#[cfg(feature = "tokio1")]
pub use self::executor::Tokio1Executor;
#[cfg(all(any(feature = "tokio02", feature = "tokio1", feature = "async-std1")))]
#[doc(inline)]
pub use self::transport::AsyncTransport;
pub use crate::address::Address;
#[cfg(feature = "builder")]
#[doc(inline)]
pub use crate::message::Message;
#[cfg(all(
    feature = "file-transport",
    any(feature = "tokio02", feature = "tokio1", feature = "async-std1")
))]
#[doc(inline)]
pub use crate::transport::file::AsyncFileTransport;
#[cfg(feature = "file-transport")]
#[doc(inline)]
pub use crate::transport::file::FileTransport;
#[cfg(all(
    feature = "sendmail-transport",
    any(feature = "tokio02", feature = "tokio1", feature = "async-std1")
))]
#[doc(inline)]
pub use crate::transport::sendmail::AsyncSendmailTransport;
#[cfg(feature = "sendmail-transport")]
#[doc(inline)]
pub use crate::transport::sendmail::SendmailTransport;
#[cfg(all(
    feature = "smtp-transport",
    any(feature = "tokio02", feature = "tokio1", feature = "async-std1")
))]
pub use crate::transport::smtp::AsyncSmtpTransport;
#[doc(inline)]
pub use crate::transport::Transport;
use crate::{address::Envelope, error::Error};

#[cfg(feature = "smtp-transport")]
pub use crate::transport::smtp::SmtpTransport;
use std::error::Error as StdError;

pub(crate) type BoxError = Box<dyn StdError + Send + Sync>;

#[cfg(test)]
#[cfg(feature = "builder")]
mod test {
    use super::*;
    use crate::message::{header, Mailbox, Mailboxes};
    use hyperx::header::Headers;
    use std::convert::TryFrom;

    #[test]
    fn envelope_from_headers() {
        let from = Mailboxes::new().with("kayo@example.com".parse().unwrap());
        let to = Mailboxes::new().with("amousset@example.com".parse().unwrap());

        let mut headers = Headers::new();
        headers.set(header::From(from));
        headers.set(header::To(to));

        assert_eq!(
            Envelope::try_from(&headers).unwrap(),
            Envelope::new(
                Some(Address::new("kayo", "example.com").unwrap()),
                vec![Address::new("amousset", "example.com").unwrap()]
            )
            .unwrap()
        );
    }

    #[test]
    fn envelope_from_headers_sender() {
        let from = Mailboxes::new().with("kayo@example.com".parse().unwrap());
        let sender = Mailbox::new(None, "kayo2@example.com".parse().unwrap());
        let to = Mailboxes::new().with("amousset@example.com".parse().unwrap());

        let mut headers = Headers::new();
        headers.set(header::From(from));
        headers.set(header::Sender(sender));
        headers.set(header::To(to));

        assert_eq!(
            Envelope::try_from(&headers).unwrap(),
            Envelope::new(
                Some(Address::new("kayo2", "example.com").unwrap()),
                vec![Address::new("amousset", "example.com").unwrap()]
            )
            .unwrap()
        );
    }

    #[test]
    fn envelope_from_headers_no_to() {
        let from = Mailboxes::new().with("kayo@example.com".parse().unwrap());
        let sender = Mailbox::new(None, "kayo2@example.com".parse().unwrap());

        let mut headers = Headers::new();
        headers.set(header::From(from));
        headers.set(header::Sender(sender));

        assert!(Envelope::try_from(&headers).is_err(),);
    }
}
<|endoftext|>


<commit_before>extern crate num;
use num::Float;

use std::f64::consts::PI;

/// Calculates the volume of the n-sphere.
pub fn sphere_volume<F: Float>(radius: F, dim: u64) -> F {
    let pi = F::from(PI)
        .expect("Casting PI should be valid.");
    let gamma = if dim % 2 == 0 {
        // This works because dim / 2 is a whole number.
        F::from(fact(dim / 2))
            .expect("Casting result of factorial should be always castable as Float.")
    } else {
        // This works because the function is gamma(1/2 + n) where n = dim / 2 + 1
        let n = dim / 2 + 1;
        let fact_2n = F::from(fact(2 * n))
            .expect("Casting result of factorial should be always castable as Float.");
        let div = F::from(4u64.pow(n as u32) * fact(n))
            .expect("Casting result of factorial should be always castable as Float.");
        (fact_2n / div) * pi.sqrt()
    };
    let dim = F::from(dim)
        .expect("u64 should be always castable as Float.");
    let half = F::one() / (F::one() + F::one());
    (pi.powf(half * dim) * radius.powf(dim)) / gamma
}

#[test]
fn volume_of_1_sphere_works() {
    for radius in (0..5000000).map(|n| n as f64 / 7000.) {
        let expected = PI * radius.powi(2);
        let actual = sphere_volume(radius, 2);
        assert!(equals(expected, actual, 0.0001, 5), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[test]
fn volume_of_2_sphere_works() {
    for radius in (0..5000000).map(|n| n as f64 / 7000.) {
        let expected = (4. / 3.) * PI * radius.powi(3);
        let actual = sphere_volume(radius, 3);
        assert!(equals(expected, actual, 0.0001, 5), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[test]
fn volume_of_3_sphere_works() {
    for radius in (0..5000000).map(|n| n as f64 / 7000.) {
        let expected = (1. / 2.) * PI.powi(2) * radius.powi(4);
        let actual = sphere_volume(radius, 4);
        assert!(equals(expected, actual, 0.0001, 5), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[cfg(test)]
fn equals(a: f64, b: f64, max_diff: f64, max_ulps_diff: i64) -> bool {
    let diff = f64::abs(a - b);
    if diff <= max_diff {
        return true;
    }
    if a.is_sign_positive() && !b.is_sign_positive() {
        return false;
    }
    let a_i64 = unsafe{::std::mem::transmute::<_, i64>(a)};
    let b_i64 = unsafe{::std::mem::transmute::<_, i64>(b)};
    let ulps_diff = i64::abs(a_i64 - b_i64);
    return ulps_diff <= max_ulps_diff;
}

#[inline]
fn fact(n: u64) -> u64 {
    //TODO: This could be made faster with better algorithm, but it's called with low values so it doesn't matter much.
    if n < 2 {
        1
    } else {
        n * fact(n - 1)
    }
}

#[test]
fn factorial_works() {
    assert_eq!(1, fact(0));
    let mut x = 1;
    for n in 1..21 {
        x *= n;
        assert_eq!(x, fact(n));
    }
}
<commit_msg>Replaced volume calculation formula with simpler one. Added surface calculation.<commit_after>extern crate num;
use num::Float;

const TAU: f64 = 2. * std::f64::consts::PI;
const LAMBDA: f64 = TAU / 4.;

/// Calculates the volume of the n-sphere.
pub fn sphere_volume<F: Float>(radius: F, n: u64) -> F {
    let pieces = cast::<F>(2.).powi(n as i32);
    let half_n = (n as f64 / 2.).floor() as i32;
    let lambda_power = cast::<F>(LAMBDA).powi(half_n);
    let double_fact = F::from(double_fact(n))
        .expect("Used too high dimensions for sphere.");
    let piece_volume = (lambda_power * radius.powi(n as i32)) / double_fact;
    F::from(pieces * piece_volume).unwrap()
}

/// Calulates the surface area of the n-sphere.
pub fn sphere_surface<F: Float>(radius: F, n: u64) -> F {
    let pieces = cast::<F>(2.).powi(n as i32);
    let half_n = (n as f64 / 2.).floor() as i32;
    let lambda_power = cast::<F>(LAMBDA).powi(half_n);
    let double_fact = F::from(double_fact(n - 2))
        .expect("Used too high dimensions for sphere.");
    let piece_volume = (lambda_power * radius.powi(n as i32 - 1)) / double_fact;
    F::from(pieces * piece_volume).unwrap()
}

#[inline]
fn cast<F: Float>(f: f64) -> F {
    F::from(f).expect("Trusted cast should succeed.")
}

#[test]
fn volume_of_1_sphere_works() {
    for radius in (0..5000000).map(|n| n as f64 / 7000.) {
        let expected = (1. / 2.) * TAU * radius.powi(2);
        let actual = sphere_volume(radius, 2);
        assert!(equals(expected, actual, 0.0001, 5), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[test]
fn volume_of_2_sphere_works() {
    for radius in (0..5000000).map(|n| n as f64 / 7000.) {
        let expected = (4. / 6.) * TAU * radius.powi(3);
        let actual = sphere_volume(radius, 3);
        assert!(equals(expected, actual, 0.0001, 5), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[test]
fn volume_of_3_sphere_works() {
    for radius in (0..5000000).map(|n| n as f64 / 7000.) {
        let expected = (1. / 8.) * TAU.powi(2) * radius.powi(4);
        let actual = sphere_volume(radius, 4);
        assert!(equals(expected, actual, 0.0001, 5), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[test]
fn surface_of_1_sphere_works() {
    for radius in (0..5000000).map(|n| n as f64 / 7000.) {
        let expected = TAU * radius;
        let actual = sphere_surface(radius, 2);
        assert!(equals(expected, actual, 0.0001, 5), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[test]
fn surface_of_2_sphere_works() {
    for radius in (0..5000000).map(|n| n as f64 / 7000.) {
        let expected = 2. * TAU * radius.powi(2);
        let actual = sphere_surface(radius, 3);
        assert!(equals(expected, actual, 0.0001, 5), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[test]
fn surface_of_3_sphere_works() {
    for radius in (0..5000000).map(|n| n as f64 / 7000.) {
        let expected = (1. / 2.) * TAU.powi(2) * radius.powi(3);
        let actual = sphere_surface(radius, 4);
        assert!(equals(expected, actual, 0.0001, 5), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[cfg(test)]
fn equals(a: f64, b: f64, max_diff: f64, max_ulps_diff: i64) -> bool {
    let diff = f64::abs(a - b);
    if diff <= max_diff {
        return true;
    }
    if a.is_sign_positive() && !b.is_sign_positive() {
        return false;
    }
    let a_i64 = unsafe{::std::mem::transmute::<_, i64>(a)};
    let b_i64 = unsafe{::std::mem::transmute::<_, i64>(b)};
    let ulps_diff = i64::abs(a_i64 - b_i64);
    return ulps_diff <= max_ulps_diff;
}

#[inline]
fn double_fact(n: u64) -> u64 {
    if n < 2 {
        1
    } else {
        n * double_fact(n - 2)
    }
}

#[test]
fn double_factorial_works() {
    assert_eq!(1, double_fact(0));
    let mut x = 1;
    for n in 1..17 {
        let n = 2 * n;
        x *= n;
        assert_eq!(x, double_fact(n));
    }
    let mut x = 1;
    for n in 0..16 {
        let n = 2 * n + 1;
        x *= n;
        assert_eq!(x, double_fact(n));
    }
}
<|endoftext|>


<commit_before>
fn ramer_douglas_peucker(v: Vec<(f32,f32)>, e: f32) -> Vec<(f32,f32)> {
  let length = v.len();
  let mut stack = vec![(0, length - 1)];
  let mut included = vec![false; length];
  let mut result: Vec<(f32,f32)> = Vec::new();

  while let Some((start_index, end_index)) =  stack.pop() {
    // println!("start = {}, end = {}", start_index, end_index);
    let mut max_distance: f32 = 0.0;
    let mut index = start_index;
    for i in start_index+1..end_index {
      let distance =
        distance_point_to_line(v[i], (v[start_index], v[end_index]));
      // println!("i = {}, distance = {}", i, distance);
      if distance > max_distance {
        max_distance = distance;
        index = i;
      }
    }
    if max_distance > e {
      stack.push((index, end_index));
      stack.push((start_index, index));
    } else {
      included[start_index] = true;
      included[end_index] = true;
    }
  }
  for i in 0..length {
    if included[i] {
      result.push(v[i]);
    }
  }
  result
}

fn distance_point_to_line(p: (f32, f32), l: ((f32, f32), (f32, f32))) -> f32 {
  if l.0 == l.1 {
    return distance_point_to_point(p, l.0);
  }
  let a = (l.0).1 - (l.1).1;
  let b = (l.1).0 - (l.0).0;
  let c = (l.0).0 * (l.1).1 - (l.1).0 * (l.0).1;
  let result = (a * p.0 + b * p.1 + c) / (a * a + b * b).sqrt();
  result.abs()
}

fn distance_point_to_point(x: (f32, f32), y: (f32, f32)) -> f32 {
  let a = y.0 - x.0;
  let b = y.1 - x.1;
  let result = (a * a + b * b).sqrt();
  result.abs()
}

#[test]
fn reduce_vector() {
  // Minimal cases:
  assert_eq!(vec![(1.0, 1.0)], ramer_douglas_peucker(vec![(1.0, 1.0)], 0.5));
  assert_eq!(vec![(1.0, 1.0), (2.0, 2.0)], ramer_douglas_peucker(vec![(1.0, 1.0), (2.0, 2.0)], 0.5));
  assert_eq!(vec![(1.0, 1.0), (3.0, 3.0)], ramer_douglas_peucker(vec![(1.0, 1.0), (2.0, 2.0), (3.0, 3.0)], 0.5));
  // Effect of varying epsilon:
  assert_eq!(vec![(0.0, 2.0), (1.0, 1.0), (3.0, 0.0), (5.0, 1.0)], ramer_douglas_peucker(vec![(0.0, 2.0), (1.0, 1.0), (3.0, 0.0), (5.0, 1.0)], 0.1));
  assert_eq!(vec![(0.0, 2.0), (3.0, 0.0), (5.0, 1.0)], ramer_douglas_peucker(vec![(0.0, 2.0), (1.0, 1.0), (3.0, 0.0), (5.0, 1.0)], 0.5));
  // Tests with vertical segments:
  assert_eq!(vec![(10.0, 35.0), (20.0, 29.0)], ramer_douglas_peucker(vec![(10.0, 35.0), (15.0, 34.0), (15.0, 30.0), (20.0, 29.0)], 10.0));
  assert_eq!(vec![(10.0, 35.0), (15.0, 34.0), (15.0, 30.0), (20.0, 29.0)], ramer_douglas_peucker(vec![(10.0, 35.0), (15.0, 34.0), (15.0, 30.0), (20.0, 29.0)], 1.0));
  // Tests with horizontal segments:
  assert_eq!(vec![(10.0, 35.0), (15.0, 35.0), (16.0, 30.0), (21.0, 30.0)], ramer_douglas_peucker(vec![(10.0, 35.0), (15.0, 35.0), (16.0, 30.0), (21.0, 30.0)], 1.0));
  assert_eq!(vec![(10.0, 35.0), (21.0, 30.0)], ramer_douglas_peucker(vec![(10.0, 35.0), (15.0, 35.0), (16.0, 30.0), (21.0, 30.0)], 10.0));
  // Tests with vertical and horizontal segments:
  assert_eq!(vec![(10.0, 30.0), (50.0, 10.0)], ramer_douglas_peucker(vec![(10.0, 30.0), (30.0, 30.0), (30.0, 10.0), (50.0, 10.0)], 10.0));
  assert_eq!(vec![(10.0, 30.0), (50.0, 10.0)], ramer_douglas_peucker(vec![(10.0, 30.0), (30.0, 30.0), (30.0, 10.0), (50.0, 10.0)], 15.0));
  // A more complex curve:
  assert_eq!(vec![(3.5, 21.25), (23.2, 3.1), (54.6, 18.15), (71.5, 9.7), (101.3, 21.1)], ramer_douglas_peucker(vec![(3.5, 21.25), (7.3, 12.0), (23.2, 3.1), (37.2, 12.07), (54.6, 18.15), (62.2, 16.45), (71.5, 9.7), (101.3, 21.1)], 5.0));
  assert_eq!(vec![(0.0, 0.0), (0.5, 0.5), (1.25, -0.25), (1.5, 0.5)], ramer_douglas_peucker(vec![(0.0,0.0),(0.5,0.5),(1.0,0.0),(1.25,-0.25),(1.5,0.5)], 0.25));
  // Start point == end point
  assert_eq!(vec![(0.0, 0.0), (2.0, 0.0), (2.0, 2.0), (0.0, 2.0), (0.0, 0.0)],
    ramer_douglas_peucker(
      vec![(0.0,0.0),(1.0,0.0),(2.0,0.0),(2.0,1.0),(2.0,2.0),(1.0,2.0),(0.0,2.0),(0.0,1.0),(0.0, 0.0)],
      1.0));
}

#[test]
fn calculate_point_to_line_distance() {
  assert!((distance_point_to_line((3.0, 2.0), ((-2.0, 0.0),(0.0, 2.0)))
    - 2.12132).abs() < 0.00001);
  assert!(distance_point_to_line((0.0, 0.0), ((-1.0, 0.0),(1.0, 0.0))).abs() < 0.00001);
}

#[test]
fn calculate_point_to_point_distance() {
  assert!((distance_point_to_point((3.0, 2.0), (5.0, -1.0))
    - 3.60555).abs() < 0.00001);
  assert!(distance_point_to_point((3.0, 2.0), (3.0, 2.0)).abs() < 0.00001);
}
<commit_msg>remove unnecessary array<commit_after>#![allow(dead_code)]
#[allow(non_camel_case_types)]
type float = f32;
fn ramer_douglas_peucker(v: Vec<(float, float)>, epsilon: float) -> Vec<(float, float)> {
    let length = v.len();
    let mut stack = vec![(0, length - 1)];
    let mut result = Vec::new();
    let mut last_index = -1;

    while let Some((start_index, end_index)) =  stack.pop() {
        // println!("start = {}, end = {}", start_index, end_index);
        let mut max_distance = 0.0 as float;
        let mut index = start_index;
        for i in start_index+1..end_index {
            let distance =
            distance_point_to_line(v[i], (v[start_index], v[end_index]));
            // println!("i = {}, distance = {}", i, distance);
            if distance > max_distance {
                max_distance = distance;
                index = i;
            }
        }
        if max_distance > epsilon {
            stack.push((index, end_index));
            stack.push((start_index, index));
        } else {
            if last_index != start_index {
                result.push(v[start_index]);
                last_index = start_index;
            }
            if last_index != end_index {
                result.push(v[end_index]);
                last_index = end_index;
            }
        }
    }
    result
}

fn distance_point_to_line(p: (float, float), l: ((float, float), (float, float))) -> float {
    if l.0 == l.1 {
        return distance_point_to_point(p, l.0);
    }
    let a = (l.0).1 - (l.1).1;
    let b = (l.1).0 - (l.0).0;
    let c = (l.0).0 * (l.1).1 - (l.1).0 * (l.0).1;
    let result = (a * p.0 + b * p.1 + c) / (a * a + b * b).sqrt();
    result.abs()
}

fn distance_point_to_point(x: (float, float), y: (float, float)) -> float {
    let a = y.0 - x.0;
    let b = y.1 - x.1;
    let result = (a * a + b * b).sqrt();
    result.abs()
}

#[test]
fn reduce_vector() {
    // Minimal cases:
    assert_eq!(vec![(1.0, 1.0)], ramer_douglas_peucker(vec![(1.0, 1.0)], 0.5));
    assert_eq!(vec![(1.0, 1.0), (2.0, 2.0)], ramer_douglas_peucker(vec![(1.0, 1.0), (2.0, 2.0)], 0.5));
    assert_eq!(vec![(1.0, 1.0), (3.0, 3.0)], ramer_douglas_peucker(vec![(1.0, 1.0), (2.0, 2.0), (3.0, 3.0)], 0.5));
    // Effect of varying epsilon:
    assert_eq!(vec![(0.0, 2.0), (1.0, 1.0), (3.0, 0.0), (5.0, 1.0)], ramer_douglas_peucker(vec![(0.0, 2.0), (1.0, 1.0), (3.0, 0.0), (5.0, 1.0)], 0.1));
    assert_eq!(vec![(0.0, 2.0), (3.0, 0.0), (5.0, 1.0)], ramer_douglas_peucker(vec![(0.0, 2.0), (1.0, 1.0), (3.0, 0.0), (5.0, 1.0)], 0.5));
    // Tests with vertical segments:
    assert_eq!(vec![(10.0, 35.0), (20.0, 29.0)], ramer_douglas_peucker(vec![(10.0, 35.0), (15.0, 34.0), (15.0, 30.0), (20.0, 29.0)], 10.0));
    assert_eq!(vec![(10.0, 35.0), (15.0, 34.0), (15.0, 30.0), (20.0, 29.0)], ramer_douglas_peucker(vec![(10.0, 35.0), (15.0, 34.0), (15.0, 30.0), (20.0, 29.0)], 1.0));
    // Tests with horizontal segments:
    assert_eq!(vec![(10.0, 35.0), (15.0, 35.0), (16.0, 30.0), (21.0, 30.0)], ramer_douglas_peucker(vec![(10.0, 35.0), (15.0, 35.0), (16.0, 30.0), (21.0, 30.0)], 1.0));
    assert_eq!(vec![(10.0, 35.0), (21.0, 30.0)], ramer_douglas_peucker(vec![(10.0, 35.0), (15.0, 35.0), (16.0, 30.0), (21.0, 30.0)], 10.0));
    // Tests with vertical and horizontal segments:
    assert_eq!(vec![(10.0, 30.0), (50.0, 10.0)], ramer_douglas_peucker(vec![(10.0, 30.0), (30.0, 30.0), (30.0, 10.0), (50.0, 10.0)], 10.0));
    assert_eq!(vec![(10.0, 30.0), (50.0, 10.0)], ramer_douglas_peucker(vec![(10.0, 30.0), (30.0, 30.0), (30.0, 10.0), (50.0, 10.0)], 15.0));
    // A more complex curve:
    assert_eq!(vec![(3.5, 21.25), (23.2, 3.1), (54.6, 18.15), (71.5, 9.7), (101.3, 21.1)], ramer_douglas_peucker(vec![(3.5, 21.25), (7.3, 12.0), (23.2, 3.1), (37.2, 12.07), (54.6, 18.15), (62.2, 16.45), (71.5, 9.7), (101.3, 21.1)], 5.0));
    assert_eq!(vec![(0.0, 0.0), (0.5, 0.5), (1.25, -0.25), (1.5, 0.5)], ramer_douglas_peucker(vec![(0.0,0.0),(0.5,0.5),(1.0,0.0),(1.25,-0.25),(1.5,0.5)], 0.25));
    // Start point == end point
    assert_eq!(vec![(0.0, 0.0), (2.0, 0.0), (2.0, 2.0), (0.0, 2.0), (0.0, 0.0)],ramer_douglas_peucker(vec![(0.0,0.0),(1.0,0.0),(2.0,0.0),(2.0,1.0),(2.0,2.0),(1.0,2.0),(0.0,2.0),(0.0,1.0),(0.0, 0.0)], 1.0));
}

#[test]
fn calculate_point_to_line_distance() {
    assert!((distance_point_to_line((3.0, 2.0), ((-2.0, 0.0),(0.0, 2.0))) - 2.12132).abs() < 0.00001);
    assert!(distance_point_to_line((0.0, 0.0), ((-1.0, 0.0),(1.0, 0.0))).abs() < 0.00001);
}

#[test]
fn calculate_point_to_point_distance() {
    assert!((distance_point_to_point((3.0, 2.0), (5.0, -1.0)) - 3.60555).abs() < 0.00001);
    assert!(distance_point_to_point((3.0, 2.0), (3.0, 2.0)).abs() < 0.00001);
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]
#![feature(globs)]

extern crate semver;
extern crate conduit;

use std::iter;
use std::io::net::ip::IpAddr;
use std::collections::hashmap::{HashMap, Entries};

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

pub trait RequestDelegator {
    fn request<'a>(&'a self) -> &'a Request;
    fn mut_request<'a>(&'a mut self) -> &'a mut Request;

    fn http_version(&self) -> semver::Version {
        self.request().http_version()
    }

    fn conduit_version(&self) -> semver::Version {
        self.request().conduit_version()
    }

    fn method(&self) -> Method {
        self.request().method()
    }

    fn scheme(&self) -> Scheme {
        self.request().scheme()
    }

    fn host<'a>(&'a self) -> Host<'a> {
        self.request().host()
    }

    fn virtual_root<'a>(&'a self) -> Option<&'a str> {
        self.request().virtual_root()
    }

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

    fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.request().query_string()
    }

    fn remote_ip(&self) -> IpAddr {
        self.request().remote_ip()
    }

    fn content_length(&self) -> Option<uint> {
        self.request().content_length()
    }

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

    fn body<'a>(&'a mut self) -> &'a mut Reader {
        self.mut_request().body()
    }

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

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

impl<'a> Request for &'a mut RequestDelegator + 'a {
    fn http_version(&self) -> semver::Version {
        self.http_version()
    }

    fn conduit_version(&self) -> semver::Version {
        self.conduit_version()
    }

    fn method(&self) -> Method {
        self.method()
    }

    fn scheme(&self) -> Scheme {
        self.scheme()
    }

    fn host<'a>(&'a self) -> Host<'a> {
        self.host()
    }

    fn virtual_root<'a>(&'a self) -> Option<&'a str> {
        self.virtual_root()
    }

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

    fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.query_string()
    }

    fn remote_ip(&self) -> IpAddr {
        self.remote_ip()
    }

    fn content_length(&self) -> Option<uint> {
        self.content_length()
    }

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

    fn body<'a>(&'a mut self) -> &'a mut Reader {
        self.body()
    }

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

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

type RawHeaders = HashMap<String, Vec<String>>;
type InHeader<'a> = (&'a String, &'a Vec<String>);
type OutHeader<'a> = (String, &'a Vec<String>);

#[deriving(PartialEq, Clone, Show)]
pub struct HeaderMap(HashMap<String, Vec<String>>);

impl HeaderMap {
    fn normalize(headers: HashMap<String, Vec<String>>) -> HeaderMap {
        let headers = headers.into_iter().map(|(k,v)| (to_lower(&k), v)).collect();
        HeaderMap(headers)
    }

    fn iter<'a>(&'a self) -> iter::Map<'a, InHeader<'a>, OutHeader<'a>, Entries<'a, String, Vec<String>>> {
        self.as_ref().iter().map(|(k,v)| (to_lower(k), v))
    }

    fn as_ref<'a>(&'a self) -> &'a HashMap<String, Vec<String>> {
        match *self {
            HeaderMap(ref map) => map
        }
    }

    fn as_mut<'a>(&'a mut self) -> &'a mut HashMap<String, Vec<String>> {
        match *self {
            HeaderMap(ref mut map) => map
        }
    }
}

impl Collection for HeaderMap {
    fn len(&self) -> uint {
        self.as_ref().len()
    }
}

impl Mutable for HeaderMap {
    fn clear(&mut self) {
        self.as_mut().clear()
    }
}

impl<S: Str> Map<S, Vec<String>> for HeaderMap {
    fn find<'a>(&'a self, key: &S) -> Option<&'a Vec<String>> {
        self.as_ref().find(&to_lower(key))
    }
}

impl<S: Str> MutableMap<S, Vec<String>> for HeaderMap {
    fn swap(&mut self, k: S, v: Vec<String>) -> Option<Vec<String>> {
        self.as_mut().swap(to_lower(&k), v)
    }

    fn pop(&mut self, k: &S) -> Option<Vec<String>> {
        self.as_mut().pop(&to_lower(k))
    }

    fn find_mut<'a>(&'a mut self, k: &S) -> Option<&'a mut Vec<String>> {
        self.as_mut().find_mut(&to_lower(k))
    }
}

fn to_lower<S: Str>(string: &S) -> String {
    string.as_slice().chars().map(|c| c.to_lowercase()).collect()
}

#[cfg(test)]
mod tests {
    extern crate "conduit-test" as test;

    use {RequestDelegator, HeaderMap};

    use std::collections::HashMap;
    use conduit;
    use conduit::{Request, Method};

    struct OverrideRequest<'a> {
        request: &'a mut Request + 'a
    }

    impl<'a> RequestDelegator for OverrideRequest<'a> {
        fn request<'a>(&'a self) -> &'a Request {
            let req: &Request = self.request; req
        }

        fn mut_request<'a>(&'a mut self) -> &'a mut Request {
            let req: &mut Request = self.request; req
        }

        fn method(&self) -> Method {
            conduit::Get
        }
    }

    #[test]
    fn test_delegate() {
        let request = &mut test::MockRequest::new(conduit::Head, "/hello") as &mut Request;
        let new = OverrideRequest { request: request };

        assert_eq!(new.method(), conduit::Get);
        assert_eq!(new.path(), "/hello");
    }

    #[test]
    fn test_header_map() {
        let mut map = HeaderMap(HashMap::new());
        map.insert("Content-Type".to_string(), vec!("text/html".to_string()));
        map.insert("location".to_string(), vec!("http://example.com".to_string()));

        assert_eq!(map.find(&"content-type".to_string()), Some(&vec!("text/html".to_string())))
        assert_eq!(map.find(&"Location".to_string()), Some(&vec!("http://example.com".to_string())))
        assert_eq!(map.find(&"content-type"), Some(&vec!("text/html".to_string())))
        assert_eq!(map.find(&"Location"), Some(&vec!("http://example.com".to_string())))
    }

    #[test]
    fn test_header_map_with_static_inserts() {
        let mut map = HeaderMap(HashMap::new());
        map.insert("Content-Type", vec!("text/html".to_string()));
        map.insert("location", vec!("http://example.com".to_string()));

        assert_eq!(map.find(&"content-type".to_string()), Some(&vec!("text/html".to_string())))
        assert_eq!(map.find(&"Location".to_string()), Some(&vec!("http://example.com".to_string())))
        assert_eq!(map.find(&"content-type"), Some(&vec!("text/html".to_string())))
        assert_eq!(map.find(&"Location"), Some(&vec!("http://example.com".to_string())))
    }

    #[test]
    fn test_normalize() {
        let mut map = HashMap::new();
        map.insert("Content-Type".to_string(), vec!("text/html".to_string()));

        let headers = HeaderMap::normalize(map);
        assert_eq!(headers.find(&"Content-Type".to_string()), Some(&vec!("text/html".to_string())))
        assert_eq!(headers.find(&"Content-Type"), Some(&vec!("text/html".to_string())))
        assert_eq!(headers.find(&"content-type".to_string()), Some(&vec!("text/html".to_string())))
        assert_eq!(headers.find(&"content-type"), Some(&vec!("text/html".to_string())))
    }

    #[test]
    fn test_iterate() {
        let mut headers = HeaderMap(HashMap::new());
        headers.insert("Content-Type", vec!("text/html".to_string()));
        headers.insert("location", vec!("http://example.com".to_string()));

        assert!(headers.iter().any(|t| t == ("content-type".to_string(), &vec!("text/html".to_string()))));
        assert!(headers.iter().any(|t| t == ("location".to_string(), &vec!("http://example.com".to_string()))));
        assert!(headers.iter().count() == 2);
    }
}
<commit_msg>Update to rust master<commit_after>#![feature(macro_rules)]
#![feature(globs)]

extern crate semver;
extern crate conduit;

use std::iter;
use std::io::net::ip::IpAddr;
use std::collections::hashmap::{HashMap, Entries};

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

pub trait RequestDelegator {
    fn request<'a>(&'a self) -> &'a Request;
    fn mut_request<'a>(&'a mut self) -> &'a mut Request;

    fn http_version(&self) -> semver::Version {
        self.request().http_version()
    }

    fn conduit_version(&self) -> semver::Version {
        self.request().conduit_version()
    }

    fn method(&self) -> Method {
        self.request().method()
    }

    fn scheme(&self) -> Scheme {
        self.request().scheme()
    }

    fn host<'a>(&'a self) -> Host<'a> {
        self.request().host()
    }

    fn virtual_root<'a>(&'a self) -> Option<&'a str> {
        self.request().virtual_root()
    }

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

    fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.request().query_string()
    }

    fn remote_ip(&self) -> IpAddr {
        self.request().remote_ip()
    }

    fn content_length(&self) -> Option<uint> {
        self.request().content_length()
    }

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

    fn body<'a>(&'a mut self) -> &'a mut Reader {
        self.mut_request().body()
    }

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

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

impl<'a> Request for &'a mut RequestDelegator + 'a {
    fn http_version(&self) -> semver::Version {
        self.http_version()
    }

    fn conduit_version(&self) -> semver::Version {
        self.conduit_version()
    }

    fn method(&self) -> Method {
        self.method()
    }

    fn scheme(&self) -> Scheme {
        self.scheme()
    }

    fn host<'a>(&'a self) -> Host<'a> {
        self.host()
    }

    fn virtual_root<'a>(&'a self) -> Option<&'a str> {
        self.virtual_root()
    }

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

    fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.query_string()
    }

    fn remote_ip(&self) -> IpAddr {
        self.remote_ip()
    }

    fn content_length(&self) -> Option<uint> {
        self.content_length()
    }

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

    fn body<'a>(&'a mut self) -> &'a mut Reader {
        self.body()
    }

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

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

type RawHeaders = HashMap<String, Vec<String>>;
type InHeader<'a> = (&'a String, &'a Vec<String>);
type OutHeader<'a> = (String, &'a Vec<String>);

#[deriving(PartialEq, Clone, Show)]
pub struct HeaderMap(HashMap<String, Vec<String>>);

impl HeaderMap {
    fn normalize(headers: HashMap<String, Vec<String>>) -> HeaderMap {
        let headers = headers.into_iter().map(|(k,v)| (to_lower(&k), v)).collect();
        HeaderMap(headers)
    }

    fn iter<'a>(&'a self) -> iter::Map<'a, InHeader<'a>, OutHeader<'a>, Entries<'a, String, Vec<String>>> {
        self.as_ref().iter().map(|(k,v)| (to_lower(k), v))
    }

    fn as_ref<'a>(&'a self) -> &'a HashMap<String, Vec<String>> {
        match *self {
            HeaderMap(ref map) => map
        }
    }

    fn as_mut<'a>(&'a mut self) -> &'a mut HashMap<String, Vec<String>> {
        match *self {
            HeaderMap(ref mut map) => map
        }
    }

    pub fn len(&self) -> uint {
        self.as_ref().len()
    }
    pub fn clear(&mut self) {
        self.as_mut().clear()
    }
    pub fn find<'a, S: Str>(&'a self, key: &S) -> Option<&'a Vec<String>> {
        self.as_ref().find(&to_lower(key))
    }
    pub fn insert<S: Str>(&mut self, k: S, v: Vec<String>) -> Option<Vec<String>> {
        self.as_mut().swap(to_lower(&k), v)
    }
    pub fn remove<S: Str>(&mut self, k: &S) -> Option<Vec<String>> {
        self.as_mut().pop(&to_lower(k))
    }

    pub fn find_mut<'a, S: Str>(&'a mut self, k: &S) -> Option<&'a mut Vec<String>> {
        self.as_mut().find_mut(&to_lower(k))
    }
}

fn to_lower<S: Str>(string: &S) -> String {
    string.as_slice().chars().map(|c| c.to_lowercase()).collect()
}

#[cfg(test)]
mod tests {
    extern crate "conduit-test" as test;

    use {RequestDelegator, HeaderMap};

    use std::collections::HashMap;
    use conduit;
    use conduit::{Request, Method};

    struct OverrideRequest<'a> {
        request: &'a mut Request + 'a
    }

    impl<'a> RequestDelegator for OverrideRequest<'a> {
        fn request<'a>(&'a self) -> &'a Request {
            let req: &Request = self.request; req
        }

        fn mut_request<'a>(&'a mut self) -> &'a mut Request {
            let req: &mut Request = self.request; req
        }

        fn method(&self) -> Method {
            conduit::Get
        }
    }

    #[test]
    fn test_delegate() {
        let request = &mut test::MockRequest::new(conduit::Head, "/hello") as &mut Request;
        let new = OverrideRequest { request: request };

        assert_eq!(new.method(), conduit::Get);
        assert_eq!(new.path(), "/hello");
    }

    #[test]
    fn test_header_map() {
        let mut map = HeaderMap(HashMap::new());
        map.insert("Content-Type".to_string(), vec!("text/html".to_string()));
        map.insert("location".to_string(), vec!("http://example.com".to_string()));

        assert_eq!(map.find(&"content-type".to_string()), Some(&vec!("text/html".to_string())))
        assert_eq!(map.find(&"Location".to_string()), Some(&vec!("http://example.com".to_string())))
        assert_eq!(map.find(&"content-type"), Some(&vec!("text/html".to_string())))
        assert_eq!(map.find(&"Location"), Some(&vec!("http://example.com".to_string())))
    }

    #[test]
    fn test_header_map_with_static_inserts() {
        let mut map = HeaderMap(HashMap::new());
        map.insert("Content-Type", vec!("text/html".to_string()));
        map.insert("location", vec!("http://example.com".to_string()));

        assert_eq!(map.find(&"content-type".to_string()), Some(&vec!("text/html".to_string())))
        assert_eq!(map.find(&"Location".to_string()), Some(&vec!("http://example.com".to_string())))
        assert_eq!(map.find(&"content-type"), Some(&vec!("text/html".to_string())))
        assert_eq!(map.find(&"Location"), Some(&vec!("http://example.com".to_string())))
    }

    #[test]
    fn test_normalize() {
        let mut map = HashMap::new();
        map.insert("Content-Type".to_string(), vec!("text/html".to_string()));

        let headers = HeaderMap::normalize(map);
        assert_eq!(headers.find(&"Content-Type".to_string()), Some(&vec!("text/html".to_string())))
        assert_eq!(headers.find(&"Content-Type"), Some(&vec!("text/html".to_string())))
        assert_eq!(headers.find(&"content-type".to_string()), Some(&vec!("text/html".to_string())))
        assert_eq!(headers.find(&"content-type"), Some(&vec!("text/html".to_string())))
    }

    #[test]
    fn test_iterate() {
        let mut headers = HeaderMap(HashMap::new());
        headers.insert("Content-Type", vec!("text/html".to_string()));
        headers.insert("location", vec!("http://example.com".to_string()));

        assert!(headers.iter().any(|t| t == ("content-type".to_string(), &vec!("text/html".to_string()))));
        assert!(headers.iter().any(|t| t == ("location".to_string(), &vec!("http://example.com".to_string()))));
        assert!(headers.iter().count() == 2);
    }
}
<|endoftext|>


<commit_before>extern crate serial;
#[macro_use] extern crate serde_derive;
extern crate serde;

use serde::ser::{Serializer, Serialize};
use serde::de::{self, Deserializer, Deserialize};

pub use serial::Error;

mod enttec;

pub use enttec::{available_enttec_ports, EnttecDmxPort, ENTTEC_NAMESPACE};

/// Trait for the general notion of a DMX port.
/// This enables creation of an "offline" port to slot into place if an API requires an output.
pub trait DmxPort {
    /// Write a DMX frame out to the port.  If the frame is smaller than the minimum universe size,
    /// it will be padded with zeros.  If the frame is larger than the maximum universe size, the
    /// values beyond the max size will be ignored.
    fn write(&mut self, frame: &[u8]) -> Result<(), Error>;

    /// Return the name of this port.  Should only be used for display purposes.
    fn port_name(&self) -> &str;

    /// Return a SerializablePort to be used to try to reopen a port
    /// after deserialization of a saved show or after application restart.
    fn serializable(&self) -> SerializablePort;
}

pub struct OfflineDmxPort {}

const OFFLINE_NAMESPACE: &'static str = "offline";
const OFFLINE_ID: &'static str = "offline";

impl DmxPort for OfflineDmxPort {
    fn write(&mut self, _: &[u8]) -> Result<(), Error> {
        Ok(())
    }
    fn port_name(&self) -> &str {
        OFFLINE_ID
    }
    fn serializable(&self) -> SerializablePort {
        SerializablePort::new(OFFLINE_NAMESPACE, OFFLINE_ID)
    }
}

#[derive(Serialize, Deserialize)]
/// A serializable data structure for persisting a record of a port to disk, also providing
/// for attempted reopening of a port.
pub struct SerializablePort<'a> {
    namespace: &'a str,
    id: &'a str,
}

impl<'a> SerializablePort<'a> {
    fn new(namespace: &'a str, id: &'a str) -> Self {
        SerializablePort { namespace: namespace, id: id }
    }
    /// Based on the namespace and id, try to reopen this DMX port.
    /// If we don't know the namespace or the port isn't available, return an offline port.
    fn reopen(self) -> Box<DmxPort> {
        fn offline() -> Box<DmxPort> {
            Box::new(OfflineDmxPort{})
        }
        match self.namespace {
            OFFLINE_NAMESPACE => offline(),
            ENTTEC_NAMESPACE =>
                match EnttecDmxPort::new(self.id) {
                    Ok(port) => Box::new(port),
                    Err(_) => offline()
                },
            _ => offline()
        }
    }
}

// Helper functions to use when serializing and deserializing DmxPort trait objects contained in
// other structs.  This can be done using the serde with attribute.
pub fn serialize<S>(port: &Box<DmxPort>, serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer
{
    port.serializable().serialize(serializer)
}

pub fn deserialize<'de, D>(deserializer: D) -> Result<Box<DmxPort>, D::Error>
    where D: Deserializer<'de>
{
    SerializablePort::deserialize(deserializer).map(SerializablePort::reopen)
}<commit_msg>ENH: serializable port impls eq<commit_after>extern crate serial;
#[macro_use] extern crate serde_derive;
extern crate serde;

use serde::ser::{Serializer, Serialize};
use serde::de::{self, Deserializer, Deserialize};

pub use serial::Error;

mod enttec;

pub use enttec::{available_enttec_ports, EnttecDmxPort, ENTTEC_NAMESPACE};

/// Trait for the general notion of a DMX port.
/// This enables creation of an "offline" port to slot into place if an API requires an output.
pub trait DmxPort {
    /// Write a DMX frame out to the port.  If the frame is smaller than the minimum universe size,
    /// it will be padded with zeros.  If the frame is larger than the maximum universe size, the
    /// values beyond the max size will be ignored.
    fn write(&mut self, frame: &[u8]) -> Result<(), Error>;

    /// Return the name of this port.  Should only be used for display purposes.
    fn port_name(&self) -> &str;

    /// Return a SerializablePort to be used to try to reopen a port
    /// after deserialization of a saved show or after application restart.
    fn serializable(&self) -> SerializablePort;
}

pub struct OfflineDmxPort {}

const OFFLINE_NAMESPACE: &'static str = "offline";
const OFFLINE_ID: &'static str = "offline";

impl DmxPort for OfflineDmxPort {
    fn write(&mut self, _: &[u8]) -> Result<(), Error> {
        Ok(())
    }
    fn port_name(&self) -> &str {
        OFFLINE_ID
    }
    fn serializable(&self) -> SerializablePort {
        SerializablePort::new(OFFLINE_NAMESPACE, OFFLINE_ID)
    }
}

#[derive(PartialEq, Eq, Serialize, Deserialize)]
/// A serializable data structure for persisting a record of a port to disk, also providing
/// for attempted reopening of a port.
pub struct SerializablePort<'a> {
    namespace: &'a str,
    id: &'a str,
}

impl<'a> SerializablePort<'a> {
    fn new(namespace: &'a str, id: &'a str) -> Self {
        SerializablePort { namespace: namespace, id: id }
    }
    /// Based on the namespace and id, try to reopen this DMX port.
    /// If we don't know the namespace or the port isn't available, return an offline port.
    fn reopen(self) -> Box<DmxPort> {
        fn offline() -> Box<DmxPort> {
            Box::new(OfflineDmxPort{})
        }
        match self.namespace {
            OFFLINE_NAMESPACE => offline(),
            ENTTEC_NAMESPACE =>
                match EnttecDmxPort::new(self.id) {
                    Ok(port) => Box::new(port),
                    Err(_) => offline()
                },
            _ => offline()
        }
    }
}

// Helper functions to use when serializing and deserializing DmxPort trait objects contained in
// other structs.  This can be done using the serde with attribute.
pub fn serialize<S>(port: &Box<DmxPort>, serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer
{
    port.serializable().serialize(serializer)
}

pub fn deserialize<'de, D>(deserializer: D) -> Result<Box<DmxPort>, D::Error>
    where D: Deserializer<'de>
{
    SerializablePort::deserialize(deserializer).map(SerializablePort::reopen)
}<|endoftext|>