<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_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);
    }
}
<commit_msg>Support Box<Error>.<commit_after>//! A small library which provides convenient, non-panicking error handling for small CLI scripts.
#![deny(missing_docs)]
#![deny(unused)]

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

/// 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: Into<Box<StdError>>
{
    if let Err(error) = main() {
        let error = error.into();
        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.
pub fn run_and_exit<E, F>(main: F) -> !
    where F: FnOnce() -> Result<(), E>,
          E: Into<Box<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) => {
        use $crate::Error;
        if !($e) {
            return Err(Error::with_description($fmt)).into();
        }
    };
    ($e:expr, $fmt:expr, $($arg:tt)*) => {
        use $crate::Error;
        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"))
    }

    fn err_box() -> Result<(), Box<StdError>> {
        Err(Box::new(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);
    }

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


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#![crate_name = "js"]
#![crate_type = "rlib"]

#![feature(link_args, collections, core)]

#![allow(non_upper_case_globals, non_camel_case_types, non_snake_case, improper_ctypes, raw_pointer_derive)]

extern crate libc;
#[macro_use]
extern crate log;
extern crate rustc_serialize as serialize;

use libc::c_uint;

/*
FIXME: Not sure where JS_Lock is
pub use jsapi::bindgen::JS_Lock as JS_LockRuntime;
pub use jsapi::bindgen::JS_Unlock as JS_UnlockRuntime;
*/

pub mod jsapi;
pub mod linkhack;
pub mod rust;
pub mod glue;
pub mod jsval;

use jsapi::{JSContext, JSObject, JS_ComputeThis, JSProtoKey};
use jsval::JSVal;

pub const default_heapsize: u32 = 32_u32 * 1024_u32 * 1024_u32;
pub const default_stacksize: usize = 8192;

pub const JSID_TYPE_STRING: i64 = 0;
pub const JSID_TYPE_INT: i64 = 1;
pub const JSID_TYPE_VOID: i64 = 2;
pub const JSID_TYPE_OBJECT: i64 = 4;
pub const JSID_TYPE_DEFAULT_XML_NAMESPACE: i64 = 6;
pub const JSID_TYPE_MASK: i64 = 7;

pub const JSFUN_CONSTRUCTOR: u32 = 0x400; /* native that can be called as a ctor */

pub const JSPROP_ENUMERATE: c_uint = 0x01;
pub const JSPROP_READONLY: c_uint  = 0x02;
pub const JSPROP_PERMANENT: c_uint = 0x04;
pub const JSPROP_GETTER: c_uint = 0x10;
pub const JSPROP_SETTER: c_uint = 0x20;
pub const JSPROP_SHARED: c_uint =    0x40;
pub const JSPROP_NATIVE_ACCESSORS: c_uint = 0x08;

pub const JSCLASS_RESERVED_SLOTS_SHIFT: c_uint = 8;
pub const JSCLASS_RESERVED_SLOTS_WIDTH: c_uint = 8;
pub const JSCLASS_RESERVED_SLOTS_MASK: c_uint = ((1 << JSCLASS_RESERVED_SLOTS_WIDTH) - 1) as c_uint;

pub const JSCLASS_HIGH_FLAGS_SHIFT: c_uint =
    JSCLASS_RESERVED_SLOTS_SHIFT + JSCLASS_RESERVED_SLOTS_WIDTH;
pub const JSCLASS_IS_GLOBAL: c_uint = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 1);
pub const JSCLASS_GLOBAL_APPLICATION_SLOTS: c_uint = 4;
pub const JSCLASS_GLOBAL_SLOT_COUNT: c_uint = JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProtoKey::JSProto_LIMIT as u32 * 3 + 31;

pub const JSCLASS_IS_DOMJSCLASS: u32 = 1 << 4;
pub const JSCLASS_IMPLEMENTS_BARRIERS: u32 = 1 << 5;
pub const JSCLASS_USERBIT1: u32 = 1 << 7;

pub const JSCLASS_IS_PROXY: u32 = 1 << (JSCLASS_HIGH_FLAGS_SHIFT+4);

pub const JSSLOT_PROXY_PRIVATE: u32 = 1;

pub const JS_DEFAULT_ZEAL_FREQ: u32 = 100;

pub const JSTrue: u8 = 1;
pub const JSFalse: u8 = 0;

#[link(name = "jsglue")]
extern { }

#[cfg(target_os = "android")]
#[link(name = "stdc++")]
extern { }

#[cfg(target_os = "android")]
#[link(name = "gcc")]
extern { }

#[inline(always)]
pub unsafe fn JS_ARGV(_cx: *mut JSContext, vp: *mut JSVal) -> *mut JSVal {
    vp.offset(2)
}

#[inline(always)]
pub unsafe fn JS_CALLEE(_cx: *mut JSContext, vp: *mut JSVal) -> JSVal {
    *vp
}
<commit_msg>Add new feature gates.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#![crate_name = "js"]
#![crate_type = "rlib"]

#![feature(collections, str_utf16)]
#![feature(core, core_intrinsics)]
#![feature(link_args)]

#![allow(non_upper_case_globals, non_camel_case_types, non_snake_case, improper_ctypes, raw_pointer_derive)]

extern crate libc;
#[macro_use]
extern crate log;
extern crate rustc_serialize as serialize;

use libc::c_uint;

/*
FIXME: Not sure where JS_Lock is
pub use jsapi::bindgen::JS_Lock as JS_LockRuntime;
pub use jsapi::bindgen::JS_Unlock as JS_UnlockRuntime;
*/

pub mod jsapi;
pub mod linkhack;
pub mod rust;
pub mod glue;
pub mod jsval;

use jsapi::{JSContext, JSObject, JS_ComputeThis, JSProtoKey};
use jsval::JSVal;

pub const default_heapsize: u32 = 32_u32 * 1024_u32 * 1024_u32;
pub const default_stacksize: usize = 8192;

pub const JSID_TYPE_STRING: i64 = 0;
pub const JSID_TYPE_INT: i64 = 1;
pub const JSID_TYPE_VOID: i64 = 2;
pub const JSID_TYPE_OBJECT: i64 = 4;
pub const JSID_TYPE_DEFAULT_XML_NAMESPACE: i64 = 6;
pub const JSID_TYPE_MASK: i64 = 7;

pub const JSFUN_CONSTRUCTOR: u32 = 0x400; /* native that can be called as a ctor */

pub const JSPROP_ENUMERATE: c_uint = 0x01;
pub const JSPROP_READONLY: c_uint  = 0x02;
pub const JSPROP_PERMANENT: c_uint = 0x04;
pub const JSPROP_GETTER: c_uint = 0x10;
pub const JSPROP_SETTER: c_uint = 0x20;
pub const JSPROP_SHARED: c_uint =    0x40;
pub const JSPROP_NATIVE_ACCESSORS: c_uint = 0x08;

pub const JSCLASS_RESERVED_SLOTS_SHIFT: c_uint = 8;
pub const JSCLASS_RESERVED_SLOTS_WIDTH: c_uint = 8;
pub const JSCLASS_RESERVED_SLOTS_MASK: c_uint = ((1 << JSCLASS_RESERVED_SLOTS_WIDTH) - 1) as c_uint;

pub const JSCLASS_HIGH_FLAGS_SHIFT: c_uint =
    JSCLASS_RESERVED_SLOTS_SHIFT + JSCLASS_RESERVED_SLOTS_WIDTH;
pub const JSCLASS_IS_GLOBAL: c_uint = 1 << (JSCLASS_HIGH_FLAGS_SHIFT + 1);
pub const JSCLASS_GLOBAL_APPLICATION_SLOTS: c_uint = 4;
pub const JSCLASS_GLOBAL_SLOT_COUNT: c_uint = JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProtoKey::JSProto_LIMIT as u32 * 3 + 31;

pub const JSCLASS_IS_DOMJSCLASS: u32 = 1 << 4;
pub const JSCLASS_IMPLEMENTS_BARRIERS: u32 = 1 << 5;
pub const JSCLASS_USERBIT1: u32 = 1 << 7;

pub const JSCLASS_IS_PROXY: u32 = 1 << (JSCLASS_HIGH_FLAGS_SHIFT+4);

pub const JSSLOT_PROXY_PRIVATE: u32 = 1;

pub const JS_DEFAULT_ZEAL_FREQ: u32 = 100;

pub const JSTrue: u8 = 1;
pub const JSFalse: u8 = 0;

#[link(name = "jsglue")]
extern { }

#[cfg(target_os = "android")]
#[link(name = "stdc++")]
extern { }

#[cfg(target_os = "android")]
#[link(name = "gcc")]
extern { }

#[inline(always)]
pub unsafe fn JS_ARGV(_cx: *mut JSContext, vp: *mut JSVal) -> *mut JSVal {
    vp.offset(2)
}

#[inline(always)]
pub unsafe fn JS_CALLEE(_cx: *mut JSContext, vp: *mut JSVal) -> JSVal {
    *vp
}
<|endoftext|>


<commit_before>#![feature(phase)]
extern crate regex;
#[phase(plugin)] extern crate regex_macros;

use std::io::{BufferedReader, BufferedWriter, InvalidInput, IoError, IoResult, TcpStream};

pub struct Bot {
    pub sock: TcpStream
}

impl Bot {
    pub fn new() -> Bot {
        let sock = TcpStream::connect("irc.fyrechat.net", 6667).unwrap();
        Bot {
            sock: sock,
        }
    }

    pub fn identify(&mut self) {
        let mut writer = BufferedWriter::new(self.sock.clone());
        writer.write_str("NICK :pickles\r\n").unwrap();
        writer.write_str("USER pickles 0 * :pickles\r\n").unwrap();
        writer.flush().unwrap();
    }

    pub fn output(&mut self) {
        let mut reader = BufferedReader::new(self.sock.clone());
        for line in reader.lines() {
            match line {
                Ok(ln) => {
                    let (source, command, args) = process(ln.as_slice()).unwrap();
                    self.handle_command(source, command, args.as_slice());
                    println!("{}", ln)
                },
                Err(e) => println!("Shit, you're fucked! {}", e),
            }
        }
    }

    fn handle_command(&mut self, source: &str, command: &str, args: &[&str]) -> () {
        match (command, args) {
            ("PING", [msg]) => {
                self.send("PONG", msg);
            },
            ("376", _) => {
                self.send("JOIN", "#vana");
            },
            ("PRIVMSG", [channel, msg]) => {
                if msg.contains("pickles") && msg.contains("hi") {
                    self.send("PRIVMSG #vana", "hi");
                }

                if msg.starts_with(". ") {
                    self.send("PRIVMSG #vana", msg.slice_from(2));
                }
            },
            _ => (),
        }
    }

    fn send(&mut self, command: &str, arg: &str) {
        let mut writer = BufferedWriter::new(self.sock.clone());
        write!(writer, "{} :{}\r\n", command, arg);
        writer.flush().unwrap();
    }
}

fn process(msg: &str) -> IoResult<(&str, &str, Vec<&str>)> {
    let reg = regex!(r"^(?::([^ ]+) )?([^ ]+)(.*)");
    let cap = match reg.captures(msg) {
        Some(x) => x,
        None => return Err(IoError {
            kind: InvalidInput,
            desc: "Failed to parse line",
            detail: None,
        }),
    };
    let source = cap.at(1);
    let command = cap.at(2);
    let args = parse_args(cap.at(3));
    Ok((source, command, args))
}

fn parse_args(line: &str) -> Vec<&str> {
    let reg = regex!(r" ([^: ]+)| :(.*)$");
    reg.captures_iter(line).map(|cap| {
        match cap.at(1) {
            "" => cap.at(2),
            x => x,
        }
    }).collect()
}
<commit_msg>Refactored basic library significantly, but sending isn't working properly.<commit_after>#![feature(phase)]
extern crate regex;
#[phase(plugin)] extern crate regex_macros;

use std::io::{BufferedReader, BufferedWriter, InvalidInput, IoError, IoResult, TcpStream};

pub struct Connection(TcpStream);

pub fn connect(host: &str, port: u16) -> IoResult<Connection> {
    let socket = try!(TcpStream::connect(host, port));
    Ok(Connection(socket))
}

fn send_internal(conn: &Connection, msg: &str) -> IoResult<()> {
    match conn {
        &Connection(ref tcp) => {
            let mut writer = BufferedWriter::new(tcp.clone());
            writer.write_str(msg);
            writer.flush()
        },
    }
}

pub struct Message<'a> {
    source: Option<&'a str>,
    command: &'a str,
    args: &'a [&'a str],
}

