<commit_before>//! Tokio-based [EventStore](https://geteventstore.com/) client library in it's early stages.
//! Currently the most interesting API is the `tokio_service::service::Service` implemented by
//! `client::Client`, which allows sending values of `Package` to get back a `Future` of a response
//! `Package`. `Package` is the name for a frame in the protocol. See it's documentation for more
//! information.
//!
//! You can build values of `Package` using `builder::Builder` and it's functions. Actual payloads
//! are described as `Message` enum.
//!
//! The protocol is multiplexed so you can have multiple (hard limit is 128 currently) calls going
//! at any point in time. Current implementation is based on `tokio_proto::multiplex`, at the
//! moment using a custom fork. It does not yet support `tokio_proto::streaming::multiplex` which is
//! needed to support subscriptions.
//!
//! # Panics
//!
//! There should not be any panicing now that `adapted` and `raw` are separate.
//!
//! # Simplest example
//!
//! Example of writing to the database and simple handling of the response.
//!
//! ```no_run
//! extern crate futures;
//! extern crate tokio_core;
//! extern crate tokio_proto;
//! extern crate tokio_service;
//! extern crate eventstore_tcp;
//!
//! use std::net::SocketAddr;
//! use futures::Future;
//! use tokio_core::reactor::Core;
//! use tokio_service::Service;
//!
//! use eventstore_tcp::{EventStoreClient, Builder, AdaptedMessage, StreamVersion, ContentType};
//!
//! fn main() {
//!     let addr = "127.0.0.1:1113".parse::<SocketAddr>().unwrap();
//!     let mut core = Core::new().unwrap();
//!
//!     // connecting the client returns a future for an EventStoreClient
//!     // which implements tokio_service::Service
//!     let client = EventStoreClient::connect(&addr, &core.handle());
//!
//!     let value = client.and_then(|client| {
//!         // once the connection is made and EventStoreClient (`client`)
//!         // is created, send a WriteEvents request:
//!         client.call(Builder::write_events()
//!             .stream_id("my_stream-1")
//!             .expected_version(StreamVersion::from(42))
//!             .new_event()
//!                 .event_type("meaning_of_life")
//!                 .data("{ 'meaning': 42 }".as_bytes())
//!                 .data_content_type(ContentType::Json)
//!             .done()
//!             .build_package(None, None))
//!
//!         // call returns a future representing the response
//!     }).and_then(|resp| {
//!         // By default, `resp` is a `Package` that contains the raw protobuf defined message
//!         // (`RawMessage`). It is possible to refine it into AdaptedMessage which can fail:
//!         match resp.message.try_adapt().unwrap() {
//!             AdaptedMessage::WriteEventsCompleted(Ok(_)) =>
//!                 println!("Event was written successfully"),
//!             AdaptedMessage::WriteEventsCompleted(Err(fail)) =>
//!                 println!("Event writing failed: {:?}", fail),
//!             unexpected => println!("Unexpected response: {:#?}", unexpected),
//!         };
//!
//!         Ok(())
//!     });
//!
//!     core.run(value).unwrap();
//! }
//! ```
//!
//! More examples can be found in the aspiring command line tool under `examples/testclient`.
#![deny(missing_docs)]

#[macro_use]
extern crate bitflags;
extern crate quick_protobuf;
extern crate uuid;
extern crate byteorder;
#[macro_use]
extern crate error_chain;
extern crate futures;
extern crate tokio_io;
extern crate tokio_core;
extern crate tokio_proto;
extern crate tokio_service;
extern crate bytes;
#[macro_use]
extern crate derive_more;

#[cfg(test)]
extern crate rustc_serialize;

use std::str;

pub mod raw;
pub use raw::RawMessage;
pub use raw::client_messages::{WriteEvents, ResolvedIndexedEvent, EventRecord, ReadAllEvents};
pub use raw::client_messages::mod_NotHandled::{NotHandledReason, MasterInfo};

pub mod adapted;
pub use adapted::AdaptedMessage;

pub mod package;
pub use package::Package;

pub mod codec;

mod client;
pub use client::EventStoreClient;

pub mod builder;
pub use builder::Builder;

mod auth;
pub use auth::UsernamePassword;

mod errors {
    use std::str;
    use std::io;
    use std::fmt;

    /// Enum describing the locations where a result value can be missing
    #[derive(Debug, PartialEq)]
    pub enum ResultStatusKind {
        /// Missing from WriteEventsCompleted
        WriteEvents,
        /// Missing from ReadEventCompleted
        ReadEvent,
        /// Missing from ReadStreamEventsCompleted
        ReadStream,
    }

    impl fmt::Display for ResultStatusKind {
        fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
            use self::ResultStatusKind::*;
            write!(fmt, "{}", match self {
                &WriteEvents => "WriteEventsCompleted::result",
                &ReadEvent => "ReadEventCompleted::result",
                &ReadStream => "ReadStreamEventsCompleted::result",
            })
        }
    }

    error_chain! {
        foreign_links {
            InvalidUtf8(str::Utf8Error);
        }

        errors {
            InvalidFlags(flags: u8) {
                display("Invalid flags: 0x{:02x}", flags)
            }
            MissingResultField(which: ResultStatusKind) {
                display("Missing result field: {}", which)
            }
            InvalidStreamVersion(value: i32) {
                display("Invalid StreamVersion: {}", value)
            }
            InvalidEventNumber(value: i32) {
                display("Invalid EventNumber: {}", value)
            }
            InvalidLogPosition(value: i64) {
                display("Invalid LogPosition: {}", value)
            }
            UnsupportedDiscriminator(d: u8) {
                display("Unsupported discriminator 0x{:02x}", d)
            }
            UnimplementedConversion {
                display("Unimplemented conversion")
            }
            WriteEventsInvalidTransaction {
                display("Unexpected WriteEvents result: InvalidTransaction")
            }
        }
    }

    impl Into<io::Error> for Error {
        fn into(self) -> io::Error {
            io::Error::new(io::ErrorKind::Other, self)
        }
    }

    impl Into<io::Error> for ErrorKind {
        fn into(self) -> io::Error {
            Error::from(self).into()
        }
    }
}

use self::errors::{Error, ErrorKind};

/// The direction in which events are read.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ReadDirection {
    /// Read from first (event 0) to the latest
    Forward,
    /// Read from latest (highest event number) to the first (event 0)
    Backward
}

impl Copy for ReadDirection {}

/// `ExpectedVersion` represents the different modes of optimistic locking when writing to a stream
/// using `WriteEventsBuilder`.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ExpectedVersion {
    /// No optimistic locking
    Any,
    /// Expect a stream not to exist
    NewStream,
    /// Expect exact number of events in the stream
    Exact(StreamVersion)
}

impl Copy for ExpectedVersion {}

impl Into<i32> for ExpectedVersion {
    /// Returns the wire representation.
    fn into(self) -> i32 {
        use self::ExpectedVersion::*;
        match self {
            Any => -2,
            NewStream => -1,
            Exact(ver) => ver.into()
        }
    }
}

impl From<StreamVersion> for ExpectedVersion {
    fn from(ver: StreamVersion) -> Self {
        ExpectedVersion::Exact(ver)
    }
}

impl CustomTryFrom<i32> for ExpectedVersion {
    type Err = Error;

    fn try_from(val: i32) -> Result<ExpectedVersion, (i32, Self::Err)> {
        let ver = StreamVersion::try_from(val)?;
        Ok(ExpectedVersion::from(ver))
    }
}

/// `StreamVersion` represents the valid values for a stream version which is the same as the
/// event number of the latest event. As such, values are non-negative integers up to
/// `i32::max_value`. Negative values of `i32` have special meaning in the protocol, and are
/// restricted from being used with this type.
///
/// Conversions to StreamVersion are quite horrible until TryFrom is stabilized.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct StreamVersion(u32);

impl Copy for StreamVersion {}

impl StreamVersion {
    /// Converts the value to a StreamVersion or panics if the value is out of range
    pub fn from(version: u32) -> Self {
        Self::from_opt(version).expect("StreamVersion overflow")
    }

    /// Converts the value to a StreamVersion returning None if the input is out of range.
    pub fn from_opt(version: u32) -> Option<Self> {
        // TODO: MAX_VALUE might be some magical value, should be lower?
        if version < i32::max_value() as u32 {
            Some(StreamVersion(version))
        } else {
            None
        }
    }

    #[doc(hidden)]
    pub fn from_i32(version: i32) -> Self {
        Self::try_from(version).unwrap()

    }

    #[doc(hidden)]
    pub fn from_i32_opt(version: i32) -> Option<Self> {
        Self::try_from(version).ok()
    }
}

impl CustomTryFrom<i32> for StreamVersion {
    type Err = Error;

    fn try_from(val: i32) -> Result<Self, (i32, Self::Err)> {
        if val < 0 {
            Err((val, ErrorKind::InvalidStreamVersion(val).into()))
        } else {
            Ok(StreamVersion(val as u32))
        }
    }
}

impl Into<i32> for StreamVersion {
    /// Returns the wire representation.
    fn into(self) -> i32 {
        self.0 as i32
    }
}

/// `EventNumber` is similar to `StreamVersion` and `ExpectedVersion` but is used when specifying a
/// position to read from in the stream. Allows specifying the first or last (when reading
/// backwards) event in addition to exact event number.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EventNumber {
    /// The first event in a stream
    First,
    /// Exactly the given event number
    Exact(StreamVersion),
    /// The last event in a stream
    Last,
}

impl Copy for EventNumber {}

impl From<StreamVersion> for EventNumber {
    fn from(ver: StreamVersion) -> Self {
        EventNumber::Exact(ver)
    }
}

impl CustomTryFrom<i32> for EventNumber {
    type Err = Error;

    fn try_from(val: i32) -> Result<Self, (i32, Self::Err)> {
        match val {
            0 => Ok(EventNumber::First),
            -1 => Ok(EventNumber::Last),
            x if x > 0 => Ok(EventNumber::Exact(StreamVersion::from_i32(x))),
            invalid => {
                Err((invalid, ErrorKind::InvalidEventNumber(val).into()))
            }
        }
    }
}

impl Into<i32> for EventNumber {
    /// Returns the wire representation.
    fn into(self) -> i32 {
        match self {
            EventNumber::First => 0,
            EventNumber::Exact(x) => x.into(),
            EventNumber::Last => -1
        }
    }
}

/// Content type of the event `data` or `metadata`.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ContentType {
    /// Raw bytes
    Bytes,
    /// JSON values usable with projections in EventStore
    Json
}

impl Copy for ContentType {}

impl Into<i32> for ContentType {
    fn into(self) -> i32 {
        match self {
            ContentType::Bytes => 0,
            ContentType::Json => 1,
        }
    }
}

/// Global unique position in the EventStore, used when reading all events.
/// Range -1..i64::max_value()
#[derive(Debug, Clone, Eq, PartialOrd, Ord)]
pub enum LogPosition {
    /// The first event ever
    First,
    /// Exact position
    Exact(u64),
    /// The last event written to the database at the moment
    Last,
}

impl Copy for LogPosition {}

impl PartialEq<LogPosition> for LogPosition {
    fn eq(&self, other: &LogPosition) -> bool {
        let left: i64 = (*self).into();
        let right: i64 = (*other).into();
        left == right
    }
}

impl From<i64> for LogPosition {
    fn from(val: i64) -> LogPosition {
        match LogPosition::from_i64_opt(val) {
            Some(x) => x,
            None => panic!("LogPosition undeflow: {}", val),
        }
    }
}

impl CustomTryFrom<i64> for LogPosition {
    type Err = Error;

    fn try_from(val: i64) -> Result<Self, (i64, Self::Err)> {
        match val {
            0 => Ok(LogPosition::First),
            -1 => Ok(LogPosition::Last),
            pos => {
                if pos > 0 {
                    Ok(LogPosition::Exact(pos as u64))
                } else {
                    Err((pos, ErrorKind::InvalidLogPosition(pos).into()))
                }
            }
        }
    }
}

impl Into<i64> for LogPosition {
    fn into(self) -> i64 {
        match self {
            LogPosition::First => 0,
            LogPosition::Exact(x) => x as i64,
            LogPosition::Last => -1,
        }
    }
}

impl LogPosition {
    /// Wraps the value into LogPosition or None, if it is larger than i64
    pub fn from_opt(pos: u64) -> Option<LogPosition> {
        match pos {
            0 => Some(LogPosition::First),
            pos => {
                if pos < i64::max_value() as u64 {
                    Some(LogPosition::Exact(pos))
                } else {
                    None
                }
            }
        }
    }

    #[doc(hidden)]
    pub fn from_i64_opt(pos: i64) -> Option<LogPosition> {
        Self::try_from(pos).ok()
    }
}

trait CustomTryFrom<T: Sized>: Sized {
    type Err;

    fn try_from(t: T) -> Result<Self, (T, Self::Err)>;
}

trait CustomTryInto<T: Sized>: Sized {
    type Err;

    fn try_into(self) -> Result<T, (Self, Self::Err)>;
}

impl<T, U> CustomTryInto<U> for T where U: CustomTryFrom<T> {
    type Err = U::Err;

    fn try_into(self) -> Result<U, (T, Self::Err)> {
        U::try_from(self)
    }
}
<commit_msg>misc-cleanup: Replace Into Trait impls by From Trait impls<commit_after>//! Tokio-based [EventStore](https://geteventstore.com/) client library in it's early stages.
//! Currently the most interesting API is the `tokio_service::service::Service` implemented by
//! `client::Client`, which allows sending values of `Package` to get back a `Future` of a response
//! `Package`. `Package` is the name for a frame in the protocol. See it's documentation for more
//! information.
//!
//! You can build values of `Package` using `builder::Builder` and it's functions. Actual payloads
//! are described as `Message` enum.
//!
//! The protocol is multiplexed so you can have multiple (hard limit is 128 currently) calls going
//! at any point in time. Current implementation is based on `tokio_proto::multiplex`, at the
//! moment using a custom fork. It does not yet support `tokio_proto::streaming::multiplex` which is
//! needed to support subscriptions.
//!
//! # Panics
//!
//! There should not be any panicing now that `adapted` and `raw` are separate.
//!
//! # Simplest example
//!
//! Example of writing to the database and simple handling of the response.
//!
//! ```no_run
//! extern crate futures;
//! extern crate tokio_core;
//! extern crate tokio_proto;
//! extern crate tokio_service;
//! extern crate eventstore_tcp;
//!
//! use std::net::SocketAddr;
//! use futures::Future;
//! use tokio_core::reactor::Core;
//! use tokio_service::Service;
//!
//! use eventstore_tcp::{EventStoreClient, Builder, AdaptedMessage, StreamVersion, ContentType};
//!
//! fn main() {
//!     let addr = "127.0.0.1:1113".parse::<SocketAddr>().unwrap();
//!     let mut core = Core::new().unwrap();
//!
//!     // connecting the client returns a future for an EventStoreClient
//!     // which implements tokio_service::Service
//!     let client = EventStoreClient::connect(&addr, &core.handle());
//!
//!     let value = client.and_then(|client| {
//!         // once the connection is made and EventStoreClient (`client`)
//!         // is created, send a WriteEvents request:
//!         client.call(Builder::write_events()
//!             .stream_id("my_stream-1")
//!             .expected_version(StreamVersion::from(42))
//!             .new_event()
//!                 .event_type("meaning_of_life")
//!                 .data("{ 'meaning': 42 }".as_bytes())
//!                 .data_content_type(ContentType::Json)
//!             .done()
//!             .build_package(None, None))
//!
//!         // call returns a future representing the response
//!     }).and_then(|resp| {
//!         // By default, `resp` is a `Package` that contains the raw protobuf defined message
//!         // (`RawMessage`). It is possible to refine it into AdaptedMessage which can fail:
//!         match resp.message.try_adapt().unwrap() {
//!             AdaptedMessage::WriteEventsCompleted(Ok(_)) =>
//!                 println!("Event was written successfully"),
//!             AdaptedMessage::WriteEventsCompleted(Err(fail)) =>
//!                 println!("Event writing failed: {:?}", fail),
//!             unexpected => println!("Unexpected response: {:#?}", unexpected),
//!         };
//!
//!         Ok(())
//!     });
//!
//!     core.run(value).unwrap();
//! }
//! ```
//!
//! More examples can be found in the aspiring command line tool under `examples/testclient`.
#![deny(missing_docs)]

#[macro_use]
extern crate bitflags;
extern crate quick_protobuf;
extern crate uuid;
extern crate byteorder;
#[macro_use]
extern crate error_chain;
extern crate futures;
extern crate tokio_io;
extern crate tokio_core;
extern crate tokio_proto;
extern crate tokio_service;
extern crate bytes;
#[macro_use]
extern crate derive_more;

#[cfg(test)]
extern crate rustc_serialize;

use std::str;

pub mod raw;
pub use raw::RawMessage;
pub use raw::client_messages::{WriteEvents, ResolvedIndexedEvent, EventRecord, ReadAllEvents};
pub use raw::client_messages::mod_NotHandled::{NotHandledReason, MasterInfo};

pub mod adapted;
pub use adapted::AdaptedMessage;

pub mod package;
pub use package::Package;

pub mod codec;

mod client;
pub use client::EventStoreClient;

pub mod builder;
pub use builder::Builder;

mod auth;
pub use auth::UsernamePassword;

mod errors {
    use std::str;
    use std::io;
    use std::fmt;

    /// Enum describing the locations where a result value can be missing
    #[derive(Debug, PartialEq)]
    pub enum ResultStatusKind {
        /// Missing from WriteEventsCompleted
        WriteEvents,
        /// Missing from ReadEventCompleted
        ReadEvent,
        /// Missing from ReadStreamEventsCompleted
        ReadStream,
    }

    impl fmt::Display for ResultStatusKind {
        fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
            use self::ResultStatusKind::*;
            write!(fmt, "{}", match self {
                &WriteEvents => "WriteEventsCompleted::result",
                &ReadEvent => "ReadEventCompleted::result",
                &ReadStream => "ReadStreamEventsCompleted::result",
            })
        }
    }

    error_chain! {
        foreign_links {
            InvalidUtf8(str::Utf8Error);
        }

        errors {
            InvalidFlags(flags: u8) {
                display("Invalid flags: 0x{:02x}", flags)
            }
            MissingResultField(which: ResultStatusKind) {
                display("Missing result field: {}", which)
            }
            InvalidStreamVersion(value: i32) {
                display("Invalid StreamVersion: {}", value)
            }
            InvalidEventNumber(value: i32) {
                display("Invalid EventNumber: {}", value)
            }
            InvalidLogPosition(value: i64) {
                display("Invalid LogPosition: {}", value)
            }
            UnsupportedDiscriminator(d: u8) {
                display("Unsupported discriminator 0x{:02x}", d)
            }
            UnimplementedConversion {
                display("Unimplemented conversion")
            }
            WriteEventsInvalidTransaction {
                display("Unexpected WriteEvents result: InvalidTransaction")
            }
        }
    }

    impl Into<io::Error> for Error {
        fn into(self) -> io::Error {
            io::Error::new(io::ErrorKind::Other, self)
        }
    }

    impl Into<io::Error> for ErrorKind {
        fn into(self) -> io::Error {
            Error::from(self).into()
        }
    }
}

use self::errors::{Error, ErrorKind};

/// The direction in which events are read.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ReadDirection {
    /// Read from first (event 0) to the latest
    Forward,
    /// Read from latest (highest event number) to the first (event 0)
    Backward
}

impl Copy for ReadDirection {}

/// `ExpectedVersion` represents the different modes of optimistic locking when writing to a stream
/// using `WriteEventsBuilder`.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ExpectedVersion {
    /// No optimistic locking
    Any,
    /// Expect a stream not to exist
    NewStream,
    /// Expect exact number of events in the stream
    Exact(StreamVersion)
}

impl Copy for ExpectedVersion {}

impl Into<i32> for ExpectedVersion {
    /// Returns the wire representation.
    fn into(self) -> i32 {
        use self::ExpectedVersion::*;
        match self {
            Any => -2,
            NewStream => -1,
            Exact(ver) => ver.into()
        }
    }
}

impl From<StreamVersion> for ExpectedVersion {
    fn from(ver: StreamVersion) -> Self {
        ExpectedVersion::Exact(ver)
    }
}

impl CustomTryFrom<i32> for ExpectedVersion {
    type Err = Error;

    fn try_from(val: i32) -> Result<ExpectedVersion, (i32, Self::Err)> {
        let ver = StreamVersion::try_from(val)?;
        Ok(ExpectedVersion::from(ver))
    }
}

/// `StreamVersion` represents the valid values for a stream version which is the same as the
/// event number of the latest event. As such, values are non-negative integers up to
/// `i32::max_value`. Negative values of `i32` have special meaning in the protocol, and are
/// restricted from being used with this type.
///
/// Conversions to StreamVersion are quite horrible until TryFrom is stabilized.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct StreamVersion(u32);

impl Copy for StreamVersion {}

impl StreamVersion {
    /// Converts the value to a StreamVersion or panics if the value is out of range
    pub fn from(version: u32) -> Self {
        Self::from_opt(version).expect("StreamVersion overflow")
    }

    /// Converts the value to a StreamVersion returning None if the input is out of range.
    pub fn from_opt(version: u32) -> Option<Self> {
        // TODO: MAX_VALUE might be some magical value, should be lower?
        if version < i32::max_value() as u32 {
            Some(StreamVersion(version))
        } else {
            None
        }
    }

    #[doc(hidden)]
    pub fn from_i32(version: i32) -> Self {
        Self::try_from(version).unwrap()

    }

    #[doc(hidden)]
    pub fn from_i32_opt(version: i32) -> Option<Self> {
        Self::try_from(version).ok()
    }
}

impl CustomTryFrom<i32> for StreamVersion {
    type Err = Error;

    fn try_from(val: i32) -> Result<Self, (i32, Self::Err)> {
        if val < 0 {
            Err((val, ErrorKind::InvalidStreamVersion(val).into()))
        } else {
            Ok(StreamVersion(val as u32))
        }
    }
}

impl Into<i32> for StreamVersion {
    /// Returns the wire representation.
    fn into(self) -> i32 {
        self.0 as i32
    }
}

/// `EventNumber` is similar to `StreamVersion` and `ExpectedVersion` but is used when specifying a
/// position to read from in the stream. Allows specifying the first or last (when reading
/// backwards) event in addition to exact event number.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EventNumber {
    /// The first event in a stream
    First,
    /// Exactly the given event number
    Exact(StreamVersion),
    /// The last event in a stream
    Last,
}

impl Copy for EventNumber {}

impl From<StreamVersion> for EventNumber {
    fn from(ver: StreamVersion) -> Self {
        EventNumber::Exact(ver)
    }
}

impl CustomTryFrom<i32> for EventNumber {
    type Err = Error;

    fn try_from(val: i32) -> Result<Self, (i32, Self::Err)> {
        match val {
            0 => Ok(EventNumber::First),
            -1 => Ok(EventNumber::Last),
            x if x > 0 => Ok(EventNumber::Exact(StreamVersion::from_i32(x))),
            invalid => {
                Err((invalid, ErrorKind::InvalidEventNumber(val).into()))
            }
        }
    }
}

impl From<EventNumber> for i32 {
    fn from(number: EventNumber) -> Self {
        match number {
            EventNumber::First => 0,
            EventNumber::Exact(x) => x.into(),
            EventNumber::Last => -1
        }
    }
}

/// Content type of the event `data` or `metadata`.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ContentType {
    /// Raw bytes
    Bytes,
    /// JSON values usable with projections in EventStore
    Json
}

impl Copy for ContentType {}

impl From<ContentType> for i32 {
    fn from(ctype: ContentType) -> Self {
        match ctype {
            ContentType::Bytes => 0,
            ContentType::Json => 1,
        }
    }
}