impl<'a> Message<'a> {
    pub fn new(source: Option<&'a str>, command: &'a str, args: &'a [&'a str]) -> Message<'a> {
        Message {
            source: source,
            command: command,
            args: args,
        }
    }
}

pub fn send(conn: &Connection, msg: Message) -> IoResult<()> {
    let arg_string = msg.args.init().connect(" ").append(" :").append(*msg.args.last().unwrap());
    send_internal(conn, msg.command.to_string().append(" ").append(arg_string.as_slice()).as_slice())
}

pub struct Bot {
    pub conn: Connection,
}

impl Bot {
    pub fn new() -> IoResult<Bot> {
        let conn = try!(connect("irc.fyrechat.net", 6667));
        Ok(Bot {
            conn: conn,
        })
    }

    pub fn send_nick(&mut self, nick: &str) -> IoResult<()> {
        send(&self.conn, Message::new(None, "NICK", [nick]))
    }

    pub fn send_user(&mut self, username: &str, real_name: &str) -> IoResult<()> {
        send(&self.conn, Message::new(None, "USER", [username, "0", "*", real_name]))
    }

    pub fn identify(&mut self) -> IoResult<()> {
        self.send_nick("pickles");
        self.send_user("pickles", "pickles")
    }

    pub fn output(&mut self) {
        let mut reader = { let Connection(ref tcp) = self.conn; BufferedReader::new(tcp.clone()) };
        for line in reader.lines() {
            match line {
                Ok(ln) => {
                    let (source, command, args) = process(ln.as_slice()).unwrap();
                    self.handle_command(source, command, args.as_slice());
                    println!("{}", ln)
                },
                Err(e) => println!("Shit, you're fucked! {}", e),
            }
        }
    }

    fn handle_command(&mut self, source: &str, command: &str, args: &[&str]) -> IoResult<()> {
        match (command, args) {
            ("PING", [msg]) => {
                try!(send(&self.conn, Message::new(None, "PONG", [msg])));
            },
            ("376", _) => {
                try!(send(&self.conn, Message::new(None, "JOIN", ["#vana"])));
            },
            ("PRIVMSG", [_, msg]) => {
                if msg.contains("pickles") && msg.contains("hi") {
                    try!(send(&self.conn, Message::new(None, "PRIVMSG", ["#vana", "hi"])));
                } else if msg.starts_with(". ") {
                    try!(send(&self.conn, Message::new(None, "PRIVMSG", ["#vana", msg.slice_from(2)])));
                };
            },
            _ => (),
        };
        Ok(())
    }
}

fn process(msg: &str) -> IoResult<(&str, &str, Vec<&str>)> {
    let reg = regex!(r"^(?::([^ ]+) )?([^ ]+)(.*)");
    let cap = match reg.captures(msg) {
        Some(x) => x,
        None => return Err(IoError {
            kind: InvalidInput,
            desc: "Failed to parse line",
            detail: None,
        }),
    };
    let source = cap.at(1);
    let command = cap.at(2);
    let args = parse_args(cap.at(3));
    Ok((source, command, args))
}

fn parse_args(line: &str) -> Vec<&str> {
    let reg = regex!(r" ([^: ]+)| :(.*)$");
    reg.captures_iter(line).map(|cap| {
        match cap.at(1) {
            "" => cap.at(2),
            x => x,
        }
    }).collect()
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate nom;
extern crate flate2;

use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use std::fmt;

use flate2::read::GzDecoder;
use nom::{be_u8, be_u16, be_u32, IResult, Needed};

use errors::*;
pub use enums::*;

const BUFSIZE: usize = 200;

mod enums;

#[allow(unused_doc_comment)]
pub mod errors {
    error_chain!{
        foreign_links {
            Io(::std::io::Error);
            Nom(::nom::Err);
        }
    }
}

pub struct MessageStream<R> {
    reader: R,
    buffer: Box<[u8; BUFSIZE]>,
    bufstart: usize,
    bufend: usize,
    bytes_read: usize,
    read_calls: u32,
    messages: u32,
}

impl<R> fmt::Debug for MessageStream<R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "MessageStream {{ read_calls: {}, bytes_read: {}, buffer_pos: {}, messages: {} }}",
            self.read_calls,
            self.bytes_read,
            self.bytes_read - (self.bufend - self.bufstart),
            self.messages
        )
    }
}

impl<R: Read> MessageStream<R> {
    fn new(reader: R) -> MessageStream<R> {
        MessageStream {
            reader,
            buffer: Box::new([0; BUFSIZE]),
            bufstart: 0,
            bufend: 0,
            bytes_read: 0,
            read_calls: 0,
            messages: 0,
        }
    }

    fn fetch_more_bytes(&mut self) -> Result<usize> {
        self.read_calls += 1;
        if self.bufend == BUFSIZE {
            // we need more data from the reader
            // first, copy the remnants back to the beginning of the buffer
            // (this should only be a few bytes)
            assert!(self.bufstart as usize > BUFSIZE / 2); // safety check
            assert!(BUFSIZE - self.bufstart < 50); // extra careful check
            {
                let (left, right) = self.buffer.split_at_mut(self.bufstart);
                &left[..right.len()].copy_from_slice(&right[..]);
                self.bufstart = 0;
                self.bufend = right.len();
            }

        }
        Ok(self.reader.read(&mut self.buffer[self.bufend..])?)
    }
}

impl<R: Read> Iterator for MessageStream<R> {
    type Item = Result<Message>;

    fn next(&mut self) -> Option<Result<Message>> {
        use IResult::*;
        {
            let buf = &self.buffer[self.bufstart..self.bufend];
            match parse_message(buf) {
                Done(rest, msg) => {
                    self.bufstart = self.bufend - rest.len();
                    self.messages += 1;
                    return Some(Ok(msg));
                }
                Error(e) => return Some(Err(format!("Parse failed: went wrong: {}", e).into())),
                // .chain_err(|| format!("Stream state: {:?}, slice: {:?}...",
                //                     self, &buf[..50]))),
                Incomplete(_) => {
                    // fall through to below... necessary to appease borrow checker
                }
            }
        }
        match self.fetch_more_bytes() {
            Ok(0) => Some(Err("Unexpected EOF".into())),
            Ok(ct) => {
                self.bufend += ct;
                self.bytes_read += ct;
                self.next()
            }
            Err(e) => Some(Err(e)),
        }
    }
}

pub fn parse_reader<R: Read>(reader: R) -> MessageStream<R> {
    // We will do the parsing in a streaming fashion because these
    // files are BIG and we don't want to load it all into memory
    MessageStream::new(reader)
}

pub fn parse_gzip<P: AsRef<Path>>(path: P) -> Result<MessageStream<GzDecoder<File>>> {
    let file = File::open(path)?;
    let reader = GzDecoder::new(file)?;
    Ok(parse_reader(reader))
}

pub fn parse_file<P: AsRef<Path>>(path: P) -> Result<MessageStream<File>> {
    let reader = File::open(path)?;
    Ok(parse_reader(reader))
}

#[inline]
pub fn be_u48(i: &[u8]) -> IResult<&[u8], u64> {
    if i.len() < 6 {
        IResult::Incomplete(Needed::Size(6))
    } else {
        let res = ((i[0] as u64) << 40) + ((i[1] as u64) << 32) + ((i[2] as u64) << 24) +
            ((i[3] as u64) << 16) + ((i[4] as u64) << 8) + i[5] as u64;
        IResult::Done(&i[6..], res)
    }
}

named!(char2bool<bool>, alt!(
    char!('Y') => {|_| true} |
    char!('N') => {|_| false}
));

named!(maybe_char2bool<Option<bool>>, alt!(
    char!('Y') => {|_| Some(true)} |
    char!('N') => {|_| Some(false)} |
    char!(' ') => {|_| None}
));

#[derive(Debug, Clone, PartialEq)]
pub enum Message {
    SystemEvent {
        tracking_number: u16,
        timestamp: u64,
        event_code: EventCode,
    },
    Unknown {
        length: u16,
        tag: char,
        content: Vec<u8>,
    },
    StockDirectory(StockDirectory),
    ParticipantPosition(MarketParticipantPosition)
}