/// Global unique position in the EventStore, used when reading all events.
/// Range -1..i64::max_value()
#[derive(Debug, Clone, Eq, PartialOrd, Ord)]
pub enum LogPosition {
    /// The first event ever
    First,
    /// Exact position
    Exact(u64),
    /// The last event written to the database at the moment
    Last,
}

impl Copy for LogPosition {}

impl PartialEq<LogPosition> for LogPosition {
    fn eq(&self, other: &LogPosition) -> bool {
        let left: i64 = (*self).into();
        let right: i64 = (*other).into();
        left == right
    }
}

impl From<i64> for LogPosition {
    fn from(val: i64) -> LogPosition {
        match LogPosition::from_i64_opt(val) {
            Some(x) => x,
            None => panic!("LogPosition undeflow: {}", val),
        }
    }
}

impl CustomTryFrom<i64> for LogPosition {
    type Err = Error;

    fn try_from(val: i64) -> Result<Self, (i64, Self::Err)> {
        match val {
            0 => Ok(LogPosition::First),
            -1 => Ok(LogPosition::Last),
            pos => {
                if pos > 0 {
                    Ok(LogPosition::Exact(pos as u64))
                } else {
                    Err((pos, ErrorKind::InvalidLogPosition(pos).into()))
                }
            }
        }
    }
}

impl Into<i64> for LogPosition {
    fn into(self) -> i64 {
        match self {
            LogPosition::First => 0,
            LogPosition::Exact(x) => x as i64,
            LogPosition::Last => -1,
        }
    }
}

impl LogPosition {
    /// Wraps the value into LogPosition or None, if it is larger than i64
    pub fn from_opt(pos: u64) -> Option<LogPosition> {
        match pos {
            0 => Some(LogPosition::First),
            pos => {
                if pos < i64::max_value() as u64 {
                    Some(LogPosition::Exact(pos))
                } else {
                    None
                }
            }
        }
    }

    #[doc(hidden)]
    pub fn from_i64_opt(pos: i64) -> Option<LogPosition> {
        Self::try_from(pos).ok()
    }
}

trait CustomTryFrom<T: Sized>: Sized {
    type Err;

    fn try_from(t: T) -> Result<Self, (T, Self::Err)>;
}

trait CustomTryInto<T: Sized>: Sized {
    type Err;

    fn try_into(self) -> Result<T, (Self, Self::Err)>;
}

impl<T, U> CustomTryInto<U> for T where U: CustomTryFrom<T> {
    type Err = U::Err;

    fn try_into(self) -> Result<U, (T, Self::Err)> {
        U::try_from(self)
    }
}
<|endoftext|>


<commit_before>// (c) 2015 Joost Yervante Damad <joost@damad.be>

use std::fmt;
use std::fs::File;
use std::io::Read;

extern crate rustysexp;
use rustysexp::Sexp;
use rustysexp::Atom;

type ERes<T> = Result<T, &'static str>;

fn err<T>(msg: &'static str) -> ERes<T> { Err(msg) }

pub enum Element {
    Layer,
    Descr,
    FpText,
    Pad,
    FpPoly,
    FpLine,
    FpCircle
}

pub struct Module {
    name: String,
    elements: Vec<Element>
}

impl Module {
    fn new(name: &String) -> Module {
        Module { name: name.clone(), elements: vec![] }
    }
    fn append(&mut self, e: Element) {
        self.elements.push(e)
    }
}

impl fmt::Display for Module {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "(module {}\n", self.name));
        for e in &self.elements {
            try!(write!(f, "{}\n", e))
        };
        write!(f, ")")
    }
}

impl fmt::Display for Element {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Element::Layer => write!(f, "(layer)"),
            Element::Descr => write!(f, "(descr)"),
            Element::FpText => write!(f, "(fp_text)"),
            Element::Pad => write!(f, "(pad)"),
            Element::FpPoly => write!(f, "(fp_poly)"),
            Element::FpLine => write!(f, "(fp_line)"),
            Element::FpCircle => write!(f, "(fp_circle)"),
        }
    }
}

fn parse_layer(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::Layer)
}
fn parse_descr(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::Descr)
}
fn parse_fp_text(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::FpText)
}
fn parse_pad(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::Pad)
}
fn parse_fp_poly(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::FpPoly)
}
fn parse_fp_line(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::FpLine)
}
fn parse_fp_circle(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::FpCircle)
}

fn parse_element_list(v: &Vec<Sexp>) -> ERes<Element> {
    match v[0] {
        Sexp::Atom(Atom::S(ref s)) => {
            match &s[..] {
                "layer" => parse_layer(v),
                "descr" => parse_descr(v),
                "fp_text" => parse_fp_text(v),
                "pad" => parse_pad(v),
                "fp_poly" => parse_fp_poly(v),
                "fp_line" => parse_fp_line(v),
                "fp_circle" => parse_fp_circle(v),
                _ => err("unknown element in module")
            }
        }
        _ => err("expecting atom")
    }
}

fn parse_element(s: &Sexp) -> ERes<Element> {
    match *s {
        Sexp::List(ref v) => parse_element_list(&v),
        _ => err("expecting element list in module")
    }
}

fn parse_module_list(v: &Vec<Sexp>) -> ERes<Module> {
    let mut module = (match v[0] {
        Sexp::Atom(Atom::S(ref s)) if s == "module" => {
            match v[1] {
                Sexp::Atom(Atom::S(ref s)) => {
                    Ok(Module::new(s))
                }
                _ => return err("expecting module name")
            }
        }
        _ => err("expecting module")
    }).unwrap();
    for e in &v[2..] {
        let el = try!(parse_element(e));
        module.append(el)
    }
    Ok(module)
}

fn parse_module(s: Sexp) -> ERes<Module> {
    match s {
        Sexp::List(v) => parse_module_list(&v),
        _ => err("expecting top level list")
    }
}

fn parse(s: &str) -> ERes<Module> {
    match rustysexp::parse_str(s) {
        Ok(s) => parse_module(s),
        Err(x) => err("IOError") // TODO...
    }
}

fn read_file(name: &str) -> Result<String,std::io::Error> {
    let mut f = try!(File::open(name));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    Ok(s)
}

pub fn parse_str(s: &str) -> Module {
    parse(s).unwrap()
}

pub fn parse_file(name: &str) -> Module {
    let s = read_file(name).unwrap();
    parse(&s[..]).unwrap()
}

<commit_msg>error handling changes<commit_after>// (c) 2015 Joost Yervante Damad <joost@damad.be>

use std::fmt;
use std::fs::File;
use std::io::Read;

extern crate rustysexp;
use rustysexp::Sexp;
use rustysexp::Atom;

type ERes<T> = Result<T, String>;

fn err<T>(msg: &str) -> ERes<T> {
    Err(String::from(msg))
}

pub enum Element {
    Layer,
    Descr,
    FpText,
    Pad,
    FpPoly,
    FpLine,
    FpCircle
}

pub struct Module {
    name: String,
    elements: Vec<Element>
}

impl Module {
    fn new(name: &String) -> Module {
        Module { name: name.clone(), elements: vec![] }
    }
    fn append(&mut self, e: Element) {
        self.elements.push(e)
    }
}

impl fmt::Display for Module {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "(module {}\n", self.name));
        for e in &self.elements {
            try!(write!(f, "{}\n", e))
        };
        write!(f, ")")
    }
}

impl fmt::Display for Element {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Element::Layer => write!(f, "(layer)"),
            Element::Descr => write!(f, "(descr)"),
            Element::FpText => write!(f, "(fp_text)"),
            Element::Pad => write!(f, "(pad)"),
            Element::FpPoly => write!(f, "(fp_poly)"),
            Element::FpLine => write!(f, "(fp_line)"),
            Element::FpCircle => write!(f, "(fp_circle)"),
        }
    }
}

fn parse_layer(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::Layer)
}
fn parse_descr(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::Descr)
}
fn parse_fp_text(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::FpText)
}
fn parse_pad(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::Pad)
}
fn parse_fp_poly(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::FpPoly)
}
fn parse_fp_line(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::FpLine)
}
fn parse_fp_circle(v: &Vec<Sexp>) -> ERes<Element> {
    Ok(Element::FpCircle)
}

fn parse_element_list(v: &Vec<Sexp>) -> ERes<Element> {
    match v[0] {
        Sexp::Atom(Atom::S(ref s)) => {
            match &s[..] {
                "layer" => parse_layer(v),
                "descr" => parse_descr(v),
                "fp_text" => parse_fp_text(v),
                "pad" => parse_pad(v),
                "fp_poly" => parse_fp_poly(v),
                "fp_line" => parse_fp_line(v),
                "fp_circle" => parse_fp_circle(v),
                x => Err(format!("unknown element in module: {}", x))
            }
        }
        _ => err("expecting atom")
    }
}

fn parse_element(s: &Sexp) -> ERes<Element> {
    match *s {
        Sexp::List(ref v) => parse_element_list(&v),
        _ => err("expecting element list in module")
    }
}

fn parse_module_list(v: &Vec<Sexp>) -> ERes<Module> {
    let mut module = (match v[0] {
        Sexp::Atom(Atom::S(ref s)) if s == "module" => {
            match v[1] {
                Sexp::Atom(Atom::S(ref s)) => {
                    Ok(Module::new(s))
                }
                ref x => return Err(format!("expecting module name got {}", x))
            }
        }
        _ => err("expecting module")
    }).unwrap();
    for e in &v[2..] {
        let el = try!(parse_element(e));
        module.append(el)
    }
    Ok(module)
}

fn parse_module(s: Sexp) -> ERes<Module> {
    match s {
        Sexp::List(v) => parse_module_list(&v),
        _ => err("expecting top level list")
    }
}

fn parse(s: &str) -> ERes<Module> {
    match rustysexp::parse_str(s) {
        Ok(s) => parse_module(s),
        Err(x) => Err(format!("IOError: {}", x))
    }
}

fn read_file(name: &str) -> Result<String,std::io::Error> {
    let mut f = try!(File::open(name));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    Ok(s)
}

pub fn parse_str(s: &str) -> Module {
    parse(s).unwrap()
}

pub fn parse_file(name: &str) -> Module {
    let s = read_file(name).unwrap();
    parse(&s[..]).unwrap()
}

<|endoftext|>


<commit_before>//! Setup and control loop devices.
//!
//! Provides rust interface with similar functionalty to the linux utility `losetup`.
//!
//! # Examples
//!
//! ```rust
//! use loopdev::LoopControl;
//! let lc = LoopControl::open().unwrap();
//! let ld = lc.next_free().unwrap();
//!
//! println!("{}", ld.get_path().unwrap().display());
//!
//! ld.attach("test.img", 0).unwrap();
//! // ...
//! ld.detach().unwrap();
//! ```

extern crate libc;

use std::fs::OpenOptions;
use std::fs::File;

use std::os::unix::prelude::*;
use std::io;
use std::path::PathBuf;
use libc::{c_int, ioctl, uint8_t, uint32_t, uint64_t};
use std::default::Default;

static LOOP_SET_FD: u64 = 0x4C00;
static LOOP_CLR_FD: u64 = 0x4C01;
static LOOP_SET_STATUS64: u64 = 0x4C04;
static LOOP_CTL_GET_FREE: u64 = 0x4C82;

const LOOP_CONTROL: &'static str = "/dev/loop-control";
const LOOP_PREFIX: &'static str = "/dev/loop";

/// Interface to the loop control device: `/dev/loop-control`.
#[derive(Debug)]
pub struct LoopControl {
    dev_file: File,
}

impl LoopControl {
    /// Opens the loop control device.
    pub fn open() -> io::Result<LoopControl> {
        Ok(LoopControl {
            dev_file: try!(OpenOptions::new().read(true).write(true).open(LOOP_CONTROL)),
        })
    }

    /// Finds and opens the next available loop device.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopControl;
    /// let lc = LoopControl::open().unwrap();
    /// let ld = lc.next_free().unwrap();
    /// println!("{}", ld.get_path().unwrap().display());
    /// ```
    pub fn next_free(&self) -> io::Result<LoopDevice> {
        let result: i32;
        unsafe {
            result = ioctl(self.dev_file.as_raw_fd() as c_int, LOOP_CTL_GET_FREE);
        }
        if result < 0 {
            Err(io::Error::last_os_error())
        } else {
            let dev = LOOP_PREFIX.to_string() + &result.to_string();
            Ok(try!(LoopDevice::open(&dev)))
        }
    }
}

/// Interface to a loop device ie `/dev/loop0`.
#[derive(Debug)]
pub struct LoopDevice {
    device: File,
}

impl LoopDevice {
    /// Opens a loop device.
    pub fn open(dev: &str) -> io::Result<LoopDevice> {
        // TODO create dev if it does not exist and begins with LOOP_PREFIX
        let f = try!(OpenOptions::new().read(true).write(true).open(dev));
        Ok(LoopDevice { device: f })
    }

    /// Attach the loop device to a file starting at offset into the file.
    ///
    /// # Examples
    ///
    /// Attach the device to the start of a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop4").unwrap();
    /// ld.attach("test.img", 0).unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach(&self, backing_file: &str, offset: u64) -> io::Result<()> {
        let bf = try!(OpenOptions::new().read(true).write(true).open(backing_file));

        // Attach the file
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int,
                     LOOP_SET_FD,
                     bf.as_raw_fd() as c_int) < 0 {
                return Err(io::Error::last_os_error());
            }
        }

        // Set offset for backing_file
        let mut info: loop_info64 = Default::default();
        info.lo_offset = offset;
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int,
                     LOOP_SET_STATUS64,
                     &mut info) < 0 {
                try!(self.detach());
                return Err(io::Error::last_os_error());
            }
        }
        Ok(())
    }

    /// Get the path of the loop device.
    pub fn get_path(&self) -> Option<PathBuf> {
        let mut p = PathBuf::from("/proc/self/fd");
        p.push(self.device.as_raw_fd().to_string());
        std::fs::read_link(&p).ok()
    }

    /// Detach a loop device from its backing file.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop6").unwrap();
    /// # ld.attach("test.img", 0).unwrap();
    /// ld.detach().unwrap();
    /// ```
    pub fn detach(&self) -> io::Result<()> {
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int, LOOP_CLR_FD, 0) < 0 {
                return Err(io::Error::last_os_error());
            }
        }
        Ok(())
    }
}

#[repr(C)]
struct loop_info64 {
    pub lo_device: uint64_t,
    pub lo_inode: uint64_t,
    pub lo_rdevice: uint64_t,
    pub lo_offset: uint64_t,
    pub lo_sizelimit: uint64_t,
    pub lo_number: uint32_t,
    pub lo_encrypt_type: uint32_t,
    pub lo_encrypt_key_size: uint32_t,
    pub lo_flags: uint32_t,
    pub lo_file_name: [uint8_t; 64],
    pub lo_crypt_name: [uint8_t; 64],
    pub lo_encrypt_key: [uint8_t; 32],
    pub lo_init: [uint64_t; 2],
}

impl Default for loop_info64 {
    fn default() -> loop_info64 {
        loop_info64 {
            lo_device: 0,
            lo_inode: 0,
            lo_rdevice: 0,
            lo_offset: 0,
            lo_sizelimit: 0,
            lo_number: 0,
            lo_encrypt_type: 0,
            lo_encrypt_key_size: 0,
            lo_flags: 0,
            lo_file_name: [0; 64],
            lo_crypt_name: [0; 64],
            lo_encrypt_key: [0; 32],
            lo_init: [0; 2],
        }
    }
}
<commit_msg>Do not bother to specify type of result<commit_after>//! Setup and control loop devices.
//!
//! Provides rust interface with similar functionalty to the linux utility `losetup`.
//!
//! # Examples
//!
//! ```rust
//! use loopdev::LoopControl;
//! let lc = LoopControl::open().unwrap();
//! let ld = lc.next_free().unwrap();
//!
//! println!("{}", ld.get_path().unwrap().display());
//!
//! ld.attach("test.img", 0).unwrap();
//! // ...
//! ld.detach().unwrap();
//! ```

extern crate libc;

use std::fs::OpenOptions;
use std::fs::File;

use std::os::unix::prelude::*;
use std::io;
use std::path::PathBuf;
use libc::{c_int, ioctl, uint8_t, uint32_t, uint64_t};
use std::default::Default;

static LOOP_SET_FD: u64 = 0x4C00;
static LOOP_CLR_FD: u64 = 0x4C01;
static LOOP_SET_STATUS64: u64 = 0x4C04;
static LOOP_CTL_GET_FREE: u64 = 0x4C82;

const LOOP_CONTROL: &'static str = "/dev/loop-control";
const LOOP_PREFIX: &'static str = "/dev/loop";

/// Interface to the loop control device: `/dev/loop-control`.
#[derive(Debug)]
pub struct LoopControl {
    dev_file: File,
}

impl LoopControl {
    /// Opens the loop control device.
    pub fn open() -> io::Result<LoopControl> {
        Ok(LoopControl {
            dev_file: try!(OpenOptions::new().read(true).write(true).open(LOOP_CONTROL)),
        })
    }

    /// Finds and opens the next available loop device.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopControl;
    /// let lc = LoopControl::open().unwrap();
    /// let ld = lc.next_free().unwrap();
    /// println!("{}", ld.get_path().unwrap().display());
    /// ```
    pub fn next_free(&self) -> io::Result<LoopDevice> {
        let result;
        unsafe {
            result = ioctl(self.dev_file.as_raw_fd() as c_int, LOOP_CTL_GET_FREE);
        }
        if result < 0 {
            Err(io::Error::last_os_error())
        } else {
            let dev = LOOP_PREFIX.to_string() + &result.to_string();
            Ok(try!(LoopDevice::open(&dev)))
        }
    }
}

/// Interface to a loop device ie `/dev/loop0`.
#[derive(Debug)]
pub struct LoopDevice {
    device: File,
}

impl LoopDevice {
    /// Opens a loop device.
    pub fn open(dev: &str) -> io::Result<LoopDevice> {
        // TODO create dev if it does not exist and begins with LOOP_PREFIX
        let f = try!(OpenOptions::new().read(true).write(true).open(dev));
        Ok(LoopDevice { device: f })
    }

    /// Attach the loop device to a file starting at offset into the file.
    ///
    /// # Examples
    ///
    /// Attach the device to the start of a file.
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop4").unwrap();
    /// ld.attach("test.img", 0).unwrap();
    /// # ld.detach().unwrap();
    /// ```
    pub fn attach(&self, backing_file: &str, offset: u64) -> io::Result<()> {
        let bf = try!(OpenOptions::new().read(true).write(true).open(backing_file));

        // Attach the file
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int,
                     LOOP_SET_FD,
                     bf.as_raw_fd() as c_int) < 0 {
                return Err(io::Error::last_os_error());
            }
        }

        // Set offset for backing_file
        let mut info: loop_info64 = Default::default();
        info.lo_offset = offset;
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int,
                     LOOP_SET_STATUS64,
                     &mut info) < 0 {
                try!(self.detach());
                return Err(io::Error::last_os_error());
            }
        }
        Ok(())
    }

    /// Get the path of the loop device.
    pub fn get_path(&self) -> Option<PathBuf> {
        let mut p = PathBuf::from("/proc/self/fd");
        p.push(self.device.as_raw_fd().to_string());
        std::fs::read_link(&p).ok()
    }

    /// Detach a loop device from its backing file.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use loopdev::LoopDevice;
    /// let ld = LoopDevice::open("/dev/loop6").unwrap();
    /// # ld.attach("test.img", 0).unwrap();
    /// ld.detach().unwrap();
    /// ```
    pub fn detach(&self) -> io::Result<()> {
        unsafe {
            if ioctl(self.device.as_raw_fd() as c_int, LOOP_CLR_FD, 0) < 0 {
                return Err(io::Error::last_os_error());
            }
        }
        Ok(())
    }
}

#[repr(C)]
struct loop_info64 {
    pub lo_device: uint64_t,
    pub lo_inode: uint64_t,
    pub lo_rdevice: uint64_t,
    pub lo_offset: uint64_t,
    pub lo_sizelimit: uint64_t,
    pub lo_number: uint32_t,
    pub lo_encrypt_type: uint32_t,
    pub lo_encrypt_key_size: uint32_t,
    pub lo_flags: uint32_t,
    pub lo_file_name: [uint8_t; 64],
    pub lo_crypt_name: [uint8_t; 64],
    pub lo_encrypt_key: [uint8_t; 32],
    pub lo_init: [uint64_t; 2],
}

impl Default for loop_info64 {
    fn default() -> loop_info64 {
        loop_info64 {
            lo_device: 0,
            lo_inode: 0,
            lo_rdevice: 0,
            lo_offset: 0,
            lo_sizelimit: 0,
            lo_number: 0,
            lo_encrypt_type: 0,
            lo_encrypt_key_size: 0,
            lo_flags: 0,
            lo_file_name: [0; 64],
            lo_crypt_name: [0; 64],
            lo_encrypt_key: [0; 32],
            lo_init: [0; 2],
        }
    }
}
<|endoftext|>


<commit_before>//! Rust bindings to the libcurl C library
//!
//! This crate contains bindings for an HTTP/HTTPS client which is powered by
//! [libcurl], the same library behind the `curl` command line tool. The API
//! currently closely matches that of libcurl itself, except that a Rustic layer
//! of safety is applied on top.
//!
//! [libcurl]: https://curl.haxx.se/libcurl/
//!
//! # The "Easy" API
//!
//! The easiest way to send a request is to use the `Easy` api which corresponds
//! to `CURL` in libcurl. This handle supports a wide variety of options and can
//! be used to make a single blocking request in a thread. Callbacks can be
//! specified to deal with data as it arrives and a handle can be reused to
//! cache connections and such.
//!
//! ```rust,no_run
//! use std::io::{stdout, Write};
//!
//! use curl::easy::Easy;
//!
//! // Write the contents of rust-lang.org to stdout
//! let mut easy = Easy::new();
//! easy.url("https://www.rust-lang.org/").unwrap();
//! easy.write_function(|data| {
//!     Ok(stdout().write(data).unwrap())
//! }).unwrap();
//! easy.perform().unwrap();
//! ```
//!
//! # What about multiple concurrent HTTP requests?
//!
//! One option you have currently is to send multiple requests in multiple
//! threads, but otherwise libcurl has a "multi" interface for doing this
//! operation. Initial bindings of this interface can be found in the `multi`
//! module, but feedback is welcome!
//!
//! # Where does libcurl come from?
//!
//! This crate links to the `curl-sys` crate which is in turn responsible for
//! acquiring and linking to the libcurl library. Currently this crate will
//! build libcurl from source if one is not already detected on the system.
//!
//! There is a large number of releases for libcurl, all with different sets of
//! capabilities. Robust programs may wish to inspect `Version::get()` to test
//! what features are implemented in the linked build of libcurl at runtime.

#![deny(missing_docs)]

extern crate curl_sys;
extern crate libc;

#[cfg(all(unix, not(target_os = "macos")))]
extern crate openssl_sys;
#[cfg(windows)]
extern crate winapi;

use std::ffi::CStr;
use std::str;
use std::sync::{Once, ONCE_INIT};

pub use error::{Error, ShareError, MultiError, FormError};
mod error;

pub use version::{Version, Protocols};
mod version;

mod panic;
pub mod easy;
pub mod multi;

/// Initializes the underlying libcurl library.
///
/// It's not required to call this before the library is used, but it's
/// recommended to do so as soon as the program starts.
pub fn init() {
    static INIT: Once = ONCE_INIT;
    INIT.call_once(|| {
        platform_init();
        unsafe {
            curl_sys::curl_global_init(curl_sys::CURL_GLOBAL_ALL);
            libc::atexit(cleanup);
        }
    });

    extern fn cleanup() {
        unsafe { curl_sys::curl_global_cleanup(); }
    }

    #[cfg(all(unix, not(target_os = "macos")))]
    fn platform_init() {
        openssl_sys::init();
    }

    #[cfg(not(all(unix, not(target_os = "macos"))))]
    fn platform_init() {}
}