#[derive(Debug, Clone, PartialEq)]
pub struct StockDirectory {
    stock_locate: u16,
    tracking_number: u16,
    timestamp: u64,
    stock: String,
    market_category: MarketCategory,
    financial_status: FinancialStatus,
    round_lot_size: u32,
    round_lots_only: bool,
    issue_classification: IssueClassification,
    issue_subtype: IssueSubType,
    authenticity: bool,
    short_sale_threshold: Option<bool>,
    ipo_flag: Option<bool>,
    luld_ref_price_tier: LuldRefPriceTier,
    etp_flag: Option<bool>,
    etp_leverage_factor: u32,
    inverse_indicator: bool,
}

named!(parse_message<Message>, do_parse!(
    length: be_u16 >>
    msg: switch!(be_u8,
        b'S' => call!(parse_system_event) |
        b'R' => map!(parse_stock_directory, |sd| Message::StockDirectory(sd)) |
        b'L' => map!(parse_participant_position, |pp| Message::ParticipantPosition(pp)) |
        other => map!(take!(length - 1),
                      |slice| Message::Unknown {
                          length,
                          tag: other as char,
                          content: Vec::from(slice)
                      })) >>
    (msg)
));

named!(parse_system_event<Message>, do_parse!(
    tag!([0, 0]) >>
    tracking_number: be_u16 >>
    timestamp: be_u48 >>
    event_code: alt!(
        char!('O') => { |_| EventCode::StartOfMessages } |
        char!('S') => { |_| EventCode::StartOfSystemHours } |
        char!('Q') => { |_| EventCode::StartOfMarketHours } |
        char!('M') => { |_| EventCode::EndOfMarketHours } |
        char!('E') => { |_| EventCode::EndOfSystemHours } |
        char!('C') => { |_| EventCode::EndOfMessages }
    ) >>
    (Message::SystemEvent { tracking_number, timestamp, event_code })
));

named!(parse_stock_directory<StockDirectory>, do_parse!(
    stock_locate: be_u16 >>
        tracking_number: be_u16 >>
        timestamp: be_u48 >>
        stock: map!(take_str!(8), |s| s.trim().to_string()) >>
        market_category: alt!(
            char!('Q') => { |_| MarketCategory::NasdaqGlobalSelect } |
            char!('G') => { |_| MarketCategory::NasdaqGlobalMarket } |
            char!('S') => { |_| MarketCategory::NasdaqCaptialMarket } |
            char!('N') => { |_| MarketCategory::Nyse } |
            char!('A') => { |_| MarketCategory::NyseMkt } |
            char!('P') => { |_| MarketCategory::NyseArca } |
            char!('Z') => { |_| MarketCategory::BatsZExchange } |
            char!(' ') => { |_| MarketCategory::Unavailable }
        ) >>
        financial_status: alt!(
            char!('N') => { |_| FinancialStatus::Normal } |
            char!('D') => { |_| FinancialStatus::Deficient } |
            char!('E') => { |_| FinancialStatus::Delinquent } |
            char!('Q') => { |_| FinancialStatus::Bankrupt } |
            char!('S') => { |_| FinancialStatus::Suspended } |
            char!('G') => { |_| FinancialStatus::DeficientBankrupt } |
            char!('H') => { |_| FinancialStatus::DeficientDelinquent } |
            char!('J') => { |_| FinancialStatus::DelinquentBankrupt } |
            char!('K') => { |_| FinancialStatus::DeficientDelinquentBankrupt } |
            char!('C') => { |_| FinancialStatus::EtpSuspended } |
            char!(' ') => { |_| FinancialStatus::Unavailable }
        ) >>
        round_lot_size: be_u32 >>
        round_lots_only: char2bool >>

        // FIXME these are dummy values
        issue_classification: value!(IssueClassification::Unit, take!(1)) >>
        issue_subtype: value!(IssueSubType::AlphaIndexETNs, take!(2)) >>
        authenticity: alt!(
            char!('P') => {|_| true} |
            char!('T') => {|_| false}
        ) >>
        short_sale_threshold: maybe_char2bool >>
        ipo_flag: maybe_char2bool >>
        luld_ref_price_tier: alt!(
            char!(' ') => { |_| LuldRefPriceTier::Na } |
            char!('1') => { |_| LuldRefPriceTier::Tier1 } |
            char!('2') => { |_| LuldRefPriceTier::Tier2 }
        ) >>
        etp_flag: maybe_char2bool >>
        etp_leverage_factor: be_u32 >>
        inverse_indicator: char2bool >>
        (StockDirectory {
            stock_locate, tracking_number, timestamp, stock,
            market_category, financial_status, round_lot_size,
            round_lots_only, issue_classification, issue_subtype,
            authenticity, short_sale_threshold, ipo_flag,
            luld_ref_price_tier, etp_flag, etp_leverage_factor, inverse_indicator
        })
));

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MarketParticipantPosition {
    stock_locate: u16,
    tracking_number: u16,
    timestamp: u64,
    mpid: String,
    stock: String,
    primary_market_maker: bool,
    market_maker_mode: MarketMakerMode,
    market_participant_state: MarketParticipantState
}

named!(parse_participant_position<MarketParticipantPosition>, do_parse!(
    stock_locate: be_u16 >>
    tracking_number: be_u16 >>
    timestamp: be_u48 >>
    mpid: map!(take_str!(4), |s| s.trim().to_string()) >>
    stock: map!(take_str!(8), |s| s.trim().to_string()) >>
    primary_market_maker: char2bool >>
    market_maker_mode: alt!(
        char!('N') => {|_| MarketMakerMode::Normal} |
        char!('P') => {|_| MarketMakerMode::Passive} |
        char!('S') => {|_| MarketMakerMode::Syndicate} |
        char!('R') => {|_| MarketMakerMode::Presyndicate} |
        char!('L') => {|_| MarketMakerMode::Penalty}
    ) >>
    market_participant_state: alt!(
        char!('A') => {|_| MarketParticipantState::Active} |
        char!('E') => {|_| MarketParticipantState::Excused} |
        char!('W') => {|_| MarketParticipantState::Withdrawn} |
        char!('S') => {|_| MarketParticipantState::Suspended} |
        char!('D') => {|_| MarketParticipantState::Deleted}
    ) >>
    (MarketParticipantPosition{
            stock_locate,
            tracking_number,
            timestamp,
            mpid,
            stock,
            primary_market_maker,
            market_maker_mode,
            market_participant_state
    })
));

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

    // for pretty-printing
    fn bytes2hex(bytes: &[u8]) -> Vec<(char, char)> {
        fn b2h(b: u8) -> (char, char) {
            let left = match b >> 4 {
                v@0...9 => b'0' + v,
                v@10...15 => b'a' + v - 10,
                _ => unreachable!()
            };
            let right = match b & 0xff {
                v@0...9 => b'0' + v,
                v@10...15 => b'a' + v - 10,
                _ => unreachable!()
            };
            (left as char, right as char)
        }
        bytes.iter().map(|b| b2h(*b)).collect()
    }

    fn hex_to_bytes(bytes: &[u8]) -> Vec<u8> {
        fn h2b(h: u8) -> Option<u8> {
            match h {
                v @ b'0'...b'9' => Some(v - b'0'),
                v @ b'a'...b'f' => Some(v - b'a' + 10),
                b' ' | b'\n' => None,
                _ => panic!("Invalid hex: {}", h as char),
            }
        }
        bytes
            .iter()
            .filter_map(|b| h2b(*b))
            .collect::<Vec<_>>()
            .chunks(2)
            .map(|slice| (slice[0] << 4) + slice[1])
            .collect()
    }

    #[test]
    fn system_event() {
        let code = b"0000 0000 286aab3b3a99 4f";
        let bytes = hex_to_bytes(&code[..]);
        let (_, out) = parse_system_event(&bytes[..]).unwrap();
        if let Message::SystemEvent { .. } = out {
        } else {
            panic!("Expected SystemEvent,  found {:?}", out)
        }
    }

    #[test]
    fn stock_directory() {
        let code = b"00 0100 0028 9d5b 22a4 1b41 2020 2020 2020 204e 2000
                     0000 644e 435a 2050 4e20 314e 0000 0000 4e";
        let bytes = hex_to_bytes(&code[..]);
        parse_stock_directory(&bytes[..]).unwrap();
    }

    #[test]
    fn market_participant_position() {
        let code = b"02 bf 00 00 28 9e bc 1a f4 55 41 44 41 4d 42 42 52 59 20 20 20 20 59 4e 41";
        let bytes = hex_to_bytes(&code[..]);
        parse_participant_position(&bytes[..]).unwrap();
    }

    #[test]
    fn full_parse() {
        let iter = parse_file("data/01302016.NASDAQ_ITCH50").unwrap();
        for (ix, msg) in iter.enumerate() {
            if let Ok(Message::Unknown { tag, content, .. }) = msg {
                print!("Message {} tag '{}' unknown: [", ix, tag);
                for v in content { print!("{:02x} ", v) }
                println!("]");
                panic!()
            }
            if let Err(e) = msg {
                panic!("Mesaage {} failed to parse: {}", ix, e);
            }
        }
    }
}
<commit_msg>factor out message header<commit_after>#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate nom;
extern crate flate2;

use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use std::fmt;

use flate2::read::GzDecoder;
use nom::{be_u8, be_u16, be_u32, IResult, Needed};

use errors::*;
pub use enums::*;

const BUFSIZE: usize = 200;

mod enums;

#[allow(unused_doc_comment)]
pub mod errors {
    error_chain!{
        foreign_links {
            Io(::std::io::Error);
            Nom(::nom::Err);
        }
    }
}

pub struct MessageStream<R> {
    reader: R,
    buffer: Box<[u8; BUFSIZE]>,
    bufstart: usize,
    bufend: usize,
    bytes_read: usize,
    read_calls: u32,
    messages: u32,
}

impl<R> fmt::Debug for MessageStream<R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "MessageStream {{ read_calls: {}, bytes_read: {}, buffer_pos: {}, messages: {} }}",
            self.read_calls,
            self.bytes_read,
            self.bytes_read - (self.bufend - self.bufstart),
            self.messages
        )
    }
}

impl<R: Read> MessageStream<R> {
    fn new(reader: R) -> MessageStream<R> {
        MessageStream {
            reader,
            buffer: Box::new([0; BUFSIZE]),
            bufstart: 0,
            bufend: 0,
            bytes_read: 0,
            read_calls: 0,
            messages: 0,
        }
    }