unsafe fn opt_str<'a>(ptr: *const libc::c_char) -> Option<&'a str> {
    if ptr.is_null() {
        None
    } else {
        Some(str::from_utf8(CStr::from_ptr(ptr).to_bytes()).unwrap())
    }
}

fn cvt(r: curl_sys::CURLcode) -> Result<(), Error> {
    if r == curl_sys::CURLE_OK {
        Ok(())
    } else {
        Err(Error::new(r))
    }
}
<commit_msg>Assert init succeeds<commit_after>//! Rust bindings to the libcurl C library
//!
//! This crate contains bindings for an HTTP/HTTPS client which is powered by
//! [libcurl], the same library behind the `curl` command line tool. The API
//! currently closely matches that of libcurl itself, except that a Rustic layer
//! of safety is applied on top.
//!
//! [libcurl]: https://curl.haxx.se/libcurl/
//!
//! # The "Easy" API
//!
//! The easiest way to send a request is to use the `Easy` api which corresponds
//! to `CURL` in libcurl. This handle supports a wide variety of options and can
//! be used to make a single blocking request in a thread. Callbacks can be
//! specified to deal with data as it arrives and a handle can be reused to
//! cache connections and such.
//!
//! ```rust,no_run
//! use std::io::{stdout, Write};
//!
//! use curl::easy::Easy;
//!
//! // Write the contents of rust-lang.org to stdout
//! let mut easy = Easy::new();
//! easy.url("https://www.rust-lang.org/").unwrap();
//! easy.write_function(|data| {
//!     Ok(stdout().write(data).unwrap())
//! }).unwrap();
//! easy.perform().unwrap();
//! ```
//!
//! # What about multiple concurrent HTTP requests?
//!
//! One option you have currently is to send multiple requests in multiple
//! threads, but otherwise libcurl has a "multi" interface for doing this
//! operation. Initial bindings of this interface can be found in the `multi`
//! module, but feedback is welcome!
//!
//! # Where does libcurl come from?
//!
//! This crate links to the `curl-sys` crate which is in turn responsible for
//! acquiring and linking to the libcurl library. Currently this crate will
//! build libcurl from source if one is not already detected on the system.
//!
//! There is a large number of releases for libcurl, all with different sets of
//! capabilities. Robust programs may wish to inspect `Version::get()` to test
//! what features are implemented in the linked build of libcurl at runtime.

#![deny(missing_docs)]

extern crate curl_sys;
extern crate libc;

#[cfg(all(unix, not(target_os = "macos")))]
extern crate openssl_sys;
#[cfg(windows)]
extern crate winapi;

use std::ffi::CStr;
use std::str;
use std::sync::{Once, ONCE_INIT};

pub use error::{Error, ShareError, MultiError, FormError};
mod error;

pub use version::{Version, Protocols};
mod version;

mod panic;
pub mod easy;
pub mod multi;

/// Initializes the underlying libcurl library.
///
/// It's not required to call this before the library is used, but it's
/// recommended to do so as soon as the program starts.
pub fn init() {
    static INIT: Once = ONCE_INIT;
    INIT.call_once(|| {
        platform_init();
        unsafe {
            assert_eq!(curl_sys::curl_global_init(curl_sys::CURL_GLOBAL_ALL), 0);
            libc::atexit(cleanup);
        }
    });

    extern fn cleanup() {
        unsafe { curl_sys::curl_global_cleanup(); }
    }

    #[cfg(all(unix, not(target_os = "macos")))]
    fn platform_init() {
        openssl_sys::init();
    }

    #[cfg(not(all(unix, not(target_os = "macos"))))]
    fn platform_init() {}
}

unsafe fn opt_str<'a>(ptr: *const libc::c_char) -> Option<&'a str> {
    if ptr.is_null() {
        None
    } else {
        Some(str::from_utf8(CStr::from_ptr(ptr).to_bytes()).unwrap())
    }
}