    fn fetch_more_bytes(&mut self) -> Result<usize> {
        self.read_calls += 1;
        if self.bufend == BUFSIZE {
            // we need more data from the reader
            // first, copy the remnants back to the beginning of the buffer
            // (this should only be a few bytes)
            assert!(self.bufstart as usize > BUFSIZE / 2); // safety check
            assert!(BUFSIZE - self.bufstart < 50); // extra careful check
            {
                let (left, right) = self.buffer.split_at_mut(self.bufstart);
                &left[..right.len()].copy_from_slice(&right[..]);
                self.bufstart = 0;
                self.bufend = right.len();
            }

        }
        Ok(self.reader.read(&mut self.buffer[self.bufend..])?)
    }
}

impl<R: Read> Iterator for MessageStream<R> {
    type Item = Result<Message>;

    fn next(&mut self) -> Option<Result<Message>> {
        use IResult::*;
        {
            let buf = &self.buffer[self.bufstart..self.bufend];
            match parse_message(buf) {
                Done(rest, msg) => {
                    self.bufstart = self.bufend - rest.len();
                    self.messages += 1;
                    return Some(Ok(msg));
                }
                Error(e) => return Some(Err(format!("Parse failed: {}", e).into())),
                Incomplete(_) => {
                    // fall through to below... necessary to appease borrow checker
                }
            }
        }
        match self.fetch_more_bytes() {
            Ok(0) => Some(Err("Unexpected EOF".into())),
            Ok(ct) => {
                self.bufend += ct;
                self.bytes_read += ct;
                self.next()
            }
            Err(e) => Some(Err(e)),
        }
    }
}

pub fn parse_reader<R: Read>(reader: R) -> MessageStream<R> {
    // We will do the parsing in a streaming fashion because these
    // files are BIG and we don't want to load it all into memory
    MessageStream::new(reader)
}

pub fn parse_gzip<P: AsRef<Path>>(path: P) -> Result<MessageStream<GzDecoder<File>>> {
    let file = File::open(path)?;
    let reader = GzDecoder::new(file)?;
    Ok(parse_reader(reader))
}

pub fn parse_file<P: AsRef<Path>>(path: P) -> Result<MessageStream<File>> {
    let reader = File::open(path)?;
    Ok(parse_reader(reader))
}

#[inline]
pub fn be_u48(i: &[u8]) -> IResult<&[u8], u64> {
    if i.len() < 6 {
        IResult::Incomplete(Needed::Size(6))
    } else {
        let res = ((i[0] as u64) << 40) + ((i[1] as u64) << 32) + ((i[2] as u64) << 24) +
            ((i[3] as u64) << 16) + ((i[4] as u64) << 8) + i[5] as u64;
        IResult::Done(&i[6..], res)
    }
}

named!(char2bool<bool>, alt!(
    char!('Y') => {|_| true} |
    char!('N') => {|_| false}
));

named!(maybe_char2bool<Option<bool>>, alt!(
    char!('Y') => {|_| Some(true)} |
    char!('N') => {|_| Some(false)} |
    char!(' ') => {|_| None}
));

#[derive(Debug, Clone, PartialEq)]
pub struct Message {
    header: MsgHeader,
    body: MessageBody
}

#[derive(Debug, Clone, PartialEq)]
struct MsgHeader {
    stock_locate: u16,
    tracking_number: u16,
    timestamp: u64
}

named!(parse_message_header<MsgHeader>, do_parse!(
    stock_locate: be_u16 >>
    tracking_number: be_u16 >>
    timestamp: be_u48 >>
    (MsgHeader { stock_locate, tracking_number, timestamp })
));

#[derive(Debug, Clone, PartialEq)]
pub enum MessageBody {
    SystemEvent(EventCode),
    //RegShoRestriction(RegShoRestriction),
    StockDirectory(StockDirectory),
    ParticipantPosition(MarketParticipantPosition),
    Unknown {
        length: u16,
        tag: char,
        content: Vec<u8>,
    },
}

named!(parse_message<Message>, do_parse!(
    length: be_u16 >>
    tag: be_u8 >>
    header: parse_message_header >>
    body: switch!(value!(tag),  // TODO is this 'value' call necessary?
                  b'S' => call!(parse_system_event) |
                  b'R' => map!(parse_stock_directory, |sd| MessageBody::StockDirectory(sd)) |
                  b'L' => map!(parse_participant_position, |pp| MessageBody::ParticipantPosition(pp)) |
                  other => map!(take!(length - 1),
                                |slice| MessageBody::Unknown {
                                    length,
                                    tag: other as char,
                                    content: Vec::from(slice)
                                })) >>
    (Message { header, body })
));

#[derive(Debug, Clone, PartialEq)]
pub struct StockDirectory {
    stock: String,
    market_category: MarketCategory,
    financial_status: FinancialStatus,
    round_lot_size: u32,
    round_lots_only: bool,
    issue_classification: IssueClassification,
    issue_subtype: IssueSubType,
    authenticity: bool,
    short_sale_threshold: Option<bool>,
    ipo_flag: Option<bool>,
    luld_ref_price_tier: LuldRefPriceTier,
    etp_flag: Option<bool>,
    etp_leverage_factor: u32,
    inverse_indicator: bool,
}

named!(parse_system_event<MessageBody>, do_parse!(
    event_code: alt!(
        char!('O') => { |_| EventCode::StartOfMessages } |
        char!('S') => { |_| EventCode::StartOfSystemHours } |
        char!('Q') => { |_| EventCode::StartOfMarketHours } |
        char!('M') => { |_| EventCode::EndOfMarketHours } |
        char!('E') => { |_| EventCode::EndOfSystemHours } |
        char!('C') => { |_| EventCode::EndOfMessages }
    ) >>
    (MessageBody::SystemEvent(event_code))
));

named!(parse_stock_directory<StockDirectory>, do_parse!(
    stock: map!(take_str!(8), |s| s.trim().to_string()) >>
    market_category: alt!(
        char!('Q') => { |_| MarketCategory::NasdaqGlobalSelect } |
        char!('G') => { |_| MarketCategory::NasdaqGlobalMarket } |
        char!('S') => { |_| MarketCategory::NasdaqCaptialMarket } |
        char!('N') => { |_| MarketCategory::Nyse } |
        char!('A') => { |_| MarketCategory::NyseMkt } |
        char!('P') => { |_| MarketCategory::NyseArca } |
        char!('Z') => { |_| MarketCategory::BatsZExchange } |
        char!(' ') => { |_| MarketCategory::Unavailable }
    ) >>
    financial_status: alt!(
        char!('N') => { |_| FinancialStatus::Normal } |
        char!('D') => { |_| FinancialStatus::Deficient } |
        char!('E') => { |_| FinancialStatus::Delinquent } |
        char!('Q') => { |_| FinancialStatus::Bankrupt } |
        char!('S') => { |_| FinancialStatus::Suspended } |
        char!('G') => { |_| FinancialStatus::DeficientBankrupt } |
        char!('H') => { |_| FinancialStatus::DeficientDelinquent } |
        char!('J') => { |_| FinancialStatus::DelinquentBankrupt } |
        char!('K') => { |_| FinancialStatus::DeficientDelinquentBankrupt } |
        char!('C') => { |_| FinancialStatus::EtpSuspended } |
        char!(' ') => { |_| FinancialStatus::Unavailable }
    ) >>
    round_lot_size: be_u32 >>
    round_lots_only: char2bool >>

    // FIXME these are dummy values
    issue_classification: value!(IssueClassification::Unit, take!(1)) >>
    issue_subtype: value!(IssueSubType::AlphaIndexETNs, take!(2)) >>
    authenticity: alt!(
        char!('P') => {|_| true} |
        char!('T') => {|_| false}
    ) >>
    short_sale_threshold: maybe_char2bool >>
    ipo_flag: maybe_char2bool >>
    luld_ref_price_tier: alt!(
        char!(' ') => { |_| LuldRefPriceTier::Na } |
        char!('1') => { |_| LuldRefPriceTier::Tier1 } |
        char!('2') => { |_| LuldRefPriceTier::Tier2 }
    ) >>
    etp_flag: maybe_char2bool >>
    etp_leverage_factor: be_u32 >>
    inverse_indicator: char2bool >>
    (StockDirectory {
        stock, market_category, financial_status, round_lot_size,
        round_lots_only, issue_classification, issue_subtype,
        authenticity, short_sale_threshold, ipo_flag,
        luld_ref_price_tier, etp_flag, etp_leverage_factor, inverse_indicator
    })
));

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MarketParticipantPosition {
    mpid: String,
    stock: String,
    primary_market_maker: bool,
    market_maker_mode: MarketMakerMode,
    market_participant_state: MarketParticipantState
}

named!(parse_participant_position<MarketParticipantPosition>, do_parse!(
    mpid: map!(take_str!(4), |s| s.trim().to_string()) >>
    stock: map!(take_str!(8), |s| s.trim().to_string()) >>
    primary_market_maker: char2bool >>
    market_maker_mode: alt!(
        char!('N') => {|_| MarketMakerMode::Normal} |
        char!('P') => {|_| MarketMakerMode::Passive} |
        char!('S') => {|_| MarketMakerMode::Syndicate} |
        char!('R') => {|_| MarketMakerMode::Presyndicate} |
        char!('L') => {|_| MarketMakerMode::Penalty}
    ) >>
    market_participant_state: alt!(
        char!('A') => {|_| MarketParticipantState::Active} |
        char!('E') => {|_| MarketParticipantState::Excused} |
        char!('W') => {|_| MarketParticipantState::Withdrawn} |
        char!('S') => {|_| MarketParticipantState::Suspended} |
        char!('D') => {|_| MarketParticipantState::Deleted}
    ) >>
    (MarketParticipantPosition{
            mpid,
            stock,
            primary_market_maker,
            market_maker_mode,
            market_participant_state
    })
));

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

    // for pretty-printing
    fn bytes2hex(bytes: &[u8]) -> Vec<(char, char)> {
        fn b2h(b: u8) -> (char, char) {
            let left = match b >> 4 {
                v@0...9 => b'0' + v,
                v@10...15 => b'a' + v - 10,
                _ => unreachable!()
            };
            let right = match b & 0xff {
                v@0...9 => b'0' + v,
                v@10...15 => b'a' + v - 10,
                _ => unreachable!()
            };
            (left as char, right as char)
        }
        bytes.iter().map(|b| b2h(*b)).collect()
    }

    fn hex_to_bytes(bytes: &[u8]) -> Vec<u8> {
        fn h2b(h: u8) -> Option<u8> {
            match h {
                v @ b'0'...b'9' => Some(v - b'0'),
                v @ b'a'...b'f' => Some(v - b'a' + 10),
                b' ' | b'\n' => None,
                _ => panic!("Invalid hex: {}", h as char),
            }
        }
        bytes
            .iter()
            .filter_map(|b| h2b(*b))
            .collect::<Vec<_>>()
            .chunks(2)
            .map(|slice| (slice[0] << 4) + slice[1])
            .collect()
    }

    #[test]
    fn system_event() {
        let code = b"4f";
        let bytes = hex_to_bytes(&code[..]);
        let (_, out) = parse_system_event(&bytes[..]).unwrap();
        if let MessageBody::SystemEvent(EventCode::StartOfMessages) = out {
        } else {
            panic!("Expected SystemEvent,  found {:?}", out)
        }
    }

    #[test]
    fn stock_directory() {
        let code = b"41 2020 2020 2020 204e 2000
                     0000 644e 435a 2050 4e20 314e 0000 0000 4e";
        let bytes = hex_to_bytes(&code[..]);
        parse_stock_directory(&bytes[..]).unwrap();
    }

    #[test]
    fn market_participant_position() {
        let code = b"41 44 41 4d 42 42 52 59 20 20 20 20 59 4e 41";
        let bytes = hex_to_bytes(&code[..]);
        parse_participant_position(&bytes[..]).unwrap();
    }

    #[test]
    fn full_parse() {
        let iter = parse_file("data/01302016.NASDAQ_ITCH50").unwrap();
        for (ix, msg) in iter.enumerate() {
            if let Err(e) = msg {
                panic!("Mesaage {} failed to parse: {}", ix, e);
            } else {
                if let MessageBody::Unknown { tag, content, .. } = msg.unwrap().body {
                    print!("Message {} tag '{}' unknown: [", ix, tag);
                    for v in content { print!("{:02x} ", v) }
                    println!("]");
                    panic!()
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! # Functor composition via the Co-Yoneda Lemma
//!
//! ## Functors in Rust
//!
//! Let's implement functors in Rust!
//!
//! Working around the lack of higher-kinded types, our trait for a functor
//! will look something like this:
//!
//! ```
//! pub trait Functor<'a, A, B> {
//!    type Output;
//!    fn fmap<F: Fn(A) -> B + 'a>(self, F) -> Self::Output;
//! }
//! ```
//!
//! This works great as long as we write functions that take specific
//! types which are functors, but it is not possible to write a function
//! operating on a generic functor type and using `fmap` more than once.
//! For example, the following will not compile:
//!
//! ```
//! fn add_and_to_string<'a, F: Functor<'a, i32, String>>(x: F) -> F::Output {
//!    x.fmap(|n: i32| n + 1)
//!     .fmap(|n: i32| n.to_string())
//! }
//! ```
//!
//! While functors in general can be encoded to some extend
//! in Rust's trait system, what we can't encode for a lack of higher-kinded
//! types, is the fact that a functor `Box` maps a function between `A` and `B`
//! to a function between `Box<A>` and `Box<B>`, not between `Box<A>` and `Option<B>`.
//!
//! Especially when looking at functor composition, it is useful to
//! be able to encode this fact, because it allows us to chain
//! multiple calls to `fmap`, knowing that the result is also a functor,
//! and can be `fmap`'ed further.
//!
//! ## The Co-Yoneda Lemma
//!
//! Let's define a data type called `Coyoneda`:
//!
//! ```
//! pub struct Coyoneda<'a, T: Param, B> {
//!     point: T,
//!     morph: Fn(T::Param) -> B + 'a
//! }
//! ```
//!
//! This datatype is a functor, which uses function composition
//! to accumulate the mapping function, without changing the captured
//! `T`. The implementation for `Functor` is trivial:
//!
//! ```
//! impl<'a, T: Param, B, C> Functor<'a, B, C> for Coyoneda<'a, T, B> {
//!     type Output = Coyoneda<'a, T, C>;
//!     fn fmap<F: Fn(B) -> C + 'a>(self, f: F) -> Coyoneda<'a, T, C> {
//!         let g = self.morph;
//!         Coyoneda{point: self.point, morph: move |x| f(g(x))}
//!     }
//! }
//! ```
//!
//! The co-yoneda lemma states that for a covariant functor `f`,
//! this `Coyoneda f` is naturally isomorphic to `f`.
//! Practically speaking, this means that we can lift any `f a` into a `Coyoneda f a`,
//! and given a function `(a -> b) -> f b`, we can retrieve back a `f b` from a `Coyoneda f b`.
//!
//! ## Composing Coyoneda
//!
//! Now here's the catch: Since we have a parameterized datatype that is isomorphic to any functor,
//! we can lift functors into Coyoneda to compose them safely within Rust's type system!
//!
//! For example, let's implement a function that is generic for any functor,
//! by operating on our `Coyoneda` type:
//!
//! ```
//! fn add_and_to_string<T: Param>(y: Coyoneda<T, i32>) -> Coyoneda<T, String> {
//!    y.fmap(|n: i32| n + 1)
//!     .fmap(|n: i32| n.to_string())
//! }
//! ```
//!
//! Given we implemented a functor for `Option`, we can now do the following:
//!
//! ```
//! let y = add_and_to_string(From::from(Some(42)));
//! assert_eq!(y.unwrap(), Some("43".to_string()))
//! ```
//!
//! ... or for `Box`:
//!
//! ```
//! let y = add_and_to_string(From::from(Box::new(42)));
//! assert_eq!(y.unwrap(), Box::new("43".to_string()))
//! ```
//!
//! ... and for every other functor as well. Yay!

mod morphism;

use morphism::Morphism;

pub trait Param { type Param; }

pub trait Functor<'a, A, B>: Param {
    type Output;
    fn fmap<F: Fn(A) -> B + 'a>(self, F) -> Self::Output;
}

pub struct Coyoneda<'a, T: Param, B> {
    point: T,
    morph: Morphism<'a, T::Param, B>
}

impl<'a, T: 'a + Param, B: 'a> Coyoneda<'a, T, B> {

    pub fn transform<U: Param, F, G>(self, f: F, g: G) -> Coyoneda<'a, U, B>
        where F: Fn(T) -> U, G: 'a + Fn(U::Param) -> T::Param {
        let Coyoneda{point: t, morph: m} = self;
        Coyoneda{point: f(t), morph: m.head(g)}
    }

    pub fn unwrap(self) -> <T as Functor<'a, <T as Param>::Param, B>>::Output
        where T: Functor<'a, <T as Param>::Param, B>, <T as Param>::Param: 'a {
        let m = self.morph;
        T::fmap(self.point, move |a| { m.run(a) })
    }

}

impl<'a, T: Param, B> Param for Coyoneda<'a, T, B> {
    type Param = B;
}

impl<'a, T: Param, B, C> Functor<'a, B, C> for Coyoneda<'a, T, B> {
    type Output = Coyoneda<'a, T, C>;
    fn fmap<F: Fn(B) -> C + 'a>(self, f: F) -> Coyoneda<'a, T, C> {
        Coyoneda{point: self.point, morph: self.morph.tail(f)}
    }
}

impl<'a, T: Param> From<T> for Coyoneda<'a, T, <T as Param>::Param> {
    fn from(x: T) -> Coyoneda<'a, T, <T as Param>::Param> {
        Coyoneda{point: x, morph: Morphism::new()}
    }
}

impl<A> Param for Box<A> {
    type Param = A;
}

impl<'a, A, B> Functor<'a, A, B> for Box<A> {
    type Output = Box<B>;
    fn fmap<F: Fn(A) -> B>(self, f: F) -> Self::Output {
        Box::new(f(*self))
    }
}

impl<A> Param for Option<A> {
    type Param = A;
}

impl<'a, A, B> Functor<'a, A, B> for Option<A> {
    type Output = Option<B>;
    fn fmap<F: Fn(A) -> B>(self, f: F) -> Self::Output {
        Option::map(self, f)
    }
}

impl<A, E> Param for Result<A, E> {
    type Param = A;
}

impl<'a, A, B, E> Functor<'a, A, B> for Result<A, E> {
    type Output = Result<B, E>;
    fn fmap<F: Fn(A) -> B>(self, f: F) -> Self::Output {
        Result::map(self, f)
    }
}

mod test {
#![cfg(test)]

    use super::*;

    fn add_and_to_string<T: Param>(y: Coyoneda<T, i32>) -> Coyoneda<T, String> {
        y.fmap(|n: i32| n + 1)
         .fmap(|n: i32| n.to_string())
         .fmap(|s| s + "foo")
         .fmap(|s| s + "bar")
    }

    #[test]
    fn test_box() {
        let x = Box::new(42);
        let y = add_and_to_string(From::from(x)).unwrap();
        assert_eq!(y, Box::new("43foobar".to_string()))
    }

    #[test]
    fn test_option() {
        let x = Some(42);
        let y = add_and_to_string(From::from(x)).unwrap();
        assert_eq!(y, Some("43foobar".to_string()))
    }