fn cvt(r: curl_sys::CURLcode) -> Result<(), Error> {
    if r == curl_sys::CURLE_OK {
        Ok(())
    } else {
        Err(Error::new(r))
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate serde;
extern crate serde_json;
extern crate time;
extern crate url;

use libc::gethostname;
use serde_json::Value;
use std::collections::BTreeMap;
use std::io::prelude::*;
use std::net::TcpStream;
use std::sync::Mutex;
use std::io;

lazy_static!
{
    pub static ref EMITTER: Mutex<Emitter<'static>> = Mutex::new(Emitter::empty());
}

pub fn emitter() -> std::sync::MutexGuard<'static, Emitter<'static>>
{
    EMITTER.lock().unwrap()
}

pub type Point<'a> = BTreeMap<&'a str, serde_json::Value>;

pub struct Emitter<'e>
{
    defaults: Point<'e>,
    output: Option<TcpStream>,
    destination: String,
    app: String,
}

impl<'e> Emitter<'e>
{
    pub fn empty() -> Emitter<'e>
    {
        let mut opts: Point = Point::new();
        let hostname = hostname();
        opts.insert("host", serde_json::to_value(hostname));
        Emitter
        {
            defaults: opts,
            output: None,
            app: String::from(""),
            destination: String::from("")
        }
    }

    pub fn init(&mut self, tmpl: BTreeMap<&'e str, Value>, app: &str)
    {
        let mut defaults = tmpl.clone();
        let hostname = hostname();
        defaults.insert("host", serde_json::to_value(hostname));

        let mut t = String::from(app);
        t.push('.');

        self.defaults = defaults;
        self.app = t;
    }

    pub fn new(tmpl: BTreeMap<&'e str, Value>, app: &str) -> Emitter<'e>
    {
        let mut defaults = tmpl.clone();
        let hostname = hostname();
        defaults.insert("host", serde_json::to_value(hostname));

        let mut t = String::from(app);
        t.push('.');

        Emitter
        {
            defaults: defaults,
            output: None,
            app: t,
            destination: String::from("")
        }
    }

    pub fn connect(&mut self, dest: &str)
    {
        self.destination = String::from(dest);
        self.output = create_connection(dest);
    }

    // The default write_all implemenation doesn't do useful things.
    fn write_all(conn: &mut TcpStream, mut buf: &[u8]) -> Result<usize, io::Error>
    {
        // let total = buf.len();
        let mut written: usize = 0;
        while !buf.is_empty()
        {
            match conn.write(buf)
            {
                Ok(0) => return Err(io::Error::new(io::ErrorKind::Other, "zero bytes written")),
                Ok(n) => {
                    // println!("bytes={} of {}", n, total);
                    written += n;
                    buf = &buf[n..]
                },
                Err(e) => return Err(e),
            }
        }
        Ok(written)
    }

    fn write(&mut self, metric: BTreeMap<&'e str, Value>)
    {
        match self.output
        {
            None => { self.output = create_connection(&self.destination); },
            Some(_) => {},
        };

        match self.output
        {
            None => {},
            Some(ref mut conn) =>
            {
                let mline = serde_json::to_string(&metric).unwrap() + "\n";
                match Emitter::write_all(conn, mline.as_bytes())
                {
                    Ok(v) => println!("OK {:?}", v),
                    Err(e) => println!("ERR {:?}", e),
                }
            }
        }
    }

    pub fn emit(&mut self, point: BTreeMap<&'e str, Value>)
    {
        let mut metric = self.defaults.clone();
        metric.append(&mut point.clone());

        // Failing to set a name means the metrics point is invalid; we decline to send it.
        let name = match metric.remove("name")
        {
            Some(v) => v,
            None => { return; },
        };
        let mut fullname = self.app.clone();
        fullname.push_str(name.as_str().unwrap());

        metric.insert("name", serde_json::to_value(fullname));
        metric.entry("value").or_insert(serde_json::to_value(1));

        let now = time::get_time();
        let millis = now.sec * 1000 + (now.nsec / 1000000) as i64;
        metric.entry("time").or_insert(serde_json::to_value(millis));

        self.write(metric);
    }

    pub fn emit_name(&mut self, name: &'e str)
    {
        let mut metric: BTreeMap<&str, Value> = BTreeMap::new();
        metric.insert("name", serde_json::to_value(name));
        self.emit(metric);
    }

    pub fn emit_name_val_tag(&mut self, name: &'e str, value: u32, tag: &'e str, tagv: &'e str)
    {
        let mut metric: BTreeMap<&str, Value> = BTreeMap::new();
        metric.insert("name", serde_json::to_value(name));
        metric.insert("value", serde_json::to_value(value));
        metric.insert(tag, serde_json::to_value(tagv));
        self.emit(metric);
    }

    pub fn emit_name_int_tag_uint(&mut self, name: &'e str, value: i64, tag: &'e str, tagv: u16)
    {
        let mut metric: BTreeMap<&str, Value> = BTreeMap::new();
        metric.insert("name", serde_json::to_value(name));
        metric.insert("value", serde_json::to_value(value));
        metric.insert(tag, serde_json::to_value(tagv));
        self.emit(metric);
    }

    pub fn emit_float(&mut self, name: &'e str, value: f32)
    {
        let mut metric: BTreeMap<&str, Value> = BTreeMap::new();
        metric.insert("name", serde_json::to_value(name));
        metric.insert("value", serde_json::to_value(value));
        self.emit(metric);
    }

    pub fn emit_int(&mut self, name: &'e str, value: i32)
    {
        let mut metric: BTreeMap<&str, Value> = BTreeMap::new();
        metric.insert("name", serde_json::to_value(name));
        metric.insert("value", serde_json::to_value(value));
        self.emit(metric);
    }

    pub fn emit_int64(&mut self, name: &'e str, value: i64)
    {
        let mut metric: BTreeMap<&str, Value> = BTreeMap::new();
        metric.insert("name", serde_json::to_value(name));
        metric.insert("value", serde_json::to_value(value));
        self.emit(metric);
    }

    pub fn emit_unsigned(&mut self, name: &'e str, value: u32)
    {
        self.emit_int64(name, value as i64);
    }

    pub fn emit_unsigned16(&mut self, name: &'e str, value: u16)
    {
        self.emit_int(name, value as i32);
    }
}

fn create_connection(dest: &str) -> Option<std::net::TcpStream>
{
    // TODO udp vs tcp for full compatibility
    // TODO reconnect on error
    let target = url::Url::parse(dest).ok().unwrap();
    match TcpStream::connect((target.host_str().unwrap(), target.port().unwrap()))
    {
        Ok(v) => { Some(v) },
        Err(_) => { None },
    }
}

pub fn hostname<'a>() -> String
{
    let bufsize = 255;
    let mut buf = Vec::<u8>::with_capacity(bufsize);
    let ptr = buf.as_mut_slice().as_mut_ptr();

    let err = unsafe
        { gethostname(ptr as *mut libc::c_char, bufsize as libc::size_t) }
        as libc::size_t;

    if err != 0
    {
        return "localhost".into();
    }

    let mut len = bufsize;
    let mut i = 0;

    loop
    {
        let byte = unsafe { *(((ptr as u64) + (i as u64)) as *const u8) };
        if byte == 0
        {
            len = i;
            break;
        }
        if i == bufsize { break; }
        i += 1;
    }

    unsafe { buf.set_len(len); }
    String::from_utf8_lossy(buf.as_slice()).into_owned()
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>fix: Didn't want to release with debug output.<commit_after>#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate serde;
extern crate serde_json;
extern crate time;
extern crate url;

use libc::gethostname;
use serde_json::Value;
use std::collections::BTreeMap;
use std::io::prelude::*;
use std::net::TcpStream;
use std::sync::Mutex;
use std::io;

lazy_static!
{
    pub static ref EMITTER: Mutex<Emitter<'static>> = Mutex::new(Emitter::empty());
}

pub fn emitter() -> std::sync::MutexGuard<'static, Emitter<'static>>
{
    EMITTER.lock().unwrap()
}

pub type Point<'a> = BTreeMap<&'a str, serde_json::Value>;

pub struct Emitter<'e>
{
    defaults: Point<'e>,
    output: Option<TcpStream>,
    destination: String,
    app: String,
}

impl<'e> Emitter<'e>
{
    pub fn empty() -> Emitter<'e>
    {
        let mut opts: Point = Point::new();
        let hostname = hostname();
        opts.insert("host", serde_json::to_value(hostname));
        Emitter
        {
            defaults: opts,
            output: None,
            app: String::from(""),
            destination: String::from("")
        }
    }

    pub fn init(&mut self, tmpl: BTreeMap<&'e str, Value>, app: &str)
    {
        let mut defaults = tmpl.clone();
        let hostname = hostname();
        defaults.insert("host", serde_json::to_value(hostname));

        let mut t = String::from(app);
        t.push('.');

        self.defaults = defaults;
        self.app = t;
    }

    pub fn new(tmpl: BTreeMap<&'e str, Value>, app: &str) -> Emitter<'e>
    {
        let mut defaults = tmpl.clone();
        let hostname = hostname();
        defaults.insert("host", serde_json::to_value(hostname));

        let mut t = String::from(app);
        t.push('.');

        Emitter
        {
            defaults: defaults,
            output: None,
            app: t,
            destination: String::from("")
        }
    }

    pub fn connect(&mut self, dest: &str)
    {
        self.destination = String::from(dest);
        self.output = create_connection(dest);
    }

    // The default write_all implemenation doesn't do useful things.
    fn write_all(conn: &mut TcpStream, mut buf: &[u8]) -> Result<usize, io::Error>
    {
        // let total = buf.len();
        let mut written: usize = 0;
        while !buf.is_empty()
        {
            match conn.write(buf)
            {
                Ok(0) => return Err(io::Error::new(io::ErrorKind::Other, "zero bytes written")),
                Ok(n) => {
                    // println!("bytes={} of {}", n, total);
                    written += n;
                    buf = &buf[n..]
                },
                Err(e) => return Err(e),
            }
        }
        Ok(written)
    }

    fn write(&mut self, metric: BTreeMap<&'e str, Value>)
    {
        match self.output
        {
            None => { self.output = create_connection(&self.destination); },
            Some(_) => {},
        };

        match self.output
        {
            None => {},
            Some(ref mut conn) =>
            {
                let mline = serde_json::to_string(&metric).unwrap() + "\n";
                match Emitter::write_all(conn, mline.as_bytes())
                {
                    Ok(_) => {},
                    Err(e) => println!("ERR {:?}", e),
                }
            }
        }
    }

    pub fn emit(&mut self, point: BTreeMap<&'e str, Value>)
    {
        let mut metric = self.defaults.clone();
        metric.append(&mut point.clone());

        // Failing to set a name means the metrics point is invalid; we decline to send it.
        let name = match metric.remove("name")
        {
            Some(v) => v,
            None => { return; },
        };
        let mut fullname = self.app.clone();
        fullname.push_str(name.as_str().unwrap());

        metric.insert("name", serde_json::to_value(fullname));
        metric.entry("value").or_insert(serde_json::to_value(1));

        let now = time::get_time();
        let millis = now.sec * 1000 + (now.nsec / 1000000) as i64;
        metric.entry("time").or_insert(serde_json::to_value(millis));

        self.write(metric);
    }

    pub fn emit_name(&mut self, name: &'e str)
    {
        let mut metric: BTreeMap<&str, Value> = BTreeMap::new();
        metric.insert("name", serde_json::to_value(name));
        self.emit(metric);
    }

    pub fn emit_name_val_tag(&mut self, name: &'e str, value: u32, tag: &'e str, tagv: &'e str)
    {
        let mut metric: BTreeMap<&str, Value> = BTreeMap::new();
        metric.insert("name", serde_json::to_value(name));
        metric.insert("value", serde_json::to_value(value));
        metric.insert(tag, serde_json::to_value(tagv));
        self.emit(metric);
    }

    pub fn emit_name_int_tag_uint(&mut self, name: &'e str, value: i64, tag: &'e str, tagv: u16)
    {
        let mut metric: BTreeMap<&str, Value> = BTreeMap::new();
        metric.insert("name", serde_json::to_value(name));
        metric.insert("value", serde_json::to_value(value));
        metric.insert(tag, serde_json::to_value(tagv));
        self.emit(metric);
    }

    pub fn emit_float(&mut self, name: &'e str, value: f32)
    {
        let mut metric: BTreeMap<&str, Value> = BTreeMap::new();
        metric.insert("name", serde_json::to_value(name));
        metric.insert("value", serde_json::to_value(value));
        self.emit(metric);
    }

    pub fn emit_int(&mut self, name: &'e str, value: i32)
    {
        let mut metric: BTreeMap<&str, Value> = BTreeMap::new();
        metric.insert("name", serde_json::to_value(name));
        metric.insert("value", serde_json::to_value(value));
        self.emit(metric);
    }

    pub fn emit_int64(&mut self, name: &'e str, value: i64)
    {
        let mut metric: BTreeMap<&str, Value> = BTreeMap::new();
        metric.insert("name", serde_json::to_value(name));
        metric.insert("value", serde_json::to_value(value));
        self.emit(metric);
    }

    pub fn emit_unsigned(&mut self, name: &'e str, value: u32)
    {
        self.emit_int64(name, value as i64);
    }

    pub fn emit_unsigned16(&mut self, name: &'e str, value: u16)
    {
        self.emit_int(name, value as i32);
    }
}

fn create_connection(dest: &str) -> Option<std::net::TcpStream>
{
    // TODO udp vs tcp for full compatibility
    // TODO reconnect on error
    let target = url::Url::parse(dest).ok().unwrap();
    match TcpStream::connect((target.host_str().unwrap(), target.port().unwrap()))
    {
        Ok(v) => { Some(v) },
        Err(_) => { None },
    }
}

pub fn hostname<'a>() -> String
{
    let bufsize = 255;
    let mut buf = Vec::<u8>::with_capacity(bufsize);
    let ptr = buf.as_mut_slice().as_mut_ptr();

    let err = unsafe
        { gethostname(ptr as *mut libc::c_char, bufsize as libc::size_t) }
        as libc::size_t;

    if err != 0
    {
        return "localhost".into();
    }

    let mut len = bufsize;
    let mut i = 0;

    loop
    {
        let byte = unsafe { *(((ptr as u64) + (i as u64)) as *const u8) };
        if byte == 0
        {
            len = i;
            break;
        }
        if i == bufsize { break; }
        i += 1;
    }

    unsafe { buf.set_len(len); }
    String::from_utf8_lossy(buf.as_slice()).into_owned()
}

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


<commit_before>#![feature(vec_push_all)]

pub struct JsonEncoder {
    buffer: Vec<u8>
}

impl JsonEncoder {
    pub fn new() -> JsonEncoder {
        JsonEncoder{buffer: Vec::new()}
    }

    #[inline(always)]
    pub fn encode_raw(&mut self, raw: &[u8]) {
        self.buffer.push_all(raw);
    }

    pub fn into_vec(self) -> Vec<u8> {
        self.buffer
    }

    pub fn with_buf<F>(&mut self, f: F) where F: Fn(&mut Vec<u8>) {
        f(&mut self.buffer);
    }

    #[inline(always)]
    pub fn encode_str_noescape(&mut self, raw_str: &str) {
        self.buffer.push(b'"');
        self.buffer.push_all(raw_str.as_bytes());
        self.buffer.push(b'"');
    }

    fn escape_bytes(&mut self, bytes: &[u8]) {
        let mut start = 0;

        for (i, byte) in bytes.iter().enumerate() {
            let escaped = match *byte {
                b'"' => b"\\\"",
                b'\\' => b"\\\\",
                b'\x08' => b"\\b",
                b'\x0c' => b"\\f",
                b'\n' => b"\\n",
                b'\r' => b"\\r",
                b'\t' => b"\\t",
                _ => {
                    continue;
                }
            };

            if start < i {
                self.encode_raw(&bytes[start..i]);
            }

            self.encode_raw(escaped);

            start = i + 1;
        }

        if start != bytes.len() {
            self.encode_raw(&bytes[start..]);
        }
    }

    pub fn encode_decimal_str(&mut self, value: u64) {
        self.buffer.push(b'"');
        self.encode_u64_decimal(value);
        self.buffer.push(b'"');
    }

    // encodes as decimal string
    #[inline(always)]
    fn encode_u64_decimal(&mut self, value: u64) {
        const CHARS: &'static [u8] = b"0123456789";
        const MAX_DIGITS: usize = 20;

        if value == 0 {
            self.buffer.push(b'0');
            return;
        }

        let mut digits: [u8; MAX_DIGITS] = [b'0'; MAX_DIGITS];
        let mut i = MAX_DIGITS;
        let mut n = value;
        while n > 0 {
            i -= 1;
            digits[i] = CHARS[(n % 10) as usize];
            n = n / 10;
        }

        self.encode_raw(&digits[i..]);
    }

    #[inline(always)]
    pub fn encode_str(&mut self, s: &str) {
        self.buffer.push(b'"');
        self.escape_bytes(s.as_bytes());
        self.buffer.push(b'"');
    }

    #[inline(always)]
    pub fn encode_i32(&mut self, value: i32) {
        if value == 0 {
            self.buffer.push(b'0');
        } else if value > 0 {
            self.encode_u31(value as u32);
        } else {
            self.buffer.push(b'-');
            self.encode_u31((-value) as u32);
        }
    }

    // encodes a 31-bit unsigned integer != 0
    fn encode_u31(&mut self, value: u32) {
        const CHARS: &'static [u8] = b"0123456789";
        const MAX_DIGITS: usize = 10;
        debug_assert!(value != 0);

        let mut digits: [u8; MAX_DIGITS] = [b'0'; MAX_DIGITS];
        let mut i = MAX_DIGITS;
        let mut n = value;
        while n > 0 {
            i -= 1;
            digits[i] = CHARS[(n % 10) as usize];
            n = n / 10;
        }

        self.encode_raw(&digits[i..]);
    }

    pub fn encode_obj<F>(&mut self, f: F) where F: Fn(&mut JsonObjectEncoder) {
        self.buffer.push(b'{');
        {
            f(&mut JsonObjectEncoder {js: self, needs_sep: false});
        }
        self.buffer.push(b'}');
    }

    pub fn encode_array<F>(&mut self, f: F) where F: Fn(&mut JsonArrayEncoder) {
        self.buffer.push(b'[');
        {
            f(&mut JsonArrayEncoder {js: self, needs_sep: false});
        }
        self.buffer.push(b']');
    }

}

pub struct JsonObjectEncoder<'a> {
    js: &'a mut JsonEncoder,
    needs_sep: bool,
}

impl<'a> JsonObjectEncoder<'a> {
    // XXX: name MAY NOT include escapable characters
    #[inline(always)]
    pub fn encode_field<F:Fn(&mut JsonEncoder)>(&mut self, name: &str, f: F) {
        if self.needs_sep {
            self.js.buffer.push(b',');
        } else {
            self.needs_sep = true;
        }
        self.js.encode_str_noescape(name);
        self.js.buffer.push(b':');

        f(self.js);
    }

    #[inline(always)]
    pub fn encode_field_array<F:Fn(&mut JsonArrayEncoder)>(&mut self, name: &str, f: F) {
        self.encode_field(name, |js| js.encode_array(|jsa| f(jsa)));
    }
}

pub struct JsonArrayEncoder<'a> {
    js: &'a mut JsonEncoder,
    needs_sep: bool,
}

impl<'a> JsonArrayEncoder<'a> {
    #[inline(always)]
    pub fn encode_elm<F:Fn(&mut JsonEncoder)>(&mut self, f: F) {
        if self.needs_sep {
            self.js.buffer.push(b',');
        } else {
            self.needs_sep = true;
        }
        f(self.js);
    }

    #[inline(always)]
    pub fn encode_elm_i32(&mut self, val: i32) {
        self.encode_elm(|j| j.encode_i32(val));
    }

    #[inline(always)]
    pub fn encode_elm_str(&mut self, s: &str) {
        self.encode_elm(|j| j.encode_str(s));
    }
}

#[test]
fn test_json_obj_encoder() {
    use std::str;

    let mut js = JsonEncoder::new();
    js.encode_obj(|_|{});
    assert_eq!(b"{}", &js.into_vec()[..]);

    let mut js = JsonEncoder::new();
    js.encode_obj(|jso| {
        jso.encode_field("total", |js| js.encode_i32(31));
    });
    assert_eq!(b"{\"total\":31}", &js.into_vec()[..]);

    let mut js = JsonEncoder::new();
    js.encode_obj(|jso| {
        jso.encode_field("total", |js| js.encode_i32(31));
        jso.encode_field("next", |js| js.encode_str("abc"));
    });
    assert_eq!(b"{\"total\":31,\"next\":\"abc\"}", &js.into_vec()[..]);

    let mut js = JsonEncoder::new();
    js.encode_obj(|jso| {
        jso.encode_field("total", |js| js.encode_i32(31));
        jso.encode_field("next", |js| js.encode_str("abc"));
        jso.encode_field("tags", |js| {
                js.encode_array(|jsa| {
                        jsa.encode_elm(|js| js.encode_i32(1));
                        jsa.encode_elm(|js| js.encode_i32(2));
                });
        });
    });
    assert_eq!("{\"total\":31,\"next\":\"abc\",\"tags\":[1,2]}", str::from_utf8(&js.into_vec()[..]).unwrap());
}
<commit_msg>Add helper methods<commit_after>#![feature(vec_push_all)]

pub struct JsonEncoder {
    buffer: Vec<u8>
}

impl JsonEncoder {
    pub fn new() -> JsonEncoder {
        JsonEncoder{buffer: Vec::new()}
    }

    #[inline(always)]
    pub fn encode_raw(&mut self, raw: &[u8]) {
        self.buffer.push_all(raw);
    }

    pub fn into_vec(self) -> Vec<u8> {
        self.buffer
    }

    pub fn with_buf<F>(&mut self, f: F) where F: Fn(&mut Vec<u8>) {
        f(&mut self.buffer);
    }

    #[inline(always)]
    pub fn encode_str_noescape(&mut self, raw_str: &str) {
        self.buffer.push(b'"');
        self.buffer.push_all(raw_str.as_bytes());
        self.buffer.push(b'"');
    }

    fn escape_bytes(&mut self, bytes: &[u8]) {
        let mut start = 0;

        for (i, byte) in bytes.iter().enumerate() {
            let escaped = match *byte {
                b'"' => b"\\\"",
                b'\\' => b"\\\\",
                b'\x08' => b"\\b",
                b'\x0c' => b"\\f",
                b'\n' => b"\\n",
                b'\r' => b"\\r",
                b'\t' => b"\\t",
                _ => {
                    continue;
                }
            };

            if start < i {
                self.encode_raw(&bytes[start..i]);
            }

            self.encode_raw(escaped);

            start = i + 1;
        }

        if start != bytes.len() {
            self.encode_raw(&bytes[start..]);
        }
    }

    pub fn encode_decimal_str(&mut self, value: u64) {
        self.buffer.push(b'"');
        self.encode_u64_decimal(value);
        self.buffer.push(b'"');
    }

    // encodes as decimal string
    #[inline(always)]
    fn encode_u64_decimal(&mut self, value: u64) {
        const CHARS: &'static [u8] = b"0123456789";
        const MAX_DIGITS: usize = 20;

        if value == 0 {
            self.buffer.push(b'0');
            return;
        }

        let mut digits: [u8; MAX_DIGITS] = [b'0'; MAX_DIGITS];
        let mut i = MAX_DIGITS;
        let mut n = value;
        while n > 0 {
            i -= 1;
            digits[i] = CHARS[(n % 10) as usize];
            n = n / 10;
        }

        self.encode_raw(&digits[i..]);
    }

    #[inline(always)]
    pub fn encode_str(&mut self, s: &str) {
        self.buffer.push(b'"');
        self.escape_bytes(s.as_bytes());
        self.buffer.push(b'"');
    }

    #[inline(always)]
    pub fn encode_i32(&mut self, value: i32) {
        if value == 0 {
            self.buffer.push(b'0');
        } else if value > 0 {
            self.encode_u31(value as u32);
        } else {
            self.buffer.push(b'-');
            self.encode_u31((-value) as u32);
        }
    }

    // encodes a 31-bit unsigned integer != 0
    fn encode_u31(&mut self, value: u32) {
        const CHARS: &'static [u8] = b"0123456789";
        const MAX_DIGITS: usize = 10;
        debug_assert!(value != 0);

        let mut digits: [u8; MAX_DIGITS] = [b'0'; MAX_DIGITS];
        let mut i = MAX_DIGITS;
        let mut n = value;
        while n > 0 {
            i -= 1;
            digits[i] = CHARS[(n % 10) as usize];
            n = n / 10;
        }

        self.encode_raw(&digits[i..]);
    }

    pub fn encode_obj<F>(&mut self, f: F) where F: Fn(&mut JsonObjectEncoder) {
        self.buffer.push(b'{');
        {
            f(&mut JsonObjectEncoder {js: self, needs_sep: false});
        }
        self.buffer.push(b'}');
    }

    pub fn encode_array<F>(&mut self, f: F) where F: Fn(&mut JsonArrayEncoder) {
        self.buffer.push(b'[');
        {
            f(&mut JsonArrayEncoder {js: self, needs_sep: false});
        }
        self.buffer.push(b']');
    }

}

pub struct JsonObjectEncoder<'a> {
    js: &'a mut JsonEncoder,
    needs_sep: bool,
}

impl<'a> JsonObjectEncoder<'a> {
    // XXX: name MAY NOT include escapable characters
    #[inline(always)]
    pub fn encode_field<F:Fn(&mut JsonEncoder)>(&mut self, name: &str, f: F) {
        if self.needs_sep {
            self.js.buffer.push(b',');
        } else {
            self.needs_sep = true;
        }
        self.js.encode_str_noescape(name);
        self.js.buffer.push(b':');

        f(self.js);
    }

    #[inline(always)]
    pub fn encode_field_array<F:Fn(&mut JsonArrayEncoder)>(&mut self, name: &str, f: F) {
        self.encode_field(name, |js| js.encode_array(|jsa| f(jsa)));
    }

    #[inline(always)]
    pub fn encode_field_i32(&mut self, name: &str, val: i32) {
        self.encode_field(name, |js| js.encode_i32(val));
    }

    #[inline(always)]
    pub fn encode_field_str(&mut self, name: &str, s: &str) {
        self.encode_field(name, |js| js.encode_str(s));
    }

}

pub struct JsonArrayEncoder<'a> {
    js: &'a mut JsonEncoder,
    needs_sep: bool,
}

impl<'a> JsonArrayEncoder<'a> {
    #[inline(always)]
    pub fn encode_elm<F:Fn(&mut JsonEncoder)>(&mut self, f: F) {
        if self.needs_sep {
            self.js.buffer.push(b',');
        } else {
            self.needs_sep = true;
        }
        f(self.js);
    }

    #[inline(always)]
    pub fn encode_elm_i32(&mut self, val: i32) {
        self.encode_elm(|j| j.encode_i32(val));
    }

    #[inline(always)]
    pub fn encode_elm_str(&mut self, s: &str) {
        self.encode_elm(|j| j.encode_str(s));
    }
}

#[test]
fn test_json_obj_encoder() {
    use std::str;

    let mut js = JsonEncoder::new();
    js.encode_obj(|_|{});
    assert_eq!(b"{}", &js.into_vec()[..]);

    let mut js = JsonEncoder::new();
    js.encode_obj(|jso| {
        jso.encode_field("total", |js| js.encode_i32(31));
    });
    assert_eq!(b"{\"total\":31}", &js.into_vec()[..]);

    let mut js = JsonEncoder::new();
    js.encode_obj(|jso| {
        jso.encode_field("total", |js| js.encode_i32(31));
        jso.encode_field("next", |js| js.encode_str("abc"));
    });
    assert_eq!(b"{\"total\":31,\"next\":\"abc\"}", &js.into_vec()[..]);

    let mut js = JsonEncoder::new();
    js.encode_obj(|jso| {
        jso.encode_field("total", |js| js.encode_i32(31));
        jso.encode_field("next", |js| js.encode_str("abc"));
        jso.encode_field("tags", |js| {
                js.encode_array(|jsa| {
                        jsa.encode_elm(|js| js.encode_i32(1));
                        jsa.encode_elm(|js| js.encode_i32(2));
                });
        });
    });
    assert_eq!("{\"total\":31,\"next\":\"abc\",\"tags\":[1,2]}", str::from_utf8(&js.into_vec()[..]).unwrap());
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate route_recognizer;

use std::fmt::Debug;

use hyper::header::Headers;
use hyper::method::Method;
use hyper::server::Handler as HyperHandler;
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

use route_recognizer::{Match, Params, Router};

fn method_to_bit(method: &Method) -> u8 {
    use hyper::method::Method::*;
    let exp = match *method {
        Options => 0,
        Get | Head => 1,
        Post => 2,
        Put => 3,
        Delete => 4,
        Connect => 5,
        Patch => 6,
        Trace | Extension(_) => 7,
    };

    1u8 << exp
}

#[derive(Debug)]
pub struct RouteEntry<H> {
    accepted_methods: u8,
    handler: H,
}

impl<H> RouteEntry<H> {
    pub fn with_handler(handler: H) -> RouteEntry<H> {
        RouteEntry {
            accepted_methods: 0,
            handler: handler,
        }
    }

    pub fn add_method(&mut self, method: &Method) {
        self.accepted_methods |= method_to_bit(method);
    }

    pub fn accepts_method(&self, method: &Method) -> bool {
        (self.accepted_methods & method_to_bit(method)) > 0
    }

    pub fn handler(&self) -> &H {
        &self.handler
    }
}

pub trait RouteHandler: Sync + Send {
    fn handle<'a, 'k>(&'a self, params: Params, req: Request<'a, 'k>, res: Response<'a>);

    fn check_continue(&self, _: Params, _: (&Method, &RequestUri, &Headers)) -> StatusCode {
        StatusCode::Continue
    }
}

impl RouteHandler for Box<RouteHandler> {
    fn handle<'a, 'k>(&'a self, params: Params, req: Request<'a, 'k>, res: Response<'a>) {
        self.as_ref().handle(params, req, res)
    }

    fn check_continue(&self, params: Params, t: (&Method, &RequestUri, &Headers)) -> StatusCode {
        self.as_ref().check_continue(params, t)
    }
}

impl RouteHandler for HyperHandler {
    fn handle<'a, 'k>(&'a self, _: Params, req: Request<'a, 'k>, res: Response<'a>) {
        self.handle(req, res)
    }

    fn check_continue(&self, _: Params, tuple: (&Method, &RequestUri, &Headers)) -> StatusCode {
        self.check_continue(tuple)
    }
}

impl<F> RouteHandler for F
    where F: Fn(Params, Request, Response),
          F: Sync + Send
{
    fn handle<'a, 'k>(&'a self, params: Params, req: Request<'a, 'k>, res: Response<'a>) {
        self(params, req, res)
    }
}

pub struct HyperRouter<H> {
    path_router: Router<RouteEntry<H>>,
    url_router: Router<RouteEntry<H>>,
    authority_router: Router<RouteEntry<H>>,
    server_wide: Option<RouteEntry<H>>,
}

impl<H> HyperRouter<H> {
    pub fn new() -> HyperRouter<H> {
        HyperRouter {
            path_router: Router::new(),
            url_router: Router::new(),
            authority_router: Router::new(),
            server_wide: None,
        }
    }

    pub fn add_path_entry(&mut self, route: &str, entry: RouteEntry<H>) {
        self.path_router.add(route, entry);
    }

    pub fn add_url_entry(&mut self, route: &str, entry: RouteEntry<H>) {
        self.path_router.add(route, entry);
    }

    pub fn add_authority_entry(&mut self, route: &str, entry: RouteEntry<H>) {
        self.path_router.add(route, entry);
    }

    pub fn add_server_wide_entry(&mut self, entry: RouteEntry<H>) {
        self.server_wide = Some(entry);
    }

    pub fn get_match(&self, method: &Method, uri: &RequestUri) -> Option<Match<&RouteEntry<H>>> {
        use hyper::uri::RequestUri::*;

        let m = match *uri {
            AbsolutePath(ref path) => self.path_router.recognize(&path).ok(),
            AbsoluteUri(ref url) => self.url_router.recognize(url.as_str()).ok(),
            Authority(ref authority) => self.authority_router.recognize(&authority).ok(),
            Star => {
                self.server_wide.as_ref().map(|handler| {
                    Match {
                        handler: handler,
                        params: Params::new(),
                    }
                })
            }
        };

        if let Some(mat) = m {
            if mat.handler.accepts_method(method) {
                Some(mat)
            } else {
                None
            }
        } else {
            None
        }
    }
}

impl<H> HyperHandler for HyperRouter<H>
    where H: AsRef<RouteHandler> + Send + Sync + Debug
{
    fn handle<'a, 'k>(&'a self, req: Request<'a, 'k>, mut res: Response<'a>) {
        if let Some(matches) = self.get_match(&req.method, &req.uri) {
            let Match { handler, params } = matches;
            handler.handler.as_ref().handle(params, req, res);
        } else {
            *res.status_mut() = StatusCode::NotFound;
        }
    }

    fn check_continue(&self, tuple: (&Method, &RequestUri, &Headers)) -> StatusCode {
        if let Some(matches) = self.get_match(tuple.0, tuple.1) {
            let Match { handler, params } = matches;
            handler.handler.as_ref().check_continue(params, tuple)
        } else {
            StatusCode::Continue
        }
    }
}

#[cfg(test)]
#[test]
fn simple_test() {
    let mut entry = RouteEntry::with_handler(0u8);
    entry.add_method(&Method::Get);
    let mut router = HyperRouter::new();
    router.add_path_entry("/test/", entry);

    let res = router.get_match(&Method::Get,
                               &RequestUri::AbsolutePath(String::from("/test/")));
    assert_eq!(res.unwrap().handler.handler, 0u8);

    let res = router.get_match(&Method::Get,
                               &RequestUri::AbsolutePath(String::from("/test2/")));
    assert!(res.is_none());

    let res = router.get_match(&Method::Post,
                               &RequestUri::AbsolutePath(String::from("/test/")));
    assert!(res.is_none());
}

#[cfg(test)]
#[test]
fn multi_method_test() {
    let mut entry = RouteEntry::with_handler(0u8);
    entry.add_method(&Method::Get);
    entry.add_method(&Method::Put);
    let mut router = HyperRouter::new();
    router.add_path_entry("/test/", entry);

    let res = router.get_match(&Method::Get,
                               &RequestUri::AbsolutePath(String::from("/test/")));
    assert_eq!(res.unwrap().handler.handler, 0u8);

    let res = router.get_match(&Method::Put,
                               &RequestUri::AbsolutePath(String::from("/test/")));
    assert_eq!(res.unwrap().handler.handler, 0u8);

    let res = router.get_match(&Method::Post,
                               &RequestUri::AbsolutePath(String::from("/test/")));
    assert!(res.is_none());
}
<commit_msg>Add create_router!<commit_after>extern crate hyper;
extern crate route_recognizer;

use std::fmt::Debug;

use hyper::header::Headers;
use hyper::method::Method;
use hyper::server::Handler as HyperHandler;
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

use route_recognizer::{Match, Params, Router};

#[macro_export]
macro_rules! create_router {
    ( $( $path:expr => $( $method:ident ),+ => $handler:expr ),+, ) => {{
        let mut router = HyperRouter::new();

        $(
            let mut entry = RouteEntry::with_handler($handler);
            $(
                entry.add_method(MethodRoutes::$method);
            )+

            router.add_path_entry($path, entry);
        )+

        router
    }};
}

fn method_to_bit(method: &Method) -> u8 {
    use hyper::method::Method::*;
    let exp = match *method {
        Options => 0,
        Get | Head => 1,
        Post => 2,
        Put => 3,
        Delete => 4,
        Connect => 5,
        Patch => 6,
        Trace | Extension(_) => 7,
    };

    1u8 << exp
}

fn method_route_to_bit(method: MethodRoutes) -> u8 {
    use MethodRoutes::*;
    let exp = match method {
        Options => 0,
        Get => 1,
        Post => 2,
        Put => 3,
        Delete => 4,
        Connect => 5,
        Patch => 6,
        Other => 7,
    };

    1u8 << exp
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum MethodRoutes {
    Options,
    Get,
    Post,
    Put,
    Delete,
    Connect,
    Patch,
    Other,
}

#[derive(Debug)]
pub struct RouteEntry<H> {
    accepted_methods: u8,
    handler: H,
}

impl<H> RouteEntry<H> {
    pub fn with_handler(handler: H) -> RouteEntry<H> {
        RouteEntry {
            accepted_methods: 0,
            handler: handler,
        }
    }

    pub fn add_method(&mut self, method: MethodRoutes) {
        self.accepted_methods |= method_route_to_bit(method);
    }

    pub fn add_methods(&mut self, methods: &[MethodRoutes]) {
        for method in methods {
            self.accepted_methods |= method_route_to_bit(*method);
        }
    }

    pub fn add_all_methods(&mut self) {
        self.accepted_methods = !0u8;
    }

    pub fn accepts_method(&self, method: &Method) -> bool {
        (self.accepted_methods & method_to_bit(method)) > 0
    }

    pub fn handler(&self) -> &H {
        &self.handler
    }
}

pub trait RouteHandler: Sync + Send {
    fn handle<'a, 'k>(&'a self, params: Params, req: Request<'a, 'k>, res: Response<'a>);

    fn check_continue(&self, _: Params, _: (&Method, &RequestUri, &Headers)) -> StatusCode {
        StatusCode::Continue
    }
}

impl RouteHandler for Box<RouteHandler> {
    fn handle<'a, 'k>(&'a self, params: Params, req: Request<'a, 'k>, res: Response<'a>) {
        self.as_ref().handle(params, req, res)
    }

    fn check_continue(&self, params: Params, t: (&Method, &RequestUri, &Headers)) -> StatusCode {
        self.as_ref().check_continue(params, t)
    }
}

impl RouteHandler for HyperHandler {
    fn handle<'a, 'k>(&'a self, _: Params, req: Request<'a, 'k>, res: Response<'a>) {
        self.handle(req, res)
    }

    fn check_continue(&self, _: Params, tuple: (&Method, &RequestUri, &Headers)) -> StatusCode {
        self.check_continue(tuple)
    }
}

impl<F> RouteHandler for F
    where F: Fn(Params, Request, Response),
          F: Sync + Send
{
    fn handle<'a, 'k>(&'a self, params: Params, req: Request<'a, 'k>, res: Response<'a>) {
        self(params, req, res)
    }
}

pub struct HyperRouter<H> {
    path_router: Router<RouteEntry<H>>,
    url_router: Router<RouteEntry<H>>,
    authority_router: Router<RouteEntry<H>>,
    server_wide: Option<RouteEntry<H>>,
}

impl<H> HyperRouter<H> {
    pub fn new() -> HyperRouter<H> {
        HyperRouter {
            path_router: Router::new(),
            url_router: Router::new(),
            authority_router: Router::new(),
            server_wide: None,
        }
    }

    pub fn add_path_entry(&mut self, route: &str, entry: RouteEntry<H>) {
        self.path_router.add(route, entry);
    }

    pub fn add_url_entry(&mut self, route: &str, entry: RouteEntry<H>) {
        self.path_router.add(route, entry);
    }

    pub fn add_authority_entry(&mut self, route: &str, entry: RouteEntry<H>) {
        self.path_router.add(route, entry);
    }

    pub fn add_server_wide_entry(&mut self, entry: RouteEntry<H>) {
        self.server_wide = Some(entry);
    }

    pub fn get_match(&self, method: &Method, uri: &RequestUri) -> Option<Match<&RouteEntry<H>>> {
        use hyper::uri::RequestUri::*;

        let m = match *uri {
            AbsolutePath(ref path) => self.path_router.recognize(&path).ok(),
            AbsoluteUri(ref url) => self.url_router.recognize(url.as_str()).ok(),
            Authority(ref authority) => self.authority_router.recognize(&authority).ok(),
            Star => {
                self.server_wide.as_ref().map(|handler| {
                    Match {
                        handler: handler,
                        params: Params::new(),
                    }
                })
            }
        };

        if let Some(mat) = m {
            if mat.handler.accepts_method(method) {
                Some(mat)
            } else {
                None
            }
        } else {
            None
        }
    }
}

impl<H> HyperHandler for HyperRouter<H>
    where H: AsRef<RouteHandler> + Send + Sync + Debug
{
    fn handle<'a, 'k>(&'a self, req: Request<'a, 'k>, mut res: Response<'a>) {
        if let Some(matches) = self.get_match(&req.method, &req.uri) {
            let Match { handler, params } = matches;
            handler.handler.as_ref().handle(params, req, res);
        } else {
            *res.status_mut() = StatusCode::NotFound;
        }
    }

    fn check_continue(&self, tuple: (&Method, &RequestUri, &Headers)) -> StatusCode {
        if let Some(matches) = self.get_match(tuple.0, tuple.1) {
            let Match { handler, params } = matches;
            handler.handler.as_ref().check_continue(params, tuple)
        } else {
            StatusCode::Continue
        }
    }
}

#[cfg(test)]
#[test]
fn simple_test() {
    let mut entry = RouteEntry::with_handler(0u8);
    entry.add_method(MethodRoutes::Get);
    let mut router = HyperRouter::new();
    router.add_path_entry("/test/", entry);

    let res = router.get_match(&Method::Get,
                               &RequestUri::AbsolutePath(String::from("/test/")));
    assert_eq!(res.unwrap().handler.handler, 0u8);

    let res = router.get_match(&Method::Get,
                               &RequestUri::AbsolutePath(String::from("/test2/")));
    assert!(res.is_none());

    let res = router.get_match(&Method::Post,
                               &RequestUri::AbsolutePath(String::from("/test/")));
    assert!(res.is_none());
}

#[cfg(test)]
#[test]
fn multi_method_test() {
    let mut entry = RouteEntry::with_handler(0u8);
    entry.add_method(MethodRoutes::Get);
    entry.add_method(MethodRoutes::Put);
    let mut router = HyperRouter::new();
    router.add_path_entry("/test/", entry);

    let res = router.get_match(&Method::Get,
                               &RequestUri::AbsolutePath(String::from("/test/")));
    assert_eq!(res.unwrap().handler.handler, 0u8);

    let res = router.get_match(&Method::Put,
                               &RequestUri::AbsolutePath(String::from("/test/")));
    assert_eq!(res.unwrap().handler.handler, 0u8);

    let res = router.get_match(&Method::Post,
                               &RequestUri::AbsolutePath(String::from("/test/")));
    assert!(res.is_none());
}

#[cfg(test)]
#[test]
fn create_router_test() {
    let router = create_router! {
        "/test/" => Get, Put => 0u8,
        "/test2/:id" => Delete => 1u8,
    };

    let res = router.get_match(&Method::Get,
                               &RequestUri::AbsolutePath(String::from("/test/")));
    assert_eq!(res.unwrap().handler.handler, 0u8);

    let res = router.get_match(&Method::Put,
                               &RequestUri::AbsolutePath(String::from("/test/")));
    assert_eq!(res.unwrap().handler.handler, 0u8);

    let res = router.get_match(&Method::Delete,
                               &RequestUri::AbsolutePath(String::from("/test/")));
    assert!(res.is_none());

    let res = router.get_match(&Method::Delete,
                               &RequestUri::AbsolutePath(String::from("/test2/test")));
    assert_eq!(res.as_ref().unwrap().handler.handler, 1u8);
    assert_eq!(res.unwrap().params["id"], "test");
}
<|endoftext|>