    #[test]
    fn test_result() {
        let x: Result<i32, ()> = Ok(42);
        let y = add_and_to_string(From::from(x)).unwrap();
        assert_eq!(y, Ok("43foobar".to_string()))
    }

}
<commit_msg>add natural transform<commit_after>//! # Functor composition via the Co-Yoneda Lemma
//!
//! ## Functors in Rust
//!
//! Let's implement functors in Rust!
//!
//! Working around the lack of higher-kinded types, our trait for a functor
//! will look something like this:
//!
//! ```
//! pub trait Functor<'a, A, B> {
//!    type Output;
//!    fn fmap<F: Fn(A) -> B + 'a>(self, F) -> Self::Output;
//! }
//! ```
//!
//! This works great as long as we write functions that take specific
//! types which are functors, but it is not possible to write a function
//! operating on a generic functor type and using `fmap` more than once.
//! For example, the following will not compile:
//!
//! ```
//! fn add_and_to_string<'a, F: Functor<'a, i32, String>>(x: F) -> F::Output {
//!    x.fmap(|n: i32| n + 1)
//!     .fmap(|n: i32| n.to_string())
//! }
//! ```
//!
//! While functors in general can be encoded to some extend
//! in Rust's trait system, what we can't encode for a lack of higher-kinded
//! types, is the fact that a functor `Box` maps a function between `A` and `B`
//! to a function between `Box<A>` and `Box<B>`, not between `Box<A>` and `Option<B>`.
//!
//! Especially when looking at functor composition, it is useful to
//! be able to encode this fact, because it allows us to chain
//! multiple calls to `fmap`, knowing that the result is also a functor,
//! and can be `fmap`'ed further.
//!
//! ## The Co-Yoneda Lemma
//!
//! Let's define a data type called `Coyoneda`:
//!
//! ```
//! pub struct Coyoneda<'a, T: Param, B> {
//!     point: T,
//!     morph: Fn(T::Param) -> B + 'a
//! }
//! ```
//!
//! This datatype is a functor, which uses function composition
//! to accumulate the mapping function, without changing the captured
//! `T`. The implementation for `Functor` is trivial:
//!
//! ```
//! impl<'a, T: Param, B, C> Functor<'a, B, C> for Coyoneda<'a, T, B> {
//!     type Output = Coyoneda<'a, T, C>;
//!     fn fmap<F: Fn(B) -> C + 'a>(self, f: F) -> Coyoneda<'a, T, C> {
//!         let g = self.morph;
//!         Coyoneda{point: self.point, morph: move |x| f(g(x))}
//!     }
//! }
//! ```
//!
//! The co-yoneda lemma states that for a covariant functor `f`,
//! this `Coyoneda f` is naturally isomorphic to `f`.
//! Practically speaking, this means that we can lift any `f a` into a `Coyoneda f a`,
//! and given a function `(a -> b) -> f b`, we can retrieve back a `f b` from a `Coyoneda f b`.
//!
//! ## Composing Coyoneda
//!
//! Now here's the catch: Since we have a parameterized datatype that is isomorphic to any functor,
//! we can lift functors into Coyoneda to compose them safely within Rust's type system!
//!
//! For example, let's implement a function that is generic for any functor,
//! by operating on our `Coyoneda` type:
//!
//! ```
//! fn add_and_to_string<T: Param>(y: Coyoneda<T, i32>) -> Coyoneda<T, String> {
//!    y.fmap(|n: i32| n + 1)
//!     .fmap(|n: i32| n.to_string())
//! }
//! ```
//!
//! Given we implemented a functor for `Option`, we can now do the following:
//!
//! ```
//! let y = add_and_to_string(From::from(Some(42)));
//! assert_eq!(y.unwrap(), Some("43".to_string()))
//! ```
//!
//! ... or for `Box`:
//!
//! ```
//! let y = add_and_to_string(From::from(Box::new(42)));
//! assert_eq!(y.unwrap(), Box::new("43".to_string()))
//! ```
//!
//! ... and for every other functor as well. Yay!

mod morphism;

use morphism::Morphism;

pub trait Param { type Param; }

pub trait Functor<'a, A, B>: Param {
    type Output;
    fn fmap<F: Fn(A) -> B + 'a>(self, F) -> Self::Output;
}

pub struct Coyoneda<'a, T: Param, B> {
    point: T,
    morph: Morphism<'a, T::Param, B>
}

impl<'a, T: 'a + Param, B: 'a> Coyoneda<'a, T, B> {

    pub fn transform<U: Param, F, G>(self, f: F, g: G) -> Coyoneda<'a, U, B>
        where F: Fn(T) -> U, G: 'a + Fn(U::Param) -> T::Param {
        let Coyoneda{point: t, morph: m} = self;
        Coyoneda{point: f(t), morph: m.head(g)}
    }

    pub fn natural_transform<U, F>(self, f: F) -> Coyoneda<'a, U, B>
        where U: Param<Param=T::Param>, F: Fn(T) -> U {
        let Coyoneda{point: t, morph: m} = self;
        Coyoneda{point: f(t), morph: m}
    }

    pub fn unwrap(self) -> <T as Functor<'a, <T as Param>::Param, B>>::Output
        where T: Functor<'a, <T as Param>::Param, B>, <T as Param>::Param: 'a {
        let m = self.morph;
        T::fmap(self.point, move |a| { m.run(a) })
    }

}

impl<'a, T: Param, B> Param for Coyoneda<'a, T, B> {
    type Param = B;
}

impl<'a, T: Param, B, C> Functor<'a, B, C> for Coyoneda<'a, T, B> {
    type Output = Coyoneda<'a, T, C>;
    fn fmap<F: Fn(B) -> C + 'a>(self, f: F) -> Coyoneda<'a, T, C> {
        Coyoneda{point: self.point, morph: self.morph.tail(f)}
    }
}

impl<'a, T: Param> From<T> for Coyoneda<'a, T, <T as Param>::Param> {
    fn from(x: T) -> Coyoneda<'a, T, <T as Param>::Param> {
        Coyoneda{point: x, morph: Morphism::new()}
    }
}

impl<A> Param for Box<A> {
    type Param = A;
}

impl<'a, A, B> Functor<'a, A, B> for Box<A> {
    type Output = Box<B>;
    fn fmap<F: Fn(A) -> B>(self, f: F) -> Self::Output {
        Box::new(f(*self))
    }
}

impl<A> Param for Option<A> {
    type Param = A;
}

impl<'a, A, B> Functor<'a, A, B> for Option<A> {
    type Output = Option<B>;
    fn fmap<F: Fn(A) -> B>(self, f: F) -> Self::Output {
        Option::map(self, f)
    }
}

impl<A, E> Param for Result<A, E> {
    type Param = A;
}

impl<'a, A, B, E> Functor<'a, A, B> for Result<A, E> {
    type Output = Result<B, E>;
    fn fmap<F: Fn(A) -> B>(self, f: F) -> Self::Output {
        Result::map(self, f)
    }
}

mod test {
#![cfg(test)]

    use super::*;

    fn add_and_to_string<T: Param>(y: Coyoneda<T, i32>) -> Coyoneda<T, String> {
        y.fmap(|n: i32| n + 1)
         .fmap(|n: i32| n.to_string())
         .fmap(|s| s + "foo")
         .fmap(|s| s + "bar")
    }

    #[test]
    fn fmap_box() {
        let x = Box::new(42);
        let y = add_and_to_string(From::from(x));
        assert_eq!(y.unwrap(), Box::new("43foobar".to_string()))
    }

    #[test]
    fn fmap_option() {
        let x = Some(42);
        let y = add_and_to_string(From::from(x));
        assert_eq!(y.unwrap(), Some("43foobar".to_string()))
    }

    #[test]
    fn fmap_result() {
        let x: Result<i32, ()> = Ok(42);
        let y = add_and_to_string(From::from(x));
        assert_eq!(y.unwrap(), Ok("43foobar".to_string()))
    }

    #[test]
    fn transform() {
        let x = Box::new(42);
        let y = add_and_to_string(From::from(x));
        let z = y.transform(|x| Option::Some(*x as usize), |x| x as i32);
        assert_eq!(z.unwrap(), Some("43foobar".to_string()))
    }

    #[test]
    fn natural_transform() {
        let x = Box::new(42);
        let y = add_and_to_string(From::from(x));
        let z = y.natural_transform(|x| Option::Some(*x));
        assert_eq!(z.unwrap(), Some("43foobar".to_string()))
    }

}
<|endoftext|>


<commit_before>//! This library implements basic processing of JavaScript sourcemaps.
//!
//! ## Installation
//!
//! The crate is called sourcemap and you can depend on it via cargo:
//!
//! ```toml
//! [dependencies]
//! sourcemap = "*"
//! ```
//!
//! If you want to use the git version:
//!
//! ```toml
//! [dependencies.sourcemap]
//! git = "https://github.com/mitsuhiko/rust-sourcemap.git"
//! ```
//!
//! ## Basic Operation
//!
//! This crate can load JavaScript sourcemaps from JSON files.  It uses
//! `serde` for parsing of the JSON data.  Due to the nature of sourcemaps
//! the entirety of the file must be loaded into memory which can be quite
//! memory intensive.
//!
//! Usage:
//!
//! ```rust
//! use sourcemap::SourceMap;
//! let input: &[_] = b"{
//!     \"version\":3,
//!     \"sources\":[\"coolstuff.js\"],
//!     \"names\":[\"x\",\"alert\"],
//!     \"mappings\":\"AAAA,GAAIA,GAAI,EACR,IAAIA,GAAK,EAAG,CACVC,MAAM\"
//! }";
//! let sm = SourceMap::from_reader(input).unwrap();
//! let token = sm.lookup_token(0, 0).unwrap(); // line-number and column
//! println!("token: {}", token);
//! ```
mod macros;

pub use crate::builder::SourceMapBuilder;
pub use crate::decoder::{decode, decode_data_url, decode_slice};
pub use crate::detector::{
    is_sourcemap, is_sourcemap_slice, locate_sourcemap_reference, locate_sourcemap_reference_slice,
    SourceMapRef,
};
pub use crate::errors::{Error, Result};
pub use crate::sourceview::SourceView;
pub use crate::types::{
    DecodedMap, RawToken, RewriteOptions, SourceMap, SourceMapIndex, SourceMapSection,
    SourceMapSectionIter, Token, TokenIter,
};
pub use crate::utils::make_relative_path;

mod builder;
mod decoder;
mod detector;
mod encoder;
mod errors;
mod jsontypes;
mod sourceview;
mod types;
mod utils;
pub mod vlq;
<commit_msg>ref: warn on missing docs<commit_after>//! This library implements basic processing of JavaScript sourcemaps.
//!
//! ## Installation
//!
//! The crate is called sourcemap and you can depend on it via cargo:
//!
//! ```toml
//! [dependencies]
//! sourcemap = "*"
//! ```
//!
//! If you want to use the git version:
//!
//! ```toml
//! [dependencies.sourcemap]
//! git = "https://github.com/mitsuhiko/rust-sourcemap.git"
//! ```
//!
//! ## Basic Operation
//!
//! This crate can load JavaScript sourcemaps from JSON files.  It uses
//! `serde` for parsing of the JSON data.  Due to the nature of sourcemaps
//! the entirety of the file must be loaded into memory which can be quite
//! memory intensive.
//!
//! Usage:
//!
//! ```rust
//! use sourcemap::SourceMap;
//! let input: &[_] = b"{
//!     \"version\":3,
//!     \"sources\":[\"coolstuff.js\"],
//!     \"names\":[\"x\",\"alert\"],
//!     \"mappings\":\"AAAA,GAAIA,GAAI,EACR,IAAIA,GAAK,EAAG,CACVC,MAAM\"
//! }";
//! let sm = SourceMap::from_reader(input).unwrap();
//! let token = sm.lookup_token(0, 0).unwrap(); // line-number and column
//! println!("token: {}", token);
//! ```
#[warn(missing_docs)]
mod macros;

pub use crate::builder::SourceMapBuilder;
pub use crate::decoder::{decode, decode_data_url, decode_slice};
pub use crate::detector::{
    is_sourcemap, is_sourcemap_slice, locate_sourcemap_reference, locate_sourcemap_reference_slice,
    SourceMapRef,
};
pub use crate::errors::{Error, Result};
pub use crate::sourceview::SourceView;
pub use crate::types::{
    DecodedMap, RawToken, RewriteOptions, SourceMap, SourceMapIndex, SourceMapSection,
    SourceMapSectionIter, Token, TokenIter,
};
pub use crate::utils::make_relative_path;

mod builder;
mod decoder;
mod detector;
mod encoder;
mod errors;
mod jsontypes;
mod sourceview;
mod types;
mod utils;
pub mod vlq;
<|endoftext|>


<commit_before>/// A Single-Producer, Multiple-Consumer queue.

use std::sync::mpsc::{channel, Receiver, RecvError, Sender, SendError};
use std::sync::{Arc, RwLock, RwLockReadGuard};
use std::fmt;
use std::any::Any;
use std::error::Error;

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum BroadcastError<T> {
    SendError(T),
    RecvError,
}

impl<T: fmt::Display> fmt::Display for BroadcastError<T> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            BroadcastError::SendError(ref t) =>
                write!(fmt, "could not send data on channel: {}", t),
            BroadcastError::RecvError =>
                write!(fmt, "could not receive data on channel"),
        }
    }
}

impl<T: Send + fmt::Display + fmt::Debug + Any> Error for BroadcastError<T> {
    fn description(&self) -> &str {
        match *self {
            BroadcastError::SendError(_) => "could not send data on channel",
            BroadcastError::RecvError => "could not receive data on channel",
        }
    }

    fn cause(&self) -> Option<&Error> {
        None
    }
}

impl<T> From<SendError<T>> for BroadcastError<T> {
    fn from(err: SendError<T>) -> BroadcastError<T> {
        let SendError(data) = err;
        BroadcastError::SendError(data)
    }
}

impl<T> From<RecvError> for BroadcastError<T> {
    fn from(_err: RecvError) -> BroadcastError<T> {
        BroadcastError::RecvError
    }
}

pub struct Broadcast<T> {
    inner: Arc<Inner<T>>,
}

impl<T: Clone> Broadcast<T> {
    pub fn send(&self, data: T) -> Result<(), BroadcastError<T>> {
        let guard = self.inner.read_senders();
        for s in guard.iter() {
            try!(s.send(data.clone()));
        }

        Ok(())
    }
}

// We implement Send/Sync here since we guarantee that the Sender<T>s in the
// vec only have `send()` called by the Broadcast struct. We need sync in order
// to share the vector with the Consumer to add senders too.
//
// TODO: Is there a way to not need to implement these traits?
//
// The same trait bounds on T are used here as in RwLock.
unsafe impl<T: Sync + Send + ?Sized> Sync for Inner<T> {}
unsafe impl<T: Sync + Send + ?Sized> Send for Inner<T> {}
struct Inner<T> {
    senders: RwLock<Vec<Sender<T>>>,
}

impl<T> Inner<T> {
    // This should only be called by Broadcast. Something may or may not go
    // horriblely wrong if send() is called from multiple threads.
    //
    // TODO: Disallow Consumer from calling this.
    fn read_senders<'a>(&'a self) -> RwLockReadGuard<'a, Vec<Sender<T>>> {
        self.senders.read().unwrap()
    }

    fn add_sender(&self, sender: Sender<T>) {
        let mut vec = self.senders.write().unwrap();
        vec.push(sender);
    }
}

pub struct Consumer<T> {
    inner: Arc<Inner<T>>,
    receiver: Receiver<T>,
}

impl<T> Consumer<T> {
    fn recv(&self) -> Result<T, BroadcastError<T>> {
        let data = try!(self.receiver.recv());
        Ok(data)
    }
}

impl<T> Clone for Consumer<T> {
    fn clone(&self) -> Self {
        let (s, r) = channel();
        self.inner.add_sender(s);
        Consumer {
            inner: self.inner.clone(),
            receiver: r,
        }
    }
}

pub fn broadcast_channel<T: Clone>() -> (Broadcast<T>, Consumer<T>) {
    let (b, c) = channel();
    let inner = Arc::new(Inner { senders: RwLock::new(vec!(b)) });
    let broadcast = Broadcast { inner: inner.clone() };
    let consumer = Consumer { inner: inner, receiver: c };
    (broadcast, consumer)
}

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

    use std::sync::{Arc, RwLock};
    use std::sync::mpsc::{channel};
    use std::thread::spawn;

    #[test]
    fn inner_iterator() {
        let (s1, r1) = channel();
        let (s2, r2) = channel();
        let inner = Arc::new(Inner { senders: RwLock::new(vec!(s1, s2)) });
        let guard = inner.read_senders();
        for s in guard.iter() {
            assert!(s.send(10u8).is_ok());
        }

        assert_eq!(r1.recv().unwrap(), 10u8);
        assert_eq!(r2.recv().unwrap(), 10u8);
    }

    #[test]
    fn sends_to_multiple_consumers() {
        let (p, c) = broadcast_channel();
        let c2 = c.clone();

        let res = p.send(9u8);
        assert!(res.is_ok());

        let res = c.recv();
        assert!(res.is_ok());
        assert_eq!(res.unwrap(), 9u8);

        let res = c2.recv();
        assert!(res.is_ok());
        assert_eq!(res.unwrap(), 9u8)
    }

    #[test]
    fn test_send_threads() {
        let (p, c1) = broadcast_channel();
        let c2 = c1.clone();

        let (s1, r1) = channel();
        let (s2, r2) = channel();

        let _thread = spawn(move || {
            assert_eq!(c1.recv().unwrap(), 9u8);
            s1.send(10u8).unwrap();
        });

        let _thread = spawn(move || {
            assert_eq!(c2.recv().unwrap(), 9u8);
            s2.send(10u8).unwrap();
        });

        assert!(p.send(9u8).is_ok());
        assert!(r1.recv().is_ok());
        assert!(r2.recv().is_ok());
    }
}
<commit_msg>New way to create Broadcast and Consumer<commit_after>/// A Single-Producer, Multiple-Consumer queue.

use std::sync::mpsc::{channel, Receiver, RecvError, Sender, SendError};
use std::sync::{Arc, RwLock, RwLockReadGuard};
use std::fmt;
use std::any::Any;
use std::error::Error;

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum BroadcastError<T> {
    SendError(T),
    RecvError,
}

impl<T: fmt::Display> fmt::Display for BroadcastError<T> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            BroadcastError::SendError(ref t) =>
                write!(fmt, "could not send data on channel: {}", t),
            BroadcastError::RecvError =>
                write!(fmt, "could not receive data on channel"),
        }
    }
}

impl<T: Send + fmt::Display + fmt::Debug + Any> Error for BroadcastError<T> {
    fn description(&self) -> &str {
        match *self {
            BroadcastError::SendError(_) => "could not send data on channel",
            BroadcastError::RecvError => "could not receive data on channel",
        }
    }

    fn cause(&self) -> Option<&Error> {
        None
    }
}

impl<T> From<SendError<T>> for BroadcastError<T> {
    fn from(err: SendError<T>) -> BroadcastError<T> {
        let SendError(data) = err;
        BroadcastError::SendError(data)
    }
}

impl<T> From<RecvError> for BroadcastError<T> {
    fn from(_err: RecvError) -> BroadcastError<T> {
        BroadcastError::RecvError
    }
}

pub struct Broadcast<T> {
    inner: Arc<Inner<T>>,
}

impl<T> Broadcast<T> {
    pub fn new() -> Broadcast<T> {
        let inner = Arc::new(Inner { senders: RwLock::new(Vec::new()) });
        Broadcast { inner: inner }
    }

    pub fn consume(&self) -> Consumer<T> {
        let (b, c) = channel();
        self.inner.add_sender(b);
        Consumer { inner: self.inner.clone(), receiver: c }
    }
}

impl<T: Clone> Broadcast<T> {
    pub fn send(&self, data: T) -> Result<(), BroadcastError<T>> {
        let guard = self.inner.read_senders();
        for s in guard.iter() {
            try!(s.send(data.clone()));
        }

        Ok(())
    }
}

// We implement Send/Sync here since we guarantee that the Sender<T>s in the
// vec only have `send()` called by the Broadcast struct. We need sync in order
// to share the vector with the Consumer to add senders too.
//
// TODO: Is there a way to not need to implement these traits?
//
// The same trait bounds on T are used here as in RwLock.
unsafe impl<T: Sync + Send + ?Sized> Sync for Inner<T> {}
unsafe impl<T: Sync + Send + ?Sized> Send for Inner<T> {}
struct Inner<T> {
    senders: RwLock<Vec<Sender<T>>>,
}

impl<T> Inner<T> {
    // This should only be called by Broadcast. Something may or may not go
    // horriblely wrong if send() is called from multiple threads.
    //
    // TODO: Disallow Consumer from calling this.
    fn read_senders<'a>(&'a self) -> RwLockReadGuard<'a, Vec<Sender<T>>> {
        self.senders.read().unwrap()
    }

    fn add_sender(&self, sender: Sender<T>) {
        let mut vec = self.senders.write().unwrap();
        vec.push(sender);
    }
}

pub struct Consumer<T> {
    inner: Arc<Inner<T>>,
    receiver: Receiver<T>,
}

impl<T> Consumer<T> {
    fn recv(&self) -> Result<T, BroadcastError<T>> {
        let data = try!(self.receiver.recv());
        Ok(data)
    }
}

impl<T> Clone for Consumer<T> {
    fn clone(&self) -> Self {
        let (s, r) = channel();
        self.inner.add_sender(s);
        Consumer {
            inner: self.inner.clone(),
            receiver: r,
        }
    }
}

pub fn broadcast_channel<T: Clone>() -> (Broadcast<T>, Consumer<T>) {
    let broadcast = Broadcast::new();
    let consumer = broadcast.consume();
    (broadcast, consumer)
}

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

    use std::sync::{Arc, RwLock};
    use std::sync::mpsc::{channel};
    use std::thread::spawn;

    #[test]
    fn inner_iterator() {
        let (s1, r1) = channel();
        let (s2, r2) = channel();
        let inner = Arc::new(Inner { senders: RwLock::new(vec!(s1, s2)) });
        let guard = inner.read_senders();
        for s in guard.iter() {
            assert!(s.send(10u8).is_ok());
        }

        assert_eq!(r1.recv().unwrap(), 10u8);
        assert_eq!(r2.recv().unwrap(), 10u8);
    }

    #[test]
    fn sends_to_multiple_consumers() {
        let (p, c) = broadcast_channel();
        let c2 = c.clone();

        let res = p.send(9u8);
        assert!(res.is_ok());

        let res = c.recv();
        assert!(res.is_ok());
        assert_eq!(res.unwrap(), 9u8);

        let res = c2.recv();
        assert!(res.is_ok());
        assert_eq!(res.unwrap(), 9u8)
    }

    #[test]
    fn test_send_threads() {
        let (p, c1) = broadcast_channel();
        let c2 = c1.clone();

        let (s1, r1) = channel();
        let (s2, r2) = channel();

        let _thread = spawn(move || {
            assert_eq!(c1.recv().unwrap(), 9u8);
            s1.send(10u8).unwrap();
        });

        let _thread = spawn(move || {
            assert_eq!(c2.recv().unwrap(), 9u8);
            s2.send(10u8).unwrap();
        });

        assert!(p.send(9u8).is_ok());
        assert!(r1.recv().is_ok());
        assert!(r2.recv().is_ok());
    }
}
<|endoftext|>


<commit_before>#![feature(libc)]
#![feature(convert)]

extern crate libc;

pub mod apr;
pub mod ap_exports;

pub mod util_filter;
pub mod httpd;

pub mod ap_mmn;
pub mod http_config;

pub mod http_protocol;

pub mod wrapper;

use libc::{c_void, c_char, c_int};

use std::ptr;
use std::ffi::CString;

use apr::raw::{apr_pool_t, APR_HOOK_MIDDLE};

use httpd::raw::{request_rec};
use httpd::Status;
use ap_exports::raw::{ap_hook_handler};
use http_config::raw::{command_rec};
use http_protocol::raw::{ap_rwrite};

macro_rules! module_def {
   ($module:ident, $handler:ident, $c_name:expr) => {
      const C_NAME: &'static [u8] = $c_name;
      const C_NAME_PTR: *const &'static [u8] = &C_NAME;
      const C_NAME_CHAR_PTR: *const c_char = C_NAME_PTR as *const c_char;

      #[no_mangle]
      pub static mut $module: http_config::raw::module = http_config::raw::module {
         version: ap_mmn::raw::MODULE_MAGIC_NUMBER_MAJOR,
         minor_version: ap_mmn::raw::MODULE_MAGIC_NUMBER_MINOR,
         module_index: -1,
         name: C_NAME_CHAR_PTR,
         dynamic_load_handle: 0 as *mut c_void,
         next: 0 as *mut http_config::raw::module,
         magic: ap_mmn::raw::MODULE_MAGIC_COOKIE,
         rewrite_args: None,
         create_dir_config: None,
         merge_dir_config: None,
         create_server_config: None,
         merge_server_config: None,
         cmds: 0 as *const command_rec,
         register_hooks: Some(module_hooks),
      };

      extern "C" fn module_hooks(_: *mut apr_pool_t) {
         unsafe {
            ap_hook_handler(
               Some($handler), ptr::null(), ptr::null(), APR_HOOK_MIDDLE
            );
         }
      }

   }
}

module_def!(aprust_module, aprust_handler, b"mod_aprust\0");

fn rwrite<T: Into<Vec<u8>>>(t: T, r: *mut request_rec) {
   let s = CString::new(t).unwrap();
   let len = s.to_bytes().len();

   unsafe {
      ap_rwrite(s.as_ptr() as *mut c_void, len as i32, r);
   }
}

fn dump_str<T: Into<Vec<u8>>>(r: *mut request_rec, name: T, optional: Option<&str>) {
   rwrite("
", r);
   rwrite(name, r);
   rwrite(": ", r);

   match optional {
      None => {
         rwrite("NULL", r);
      },
      Some(slice) => {
         let html = format!("{:?}", slice);
         rwrite(html, r);
      }
   };

   rwrite("
", r);
}

#[no_mangle]
pub extern "C" fn aprust_handler(r: *mut request_rec) -> c_int {
   let req = httpd::Request::from_raw_ptr(r).unwrap();

   let mut headers_out = req.headers_out().unwrap();
   headers_out.set("Test-Key", "Hello");

   let headers_in = req.headers_in().unwrap();
   rwrite("<meta charset=\"utf-8\">", r);

   dump_str(r, "Cookie", headers_in.get("Cookie"));

   dump_str(r, "the_request", req.the_request());
   dump_str(r, "protocol", req.protocol());
   dump_str(r, "hostname", req.hostname());
   dump_str(r, "status_line", req.status_line());
   dump_str(r, "method", req.method());
   dump_str(r, "range", req.range());
   dump_str(r, "content_type", req.content_type());
   dump_str(r, "handler", req.handler());
   dump_str(r, "content_encoding", req.content_encoding());
   dump_str(r, "vlist_validator", req.vlist_validator());
   dump_str(r, "user", req.user());
   dump_str(r, "ap_auth_type", req.ap_auth_type());
   dump_str(r, "unparsed_uri", req.unparsed_uri());
   dump_str(r, "uri", req.uri());
   dump_str(r, "filename", req.filename());
   dump_str(r, "canonical_filename", req.canonical_filename());
   dump_str(r, "path_info", req.path_info());
   dump_str(r, "args", req.args());
   dump_str(r, "log_id", req.log_id());
   dump_str(r, "useragent_ip", req.useragent_ip());

   rwrite("", r);

   let status = Status::OK;

   status.into()
}
<commit_msg>Pure Rust handler.<commit_after>#![feature(libc)]
#![feature(convert)]

extern crate libc;

pub mod apr;
pub mod ap_exports;

pub mod util_filter;
pub mod httpd;

pub mod ap_mmn;
pub mod http_config;

pub mod http_protocol;

pub mod wrapper;

use libc::{c_void, c_char, c_int};

use std::ptr;
use std::ffi::CString;

use apr::raw::{apr_pool_t, APR_HOOK_MIDDLE};

use httpd::raw::{request_rec};
use ap_exports::raw::{ap_hook_handler};
use http_config::raw::{command_rec};
use http_protocol::raw::{ap_rwrite};

macro_rules! module_def {
   ($module:ident, $handler:ident, $c_name:expr) => {
      const C_NAME: &'static [u8] = $c_name;
      const C_NAME_PTR: *const &'static [u8] = &C_NAME;
      const C_NAME_CHAR_PTR: *const c_char = C_NAME_PTR as *const c_char;

      #[no_mangle]
      pub static mut $module: http_config::raw::module = http_config::raw::module {
         version: ap_mmn::raw::MODULE_MAGIC_NUMBER_MAJOR,
         minor_version: ap_mmn::raw::MODULE_MAGIC_NUMBER_MINOR,
         module_index: -1,
         name: C_NAME_CHAR_PTR,
         dynamic_load_handle: 0 as *mut c_void,
         next: 0 as *mut http_config::raw::module,
         magic: ap_mmn::raw::MODULE_MAGIC_COOKIE,
         rewrite_args: None,
         create_dir_config: None,
         merge_dir_config: None,
         create_server_config: None,
         merge_server_config: None,
         cmds: 0 as *const command_rec,
         register_hooks: Some(c_module_hooks),
      };

      extern "C" fn c_module_hooks(_: *mut apr_pool_t) {
         unsafe {
            ap_hook_handler(
               Some(c_module_handler), ptr::null(), ptr::null(), APR_HOOK_MIDDLE
            );
         }
      }

      #[no_mangle]
      pub extern "C" fn c_module_handler(r: *mut request_rec) -> c_int {
         match httpd::Request::from_raw_ptr(r) {
            None => httpd::Status::DECLINED.into(),
            Some(request) => $handler(&request).into()
         }
      }
   }
}

module_def!(aprust_module, aprust_handler, b"mod_aprust\0");

fn rwrite<T: Into<Vec<u8>>>(t: T, req: &httpd::Request) {
   let s = CString::new(t).unwrap();
   let len = s.to_bytes().len();

   unsafe {
      ap_rwrite(s.as_ptr() as *mut c_void, len as i32, req.raw);
   }
}

fn dump_str<T: Into<Vec<u8>>>(req: &httpd::Request, name: T, optional: Option<&str>) {
   rwrite("
", req);
   rwrite(name, req);
   rwrite(": ", req);

   match optional {
      None => {
         rwrite("NULL", req);
      },
      Some(slice) => {
         let html = format!("{:?}", slice);
         rwrite(html, req);
      }
   };

   rwrite("
", req);
}

fn aprust_handler(req: &httpd::Request) -> httpd::Status {
   let mut headers_out = req.headers_out().unwrap();
   headers_out.set("Test-Key", "Hello");

   let headers_in = req.headers_in().unwrap();
   rwrite("<meta charset=\"utf-8\">", req);

   dump_str(req, "Cookie", headers_in.get("Cookie"));

   dump_str(req, "the_request", req.the_request());
   dump_str(req, "protocol", req.protocol());
   dump_str(req, "hostname", req.hostname());
   dump_str(req, "status_line", req.status_line());
   dump_str(req, "method", req.method());
   dump_str(req, "range", req.range());
   dump_str(req, "content_type", req.content_type());
   dump_str(req, "handler", req.handler());
   dump_str(req, "content_encoding", req.content_encoding());
   dump_str(req, "vlist_validator", req.vlist_validator());
   dump_str(req, "user", req.user());
   dump_str(req, "ap_auth_type", req.ap_auth_type());
   dump_str(req, "unparsed_uri", req.unparsed_uri());
   dump_str(req, "uri", req.uri());
   dump_str(req, "filename", req.filename());
   dump_str(req, "canonical_filename", req.canonical_filename());
   dump_str(req, "path_info", req.path_info());
   dump_str(req, "args", req.args());
   dump_str(req, "log_id", req.log_id());
   dump_str(req, "useragent_ip", req.useragent_ip());

   rwrite("", req);

   httpd::Status::OK
}
<|endoftext|>