<commit_before>#![crate_name = "persistent"]
#![license = "MIT"]
#![deny(missing_doc)]
#![deny(warnings)]
#![feature(default_type_params)]

//! A set of middleware for sharing data between requests in the Iron
//! framework.

extern crate iron;
extern crate typemap;
extern crate plugin;

use iron::{Request, Response, BeforeMiddleware, AfterMiddleware, IronResult};
use std::sync::{Arc, RWLock, Mutex};
use typemap::Assoc;
use plugin::{PluginFor, Phantom};

/// Middleware for data that persists between requests with read and write capabilities.
///
/// The data is stored behind a `RWLock`, so multiple read locks
/// can be taken out concurrently.
///
/// If most threads need to take out a write lock, you may want to
/// consider `Write`, which stores the data behind a `Mutex`, which
/// has a faster locking speed.
///
/// `State` can be linked as `BeforeMiddleware` to add data to the `Request`
/// extensions and it can be linked as an `AfterMiddleware` to add data to
/// the `Response` extensions.
///
/// `State` also implements `PluginFor`, so the data stored within can be
/// accessed through `request.get::<State<P, D>>()` as an `Arc<RWLock<D>>`.
pub struct State<P, D> {
    data: Arc<RWLock<D>>
}

/// Middleware for data that persists between Requests with read-only capabilities.
///
/// The data is stored behind an Arc, so multiple threads can have
/// concurrent, non-blocking access.
///
/// `Read` can be linked as `BeforeMiddleware` to add data to the `Request`
/// extensions and it can be linked as an `AfterMiddleware` to add data to
/// the `Response` extensions.
///
/// `Read` also implements `PluginFor`, so the data stored within can be
/// accessed through `request.get::<Read<P, D>>()` as an `Arc<D>`.
pub struct Read<P, D> {
    data: Arc<D>
}

/// Middleware for data that persists between Requests for data which mostly
/// needs to be written instead of read.
///
/// The data is stored behind a `Mutex`, so only one request at a time can
/// access the data. This is more performant than `State` in the case where
/// most uses of the data require a write lock.
///
/// `Write` can be linked as `BeforeMiddleware` to add data to the `Request`
/// extensions and it can be linked as an `AfterMiddleware` to add data to
/// the `Response` extensions.
///
/// `Write` also implements `PluginFor`, so the data stored within can be
/// accessed through `request.get::<Write<P, D>>()` as an `Arc<Mutex<D>>`.
pub struct Write<P, D> {
    data: Arc<Mutex<D>>
}

impl<P, D: Send + Sync> Clone for Read<P, D> {
    fn clone(&self) -> Read<P, D> {
        Read { data: self.data.clone() }
    }
}

impl<P, D: Send + Sync> Clone for State<P, D> {
    fn clone(&self) -> State<P, D> {
        State { data: self.data.clone() }
    }
}

impl<P, D: Send + Sync> Clone for Write<P, D> {
    fn clone(&self) -> Write<P, D> {
        Write { data: self.data.clone() }
    }
}

impl<P, D> Assoc<Arc<RWLock<D>>> for State<P, D> where P: Assoc<D> {}
impl<P, D> Assoc<Arc<D>> for Read<P, D> where P: Assoc<D> {}
impl<P, D> Assoc<Arc<Mutex<D>>> for Write<P, D> where P: Assoc<D> {}

impl<P, D> PluginFor<Request, Arc<RWLock<D>>> for State<P, D>
    where D: Send + Sync,
          P: Assoc<D> {
    fn eval(req: &Request, _: Phantom<State<P, D>>) -> Option<Arc<RWLock<D>>> {
        req.extensions.find::<State<P, D>, Arc<RWLock<D>>>()
            .map(|x| x.clone())
    }
}

impl<P, D> PluginFor<Request, Arc<D>> for Read<P, D>
    where D: Send + Sync,
          P: Assoc<D> {
    fn eval(req: &Request, _: Phantom<Read<P, D>>) -> Option<Arc<D>> {
        req.extensions.find::<Read<P, D>, Arc<D>>()
            .map(|x| x.clone())
    }
}

impl<P, D> PluginFor<Request, Arc<Mutex<D>>> for Write<P, D>
    where D: Send + Sync,
          P: Assoc<D> {
    fn eval(req: &Request, _: Phantom<Write<P, D>>) -> Option<Arc<Mutex<D>>> {
        req.extensions.find::<Write<P, D>, Arc<Mutex<D>>>()
            .map(|x| x.clone())
    }
}

impl<D: Send + Sync, P: Assoc<D>> BeforeMiddleware for State<P, D> {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        req.extensions.insert::<State<P, D>, Arc<RWLock<D>>>(self.data.clone());
        Ok(())
    }
}

impl<D: Send + Sync, P: Assoc<D>> AfterMiddleware for State<P, D> {
    fn after(&self, _: &mut Request, res: &mut Response) -> IronResult<()> {
        res.extensions.insert::<State<P, D>, Arc<RWLock<D>>>(self.data.clone());
        Ok(())
    }
}

impl<D: Send + Sync, P: Assoc<D>> BeforeMiddleware for Read<P, D> {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        req.extensions.insert::<Read<P, D>, Arc<D>>(self.data.clone());
        Ok(())
    }
}

impl<D: Send + Sync, P: Assoc<D>> AfterMiddleware for Read<P, D> {
    fn after(&self, _: &mut Request, res: &mut Response) -> IronResult<()> {
        res.extensions.insert::<Read<P, D>, Arc<D>>(self.data.clone());
        Ok(())
    }
}

impl<D: Send + Sync, P: Assoc<D>> BeforeMiddleware for Write<P, D> {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        req.extensions.insert::<Write<P, D>, Arc<Mutex<D>>>(self.data.clone());
        Ok(())
    }
}

impl<D: Send + Sync, P: Assoc<D>> AfterMiddleware for Write<P, D> {
    fn after(&self, _: &mut Request, res: &mut Response) -> IronResult<()> {
        res.extensions.insert::<Write<P, D>, Arc<Mutex<D>>>(self.data.clone());
        Ok(())
    }
}

impl<P, D> State<P, D> where D: Send + Sync, P: Assoc<D> {
    /// Construct a new pair of `State` that can be passed directly to `Chain::link`.
    ///
    /// The data is initialized with the passed-in value.
    pub fn both(start: D) -> (State<P, D>, State<P, D>) {
        let x = State { data: Arc::new(RWLock::new(start)) };
        (x.clone(), x)
    }

    /// Construct a new `State` that can be passed directly to
    /// `Chain::link_before` or `Chain::link_after`.
    ///
    /// The data is initialized with the passed-in value.
    pub fn one(start: D) -> State<P, D> {
        State { data: Arc::new(RWLock::new(start)) }
    }
}

impl<P, D> Read<P, D> where D: Send + Sync, P: Assoc<D> {
    /// Construct a new pair of `Read` that can be passed directly to `Chain::link`.
    ///
    /// The data is initialized with the passed-in value.
    pub fn both(start: D) -> (Read<P, D>, Read<P, D>) {
        let x = Read { data: Arc::new(start) };
        (x.clone(), x)
    }

    /// Construct a new `Read` that can be passed directly to
    /// `Chain::link_before` or `Chain::link_after`.
    ///
    /// The data is initialized with the passed-in value.
    pub fn one(start: D) -> Read<P, D> {
        Read { data: Arc::new(start) }
    }
}

impl<P, D> Write<P, D> where D: Send + Sync, P: Assoc<D> {
    /// Construct a new pair of `Write` that can be passed directly to `Chain::link`.
    ///
    /// The data is initialized with the passed-in value.
    pub fn both(start: D) -> (Write<P, D>, Write<P, D>) {
        let x = Write { data: Arc::new(Mutex::new(start)) };
        (x.clone(), x)
    }

    /// Construct a new `Write` that can be passed directly to
    /// `Chain::link_before` or `Chain::link_after`.
    ///
    /// The data is initialized with the passed-in value.
    pub fn one(start: D) -> Write<P, D> {
        Write { data: Arc::new(Mutex::new(start)) }
    }
}

<commit_msg>(fix) add explicit 'static lifetimes to val types<commit_after>#![crate_name = "persistent"]
#![license = "MIT"]
#![deny(missing_doc)]
#![deny(warnings)]
#![feature(default_type_params)]

//! A set of middleware for sharing data between requests in the Iron
//! framework.

extern crate iron;
extern crate typemap;
extern crate plugin;

use iron::{Request, Response, BeforeMiddleware, AfterMiddleware, IronResult};
use std::sync::{Arc, RWLock, Mutex};
use typemap::Assoc;
use plugin::{PluginFor, Phantom};

/// Middleware for data that persists between requests with read and write capabilities.
///
/// The data is stored behind a `RWLock`, so multiple read locks
/// can be taken out concurrently.
///
/// If most threads need to take out a write lock, you may want to
/// consider `Write`, which stores the data behind a `Mutex`, which
/// has a faster locking speed.
///
/// `State` can be linked as `BeforeMiddleware` to add data to the `Request`
/// extensions and it can be linked as an `AfterMiddleware` to add data to
/// the `Response` extensions.
///
/// `State` also implements `PluginFor`, so the data stored within can be
/// accessed through `request.get::<State<P, D>>()` as an `Arc<RWLock<D>>`.
pub struct State<P, D> {
    data: Arc<RWLock<D>>
}

/// Middleware for data that persists between Requests with read-only capabilities.
///
/// The data is stored behind an Arc, so multiple threads can have
/// concurrent, non-blocking access.
///
/// `Read` can be linked as `BeforeMiddleware` to add data to the `Request`
/// extensions and it can be linked as an `AfterMiddleware` to add data to
/// the `Response` extensions.
///
/// `Read` also implements `PluginFor`, so the data stored within can be
/// accessed through `request.get::<Read<P, D>>()` as an `Arc<D>`.
pub struct Read<P, D> {
    data: Arc<D>
}

/// Middleware for data that persists between Requests for data which mostly
/// needs to be written instead of read.
///
/// The data is stored behind a `Mutex`, so only one request at a time can
/// access the data. This is more performant than `State` in the case where
/// most uses of the data require a write lock.
///
/// `Write` can be linked as `BeforeMiddleware` to add data to the `Request`
/// extensions and it can be linked as an `AfterMiddleware` to add data to
/// the `Response` extensions.
///
/// `Write` also implements `PluginFor`, so the data stored within can be
/// accessed through `request.get::<Write<P, D>>()` as an `Arc<Mutex<D>>`.
pub struct Write<P, D> {
    data: Arc<Mutex<D>>
}

impl<P, D: Send + Sync> Clone for Read<P, D> {
    fn clone(&self) -> Read<P, D> {
        Read { data: self.data.clone() }
    }
}

impl<P, D: Send + Sync> Clone for State<P, D> {
    fn clone(&self) -> State<P, D> {
        State { data: self.data.clone() }
    }
}

impl<P, D: Send + Sync> Clone for Write<P, D> {
    fn clone(&self) -> Write<P, D> {
        Write { data: self.data.clone() }
    }
}

impl<P, D:'static> Assoc<Arc<RWLock<D>>> for State<P, D> where P: Assoc<D> {}
impl<P, D:'static> Assoc<Arc<D>> for Read<P, D> where P: Assoc<D> {}
impl<P, D:'static> Assoc<Arc<Mutex<D>>> for Write<P, D> where P: Assoc<D> {}

impl<P, D> PluginFor<Request, Arc<RWLock<D>>> for State<P, D>
    where D: Send + Sync,
          P: Assoc<D> {
    fn eval(req: &Request, _: Phantom<State<P, D>>) -> Option<Arc<RWLock<D>>> {
        req.extensions.find::<State<P, D>, Arc<RWLock<D>>>()
            .map(|x| x.clone())
    }
}

impl<P, D> PluginFor<Request, Arc<D>> for Read<P, D>
    where D: Send + Sync,
          P: Assoc<D> {
    fn eval(req: &Request, _: Phantom<Read<P, D>>) -> Option<Arc<D>> {
        req.extensions.find::<Read<P, D>, Arc<D>>()
            .map(|x| x.clone())
    }
}

impl<P, D> PluginFor<Request, Arc<Mutex<D>>> for Write<P, D>
    where D: Send + Sync,
          P: Assoc<D> {
    fn eval(req: &Request, _: Phantom<Write<P, D>>) -> Option<Arc<Mutex<D>>> {
        req.extensions.find::<Write<P, D>, Arc<Mutex<D>>>()
            .map(|x| x.clone())
    }
}

impl<D: Send + Sync, P: Assoc<D>> BeforeMiddleware for State<P, D> {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        req.extensions.insert::<State<P, D>, Arc<RWLock<D>>>(self.data.clone());
        Ok(())
    }
}

impl<D: Send + Sync, P: Assoc<D>> AfterMiddleware for State<P, D> {
    fn after(&self, _: &mut Request, res: &mut Response) -> IronResult<()> {
        res.extensions.insert::<State<P, D>, Arc<RWLock<D>>>(self.data.clone());
        Ok(())
    }
}

impl<D: Send + Sync, P: Assoc<D>> BeforeMiddleware for Read<P, D> {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        req.extensions.insert::<Read<P, D>, Arc<D>>(self.data.clone());
        Ok(())
    }
}

impl<D: Send + Sync, P: Assoc<D>> AfterMiddleware for Read<P, D> {
    fn after(&self, _: &mut Request, res: &mut Response) -> IronResult<()> {
        res.extensions.insert::<Read<P, D>, Arc<D>>(self.data.clone());
        Ok(())
    }
}

impl<D: Send + Sync, P: Assoc<D>> BeforeMiddleware for Write<P, D> {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        req.extensions.insert::<Write<P, D>, Arc<Mutex<D>>>(self.data.clone());
        Ok(())
    }
}

impl<D: Send + Sync, P: Assoc<D>> AfterMiddleware for Write<P, D> {
    fn after(&self, _: &mut Request, res: &mut Response) -> IronResult<()> {
        res.extensions.insert::<Write<P, D>, Arc<Mutex<D>>>(self.data.clone());
        Ok(())
    }
}

impl<P, D> State<P, D> where D: Send + Sync, P: Assoc<D> {
    /// Construct a new pair of `State` that can be passed directly to `Chain::link`.
    ///
    /// The data is initialized with the passed-in value.
    pub fn both(start: D) -> (State<P, D>, State<P, D>) {
        let x = State { data: Arc::new(RWLock::new(start)) };
        (x.clone(), x)
    }

    /// Construct a new `State` that can be passed directly to
    /// `Chain::link_before` or `Chain::link_after`.
    ///
    /// The data is initialized with the passed-in value.
    pub fn one(start: D) -> State<P, D> {
        State { data: Arc::new(RWLock::new(start)) }
    }
}

impl<P, D> Read<P, D> where D: Send + Sync, P: Assoc<D> {
    /// Construct a new pair of `Read` that can be passed directly to `Chain::link`.
    ///
    /// The data is initialized with the passed-in value.
    pub fn both(start: D) -> (Read<P, D>, Read<P, D>) {
        let x = Read { data: Arc::new(start) };
        (x.clone(), x)
    }

    /// Construct a new `Read` that can be passed directly to
    /// `Chain::link_before` or `Chain::link_after`.
    ///
    /// The data is initialized with the passed-in value.
    pub fn one(start: D) -> Read<P, D> {
        Read { data: Arc::new(start) }
    }
}

impl<P, D> Write<P, D> where D: Send + Sync, P: Assoc<D> {
    /// Construct a new pair of `Write` that can be passed directly to `Chain::link`.
    ///
    /// The data is initialized with the passed-in value.
    pub fn both(start: D) -> (Write<P, D>, Write<P, D>) {
        let x = Write { data: Arc::new(Mutex::new(start)) };
        (x.clone(), x)
    }

    /// Construct a new `Write` that can be passed directly to
    /// `Chain::link_before` or `Chain::link_after`.
    ///
    /// The data is initialized with the passed-in value.
    pub fn one(start: D) -> Write<P, D> {
        Write { data: Arc::new(Mutex::new(start)) }
    }
}
<|endoftext|>


<commit_before>//! This library provides [`anyhow::Error`][Error], a trait object based error
//! type for easy idiomatic error handling in Rust applications.
//!
//!

//!
//! # Details
//!
//! - Use `Result<T, anyhow::Error>`, or equivalently `anyhow::Result<T>`, as
//!   the return type of any fallible function.
//!
//!   Within the function, use `?` to easily propagate any error that implements
//!   the `std::error::Error` trait.
//!
//!   ```
//!   # pub trait Deserialize {}
//!   #
//!   # mod serde_json {
//!   #     use super::Deserialize;
//!   #     use std::io;
//!   #
//!   #     pub fn from_str<T: Deserialize>(json: &str) -> io::Result<T> {
//!   #         unimplemented!()
//!   #     }
//!   # }
//!   #
//!   # struct ClusterMap;
//!   #
//!   # impl Deserialize for ClusterMap {}
//!   #
//!   use anyhow::Result;
//!
//!   fn get_cluster_info() -> Result<ClusterMap> {
//!       let config = std::fs::read_to_string("cluster.json")?;
//!       let map: ClusterMap = serde_json::from_str(&config)?;
//!       Ok(map)
//!   }
//!   #
//!   # fn main() {}
//!   ```
//!
//! - Attach context to help the person troubleshooting the error understand
//!   where things went wrong. A low-level error like "No such file or
//!   directory" can be annoying to debug without more context about what higher
//!   level step the application was in the middle of.
//!
//!   ```
//!   # struct It;
//!   #
//!   # impl It {
//!   #     fn detach(&self) -> Result<()> {
//!   #         unimplemented!()
//!   #     }
//!   # }
//!   #
//!   use anyhow::{Context, Result};
//!
//!   fn main() -> Result<()> {
//!       # return Ok(());
//!       #
//!       # const _: &str = stringify! {
//!       ...
//!       # };
//!       #
//!       # let it = It;
//!       # let path = "./path/to/instrs.jsox";
//!       #
//!       it.detach().context("failed to detach the important thing")?;
//!
//!       let content = std::fs::read(path)
//!           .with_context(|| format!("failed to read instrs from {}", path))?;
//!       #
//!       # const _: &str = stringify! {
//!       ...
//!       # };
//!       #
//!       # Ok(())
//!   }
//!   ```
//!
//!   ```console
//!   Error: failed to read instrs from ./path/to/instrs.jsox
//!
//!   caused by:
//!       0: No such file or directory (os error 2)
//!   ```
//!
//! - Downcasting is supported and can be by value, by shared reference, or by
//!   mutable reference as needed.
//!
//!   ```
//!   # use anyhow::anyhow;
//!   # use std::fmt::{self, Display};
//!   # use std::task::Poll;
//!   #
//!   # #[derive(Debug)]
//!   # enum DataStoreError {
//!   #     Censored(()),
//!   # }
//!   #
//!   # impl Display for DataStoreError {
//!   #     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
//!   #         unimplemented!()
//!   #     }
//!   # }
//!   #
//!   # impl std::error::Error for DataStoreError {}
//!   #
//!   # const REDACTED_CONTENT: () = ();
//!   #
//!   # let error = anyhow!("...");
//!   # let root_cause = &error;
//!   #
//!   # let ret =
//!   // If the error was caused by redaction, then return a
//!   // tombstone instead of the content.
//!   match root_cause.downcast_ref::<DataStoreError>() {
//!       Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)),
//!       None => Err(error),
//!   }
//!   # ;
//!   ```
//!
//! - A backtrace is captured and printed with the error if the underlying error
//!   type does not already provide its own. In order to see backtraces, the
//!   `RUST_LIB_BACKTRACE=1` environment variable must be defined.
//!
//! - Anyhow works with any error type that has an impl of `std::error::Error`,
//!   including ones defined in your crate. We do not bundle a `derive(Error)`
//!   macro but you can write the impls yourself or use a standalone macro like
//!   [err-derive].
//!
//!   [err-derive]: https://crates.io/crates/err-derive
//!
//!   ```
//!   # const IGNORE: &str = stringify! {
//!   #[derive(Error, Debug)]
//!   pub enum FormatError {
//!       #[error(display = "invalid header (expected {:?}, got {:?})", expected, found)]
//!       InvalidHeader {
//!           expected: String,
//!           found: String,
//!       },
//!       #[error(display = "missing attribute: {}", _0)]
//!       MissingAttribute(String),
//!   }
//!   # };
//!   ```
//!
//! - One-off error messages can be constructed using the `anyhow!` macro, which
//!   supports string interpolation and produces an `anyhow::Error`.
//!
//!   ```
//!   # use anyhow::{anyhow, Result};
//!   #
//!   # fn demo() -> Result<()> {
//!   #     let missing = "...";
//!   return Err(anyhow!("missing attribute: {}", missing));
//!   #     Ok(())
//!   # }
//!   ```
//!
//!

//!
//! # Acknowledgements
//!
//! The implementation of the `anyhow::Error` type is forked from
//! `fehler::Exception` ([https://github.com/withoutboats/fehler][fehler]). This
//! library just exposes it under the more standard `Error` / `Result`
//! terminology rather than the `throw!` / `#[throws]` / `Exception` language of
//! exceptions.
//!
//! [fehler]: https://github.com/withoutboats/fehler

#![doc(html_root_url = "https://docs.rs/anyhow/1.0.0-alpha.1")]
#![cfg_attr(backtrace, feature(backtrace))]

mod context;
mod error;

#[cfg(not(feature = "std"))]
compile_error!("no_std support is not implemented yet");

pub use crate::context::Context;
pub use crate::error::{Chain, Error};

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

/// Return early with an error.
///
/// This macro is equivalent to `return Err(From::from($err))`.
#[macro_export]
macro_rules! bail {
    ($err:expr $(,)?) => {
        return std::result::Result::Err(std::convert::From::from($err));
    };
}

/// Construct an ad-hoc error from a string.
///
/// This evaluates to an `Error`. It can take either just a string, or a format
/// string with arguments. It also can take any custom type which implements
/// `Debug` and `Display`.
#[macro_export]
macro_rules! anyhow {
    ($msg:expr $(,)?) => {
        $crate::private::new_adhoc($msg)
    };
    ($fmt:expr, $($arg:tt)*) => {
        $crate::private::new_adhoc(format!($fmt, $($arg)*))
    };
}

// Not public API.
#[doc(hidden)]
pub mod private {
    use crate::Error;
    use std::fmt::{Debug, Display};

    #[cfg(backtrace)]
    use std::backtrace::Backtrace;

    pub fn new_adhoc<M>(message: M) -> Error
    where
        M: Display + Debug + Send + Sync + 'static,
    {
        #[cfg(backtrace)]
        let backtrace = Some(Backtrace::capture());

        #[cfg(not(backtrace))]
        let backtrace = None;

        Error::new_adhoc(message, backtrace)
    }
}
<commit_msg>Document anyhow::Result with example<commit_after>//! This library provides [`anyhow::Error`][Error], a trait object based error
//! type for easy idiomatic error handling in Rust applications.
//!
//!

//!
//! # Details
//!
//! - Use `Result<T, anyhow::Error>`, or equivalently `anyhow::Result<T>`, as
//!   the return type of any fallible function.
//!
//!   Within the function, use `?` to easily propagate any error that implements
//!   the `std::error::Error` trait.
//!
//!   ```
//!   # pub trait Deserialize {}
//!   #
//!   # mod serde_json {
//!   #     use super::Deserialize;
//!   #     use std::io;
//!   #
//!   #     pub fn from_str<T: Deserialize>(json: &str) -> io::Result<T> {
//!   #         unimplemented!()
//!   #     }
//!   # }
//!   #
//!   # struct ClusterMap;
//!   #
//!   # impl Deserialize for ClusterMap {}
//!   #
//!   use anyhow::Result;
//!
//!   fn get_cluster_info() -> Result<ClusterMap> {
//!       let config = std::fs::read_to_string("cluster.json")?;
//!       let map: ClusterMap = serde_json::from_str(&config)?;
//!       Ok(map)
//!   }
//!   #
//!   # fn main() {}
//!   ```
//!
//! - Attach context to help the person troubleshooting the error understand
//!   where things went wrong. A low-level error like "No such file or
//!   directory" can be annoying to debug without more context about what higher
//!   level step the application was in the middle of.
//!
//!   ```
//!   # struct It;
//!   #
//!   # impl It {
//!   #     fn detach(&self) -> Result<()> {
//!   #         unimplemented!()
//!   #     }
//!   # }
//!   #
//!   use anyhow::{Context, Result};
//!
//!   fn main() -> Result<()> {
//!       # return Ok(());
//!       #
//!       # const _: &str = stringify! {
//!       ...
//!       # };
//!       #
//!       # let it = It;
//!       # let path = "./path/to/instrs.jsox";
//!       #
//!       it.detach().context("failed to detach the important thing")?;
//!
//!       let content = std::fs::read(path)
//!           .with_context(|| format!("failed to read instrs from {}", path))?;
//!       #
//!       # const _: &str = stringify! {
//!       ...
//!       # };
//!       #
//!       # Ok(())
//!   }
//!   ```
//!
//!   ```console
//!   Error: failed to read instrs from ./path/to/instrs.jsox
//!
//!   caused by:
//!       0: No such file or directory (os error 2)
//!   ```
//!
//! - Downcasting is supported and can be by value, by shared reference, or by
//!   mutable reference as needed.
//!
//!   ```
//!   # use anyhow::anyhow;
//!   # use std::fmt::{self, Display};
//!   # use std::task::Poll;
//!   #
//!   # #[derive(Debug)]
//!   # enum DataStoreError {
//!   #     Censored(()),
//!   # }
//!   #
//!   # impl Display for DataStoreError {
//!   #     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
//!   #         unimplemented!()
//!   #     }
//!   # }
//!   #
//!   # impl std::error::Error for DataStoreError {}
//!   #
//!   # const REDACTED_CONTENT: () = ();
//!   #
//!   # let error = anyhow!("...");
//!   # let root_cause = &error;
//!   #
//!   # let ret =
//!   // If the error was caused by redaction, then return a
//!   // tombstone instead of the content.
//!   match root_cause.downcast_ref::<DataStoreError>() {
//!       Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)),
//!       None => Err(error),
//!   }
//!   # ;
//!   ```
//!
//! - A backtrace is captured and printed with the error if the underlying error
//!   type does not already provide its own. In order to see backtraces, the
//!   `RUST_LIB_BACKTRACE=1` environment variable must be defined.
//!
//! - Anyhow works with any error type that has an impl of `std::error::Error`,
//!   including ones defined in your crate. We do not bundle a `derive(Error)`
//!   macro but you can write the impls yourself or use a standalone macro like
//!   [err-derive].
//!
//!   [err-derive]: https://crates.io/crates/err-derive
//!
//!   ```
//!   # const IGNORE: &str = stringify! {
//!   #[derive(Error, Debug)]
//!   pub enum FormatError {
//!       #[error(display = "invalid header (expected {:?}, got {:?})", expected, found)]
//!       InvalidHeader {
//!           expected: String,
//!           found: String,
//!       },
//!       #[error(display = "missing attribute: {}", _0)]
//!       MissingAttribute(String),
//!   }
//!   # };
//!   ```
//!
//! - One-off error messages can be constructed using the `anyhow!` macro, which
//!   supports string interpolation and produces an `anyhow::Error`.
//!
//!   ```
//!   # use anyhow::{anyhow, Result};
//!   #
//!   # fn demo() -> Result<()> {
//!   #     let missing = "...";
//!   return Err(anyhow!("missing attribute: {}", missing));
//!   #     Ok(())
//!   # }
//!   ```
//!
//!

//!
//! # Acknowledgements
//!
//! The implementation of the `anyhow::Error` type is forked from
//! `fehler::Exception` ([https://github.com/withoutboats/fehler][fehler]). This
//! library just exposes it under the more standard `Error` / `Result`
//! terminology rather than the `throw!` / `#[throws]` / `Exception` language of
//! exceptions.
//!
//! [fehler]: https://github.com/withoutboats/fehler

#![doc(html_root_url = "https://docs.rs/anyhow/1.0.0-alpha.1")]
#![cfg_attr(backtrace, feature(backtrace))]

mod context;
mod error;

#[cfg(not(feature = "std"))]
compile_error!("no_std support is not implemented yet");

pub use crate::context::Context;
pub use crate::error::{Chain, Error};

/// `Result<T, Error>`
///
/// # Example
///
/// ```
/// # pub trait Deserialize {}
/// #
/// # mod serde_json {
/// #     use super::Deserialize;
/// #     use std::io;
/// #
/// #     pub fn from_str<T: Deserialize>(json: &str) -> io::Result<T> {
/// #         unimplemented!()
/// #     }
/// # }
/// #
/// # #[derive(Debug)]
/// # struct ClusterMap;
/// #
/// # impl Deserialize for ClusterMap {}
/// #
/// use anyhow::Result;
///
/// fn main() -> Result<()> {
///     # return Ok(());
///     let config = std::fs::read_to_string("cluster.json")?;
///     let map: ClusterMap = serde_json::from_str(&config)?;
///     println!("cluster info: {:#?}", map);
///     Ok(())
/// }
/// ```
pub type Result<T> = std::result::Result<T, Error>;

/// Return early with an error.
///
/// This macro is equivalent to `return Err(From::from($err))`.
#[macro_export]
macro_rules! bail {
    ($err:expr $(,)?) => {
        return std::result::Result::Err(std::convert::From::from($err));
    };
}

/// Construct an ad-hoc error from a string.
///
/// This evaluates to an `Error`. It can take either just a string, or a format
/// string with arguments. It also can take any custom type which implements
/// `Debug` and `Display`.
#[macro_export]
macro_rules! anyhow {
    ($msg:expr $(,)?) => {
        $crate::private::new_adhoc($msg)
    };
    ($fmt:expr, $($arg:tt)*) => {
        $crate::private::new_adhoc(format!($fmt, $($arg)*))
    };
}

// Not public API.
#[doc(hidden)]
pub mod private {
    use crate::Error;
    use std::fmt::{Debug, Display};

    #[cfg(backtrace)]
    use std::backtrace::Backtrace;

    pub fn new_adhoc<M>(message: M) -> Error
    where
        M: Display + Debug + Send + Sync + 'static,
    {
        #[cfg(backtrace)]
        let backtrace = Some(Backtrace::capture());

        #[cfg(not(backtrace))]
        let backtrace = None;

        Error::new_adhoc(message, backtrace)
    }
}
<|endoftext|>


<commit_before>use std::ops::Deref;
use std::cmp::Ordering;

/// A `Vec` in sorted order without duplicates.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SortedUniqueVec<T: Ord + Clone> {
    vec: Vec<T>,
}

pub fn is_sorted_unique<T: Ord>(slice: &[T]) -> bool {
    if slice.len() < 2 {
        true
    } else {
        slice.windows(2).all(|win| win[0] < win[1])
    }
}

pub enum LeftOrRight {
    Left,
    Right,
}

impl<T: Ord + Clone> SortedUniqueVec<T> {
    pub fn new() -> Self {
        SortedUniqueVec { vec: Vec::new() }
    }

    pub fn with_capacity(capa: usize) -> Self {
        SortedUniqueVec { vec: Vec::with_capacity(capa) }
    }

    /// Panics if sorted order is destroyed by this push operation.
    pub fn push(&mut self, item: T) {
        if let Some(last_item) = self.last() {
            assert!(last_item < &item);
        }
        self.vec.push(item);
    }

    pub fn retain<F>(&mut self, f: F)
        where F: FnMut(&T) -> bool
    {
        self.vec.retain(f);
    }

    pub fn len(&self) -> usize {
        self.vec.len()
    }

    pub fn contains(&self, element: &T) -> bool {
        self.vec.binary_search(element).is_ok()
    }

    pub fn get(&self, idx: usize) -> Option<&T> {
        self.vec.get(idx)
    }

    pub fn get_mut(&mut self, idx: usize) -> Option<&mut T> {
        self.vec.get_mut(idx)
    }

    pub fn index_by<F>(&self, f: F) -> Option<usize>
        where F: FnMut(&T) -> Ordering
    {
        match self.vec.binary_search_by(f) {
            Ok(idx) => Some(idx),
            Err(_) => None,
        }
    }

    pub fn find_by<F>(&self, f: F) -> Option<&T>
        where F: FnMut(&T) -> Ordering
    {
        match self.vec.binary_search_by(f) {
            Ok(idx) => self.vec.get(idx),
            Err(_) => None,
        }
    }

    /// Insert `element` into the sorted list.
    ///
    /// Panics if an element with the same key (according to the Eq trait) already exists.
    pub fn insert(&mut self, element: T) {
        match self.vec.binary_search(&element) {
            Ok(_idx) => {
                panic!("Element already exists");
            }
            Err(idx) => {
                self.vec.insert(idx, element);
            }
        }
    }

    /// Merges `self` and `other` into a new SortedVec.
    /// `choose_equal` decides which one of two equal values to take.
    pub fn merge<F>(&self, other: &Self, choose_equal: &F) -> Self
        where F: Fn(&T, &T) -> LeftOrRight
    {
        let mut vec = Vec::with_capacity(self.len() + other.len());

        let mut left_iter = self.vec.iter().peekable();
        let mut right_iter = other.vec.iter().peekable();

        enum Take {
            OneLeft,
            OneRight,
            Both,
            AllLeft,
            AllRight,
        };

        loop {
            let take;

            match (left_iter.peek(), right_iter.peek()) {
                (Some(l), Some(r)) => {
                    if l < r {
                        take = Take::OneLeft;
                    } else if r < l {
                        take = Take::OneRight;
                    } else {
                        take = Take::Both;
                    }
                }
                (Some(_), None) => {
                    take = Take::AllLeft;
                }
                (None, Some(_)) => {
                    take = Take::AllRight;
                }
                (None, None) => {
                    break;
                }
            }
            match take {
                Take::OneLeft => {
                    vec.push((*left_iter.next().unwrap()).clone());
                }
                Take::OneRight => {
                    vec.push((*right_iter.next().unwrap()).clone());
                }
                Take::Both => {
                    // two equal values
                    let left_value = left_iter.next().unwrap();
                    let right_value = right_iter.next().unwrap();
                    match choose_equal(left_value, right_value) {
                        LeftOrRight::Left => {
                            vec.push((*left_value).clone());
                        }
                        LeftOrRight::Right => {
                            vec.push((*right_value).clone());
                        }
                    }
                }
                Take::AllLeft => {
                    for item in left_iter {
                        vec.push((*item).clone());
                    }
                    break;
                }
                Take::AllRight => {
                    for item in right_iter {
                        vec.push((*item).clone());
                    }
                    break;
                }

            }
        }

        debug_assert!(is_sorted_unique(&vec));
        SortedUniqueVec { vec: vec }
    }
}

impl<T: Ord + Clone> AsRef<[T]> for SortedUniqueVec<T> {
    fn as_ref(&self) -> &[T] {
        &self.vec
    }
}

impl<T: Ord + Clone> Deref for SortedUniqueVec<T> {
    type Target = [T];

    fn deref(&self) -> &[T] {
        &self.vec
    }
}

#[test]
fn test_insert() {
    let mut s = SortedUniqueVec::new();
    s.insert(5);
    s.insert(1);
    s.insert(8);
    s.insert(0);
    assert!(is_sorted_unique(&s));
    assert_eq!(&[0, 1, 5, 8][..], s.as_ref());
    assert_eq!(4, s.len());
}

#[test]
fn test_merge() {
    let mut s1 = SortedUniqueVec::new();
    s1.insert(5);
    s1.insert(1);
    s1.insert(8);
    s1.insert(0);
    assert!(is_sorted_unique(&s1));

    let mut s2 = SortedUniqueVec::new();
    s2.insert(55);
    s2.insert(1);
    s2.insert(5);
    s2.insert(7);
    s2.insert(9);
    assert!(is_sorted_unique(&s2));

    let r = s1.merge(&s2, &|_, _| LeftOrRight::Left);
    assert!(is_sorted_unique(&r));
    assert_eq!(&[0, 1, 5, 7, 8, 9, 55][..], r.as_ref());
}

#[test]
fn test_push_ok() {
    let mut s = SortedUniqueVec::new();
    s.push(0);
    s.push(5);
    s.push(6);
    assert!(is_sorted_unique(&s));
    assert_eq!(3, s.len());
    assert_eq!(&[0, 5, 6][..], s.as_ref());
}

#[test]
#[should_panic]
fn test_push_fail() {
    let mut s = SortedUniqueVec::new();
    s.push(0);
    s.push(1);
    s.push(1);
}

#[test]
#[should_panic]
fn test_push_fail2() {
    let mut s = SortedUniqueVec::new();
    s.push(0);
    s.push(5);
    s.push(9);
    s.push(3);
}
<commit_msg>Add slice_mut. Note that mutation can modify the sort order!<commit_after>use std::ops::Deref;
use std::cmp::Ordering;

/// A `Vec` in sorted order without duplicates.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SortedUniqueVec<T: Ord + Clone> {
    vec: Vec<T>,
}

pub fn is_sorted_unique<T: Ord>(slice: &[T]) -> bool {
    if slice.len() < 2 {
        true
    } else {
        slice.windows(2).all(|win| win[0] < win[1])
    }
}

pub enum LeftOrRight {
    Left,
    Right,
}

impl<T: Ord + Clone> SortedUniqueVec<T> {
    pub fn new() -> Self {
        SortedUniqueVec { vec: Vec::new() }
    }

    pub fn with_capacity(capa: usize) -> Self {
        SortedUniqueVec { vec: Vec::with_capacity(capa) }
    }

    /// Panics if sorted order is destroyed by this push operation.
    pub fn push(&mut self, item: T) {
        if let Some(last_item) = self.last() {
            assert!(last_item < &item);
        }
        self.vec.push(item);
    }

    pub fn retain<F>(&mut self, f: F)
        where F: FnMut(&T) -> bool
    {
        self.vec.retain(f);
    }

    pub fn len(&self) -> usize {
        self.vec.len()
    }

    pub fn contains(&self, element: &T) -> bool {
        self.vec.binary_search(element).is_ok()
    }

    pub fn get(&self, idx: usize) -> Option<&T> {
        self.vec.get(idx)
    }

    /// Note: This can destroy the sort order!
    pub fn get_mut(&mut self, idx: usize) -> Option<&mut T> {
        self.vec.get_mut(idx)
    }

    /// Note: This can destroy the sort order!
    pub fn slice_mut(&mut self) -> &mut[T] {
        &mut self.vec[..]
    }

    pub fn index_by<F>(&self, f: F) -> Option<usize>
        where F: FnMut(&T) -> Ordering
    {
        match self.vec.binary_search_by(f) {
            Ok(idx) => Some(idx),
            Err(_) => None,
        }
    }

    pub fn find_by<F>(&self, f: F) -> Option<&T>
        where F: FnMut(&T) -> Ordering
    {
        match self.vec.binary_search_by(f) {
            Ok(idx) => self.vec.get(idx),
            Err(_) => None,
        }
    }

    /// Insert `element` into the sorted list.
    ///
    /// Panics if an element with the same key (according to the Eq trait) already exists.
    pub fn insert(&mut self, element: T) {
        match self.vec.binary_search(&element) {
            Ok(_idx) => {
                panic!("Element already exists");
            }
            Err(idx) => {
                self.vec.insert(idx, element);
            }
        }
    }

    /// Merges `self` and `other` into a new SortedVec.
    /// `choose_equal` decides which one of two equal values to take.
    pub fn merge<F>(&self, other: &Self, choose_equal: &F) -> Self
        where F: Fn(&T, &T) -> LeftOrRight
    {
        let mut vec = Vec::with_capacity(self.len() + other.len());

        let mut left_iter = self.vec.iter().peekable();
        let mut right_iter = other.vec.iter().peekable();

        enum Take {
            OneLeft,
            OneRight,
            Both,
            AllLeft,
            AllRight,
        };

        loop {
            let take;

            match (left_iter.peek(), right_iter.peek()) {
                (Some(l), Some(r)) => {
                    if l < r {
                        take = Take::OneLeft;
                    } else if r < l {
                        take = Take::OneRight;
                    } else {
                        take = Take::Both;
                    }
                }
                (Some(_), None) => {
                    take = Take::AllLeft;
                }
                (None, Some(_)) => {
                    take = Take::AllRight;
                }
                (None, None) => {
                    break;
                }
            }
            match take {
                Take::OneLeft => {
                    vec.push((*left_iter.next().unwrap()).clone());
                }
                Take::OneRight => {
                    vec.push((*right_iter.next().unwrap()).clone());
                }
                Take::Both => {
                    // two equal values
                    let left_value = left_iter.next().unwrap();
                    let right_value = right_iter.next().unwrap();
                    match choose_equal(left_value, right_value) {
                        LeftOrRight::Left => {
                            vec.push((*left_value).clone());
                        }
                        LeftOrRight::Right => {
                            vec.push((*right_value).clone());
                        }
                    }
                }
                Take::AllLeft => {
                    for item in left_iter {
                        vec.push((*item).clone());
                    }
                    break;
                }
                Take::AllRight => {
                    for item in right_iter {
                        vec.push((*item).clone());
                    }
                    break;
                }

            }
        }

        debug_assert!(is_sorted_unique(&vec));
        SortedUniqueVec { vec: vec }
    }
}

impl<T: Ord + Clone> AsRef<[T]> for SortedUniqueVec<T> {
    fn as_ref(&self) -> &[T] {
        &self.vec
    }
}

impl<T: Ord + Clone> Deref for SortedUniqueVec<T> {
    type Target = [T];

    fn deref(&self) -> &[T] {
        &self.vec
    }
}

#[test]
fn test_insert() {
    let mut s = SortedUniqueVec::new();
    s.insert(5);
    s.insert(1);
    s.insert(8);
    s.insert(0);
    assert!(is_sorted_unique(&s));
    assert_eq!(&[0, 1, 5, 8][..], s.as_ref());
    assert_eq!(4, s.len());
}

#[test]
fn test_merge() {
    let mut s1 = SortedUniqueVec::new();
    s1.insert(5);
    s1.insert(1);
    s1.insert(8);
    s1.insert(0);
    assert!(is_sorted_unique(&s1));

    let mut s2 = SortedUniqueVec::new();
    s2.insert(55);
    s2.insert(1);
    s2.insert(5);
    s2.insert(7);
    s2.insert(9);
    assert!(is_sorted_unique(&s2));

    let r = s1.merge(&s2, &|_, _| LeftOrRight::Left);
    assert!(is_sorted_unique(&r));
    assert_eq!(&[0, 1, 5, 7, 8, 9, 55][..], r.as_ref());
}

#[test]
fn test_push_ok() {
    let mut s = SortedUniqueVec::new();
    s.push(0);
    s.push(5);
    s.push(6);
    assert!(is_sorted_unique(&s));
    assert_eq!(3, s.len());
    assert_eq!(&[0, 5, 6][..], s.as_ref());
}

#[test]
#[should_panic]
fn test_push_fail() {
    let mut s = SortedUniqueVec::new();
    s.push(0);
    s.push(1);
    s.push(1);
}

#[test]
#[should_panic]
fn test_push_fail2() {
    let mut s = SortedUniqueVec::new();
    s.push(0);
    s.push(5);
    s.push(9);
    s.push(3);
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// #![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico")]

#![allow(unused_features)]
#![feature(std_misc, libc, asm, core, alloc, test, unboxed_closures, page_size, core_simd, rt)]
#![feature(rustc_private)]
#![feature(unique)]

#[macro_use] extern crate log;
extern crate libc;
extern crate test;
extern crate mmap;
#[cfg(feature = "enable-clonable-handle")]
extern crate spin;

use std::any::Any;
use std::fmt::{self, Debug};

#[cfg(feature = "enable-clonable-handle")]
pub use coroutine_clonable as coroutine;

#[cfg(not(feature = "enable-clonable-handle"))]
pub use coroutine_unique as coroutine;

pub use builder::Builder;
pub use coroutine::{Coroutine, Handle};
pub use options::Options;

mod context;
#[cfg(feature = "enable-clonable-handle")]
pub mod coroutine_clonable;
#[cfg(not(feature = "enable-clonable-handle"))]
pub mod coroutine_unique;

pub mod builder;
pub mod options;
mod stack;
mod thunk; // use self-maintained thunk, because std::thunk is temporary. May be replaced by FnBox in the future.
mod sys;
mod environment;

#[cfg(test)]
mod tests;
#[cfg(test)]
mod benchmarks;

/// Spawn a new Coroutine
///
/// Equavalent to `Coroutine::spawn`.
pub fn spawn<F>(f: F) -> Handle
    where F: FnOnce() + Send + 'static
{
    Builder::new().spawn(f)
}

/// Get the current Coroutine
///
/// Equavalent to `Coroutine::current`.
pub fn current() -> &'static Handle {
    Coroutine::current()
}

/// Resume a Coroutine
///
/// Equavalent to `Coroutine::resume`.
pub fn resume(coro: &Handle) -> Result {
    coro.resume()
}

/// Yield the current Coroutine with `Suspended` state
///
/// Equavalent to `Coroutine::sched`.
pub fn sched() {
    Coroutine::sched()
}

/// Yield the current Coroutine with `Blocked` state
///
/// Equavalent to `Coroutine::block`.
pub fn block() {
    Coroutine::block()
}

/// State of a Coroutine
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum State {
    /// Waiting its child to return
    Normal,

    /// Suspended. Can be waked up by `resume`
    Suspended,

    /// Blocked. Can be waked up by `resume`
    Blocked,

    /// Running
    Running,

    /// Finished
    Finished,

    /// Panic happened inside, cannot be resumed again
    Panicked,
}

/// Return type of resuming. Ok if resume successfully with the current state,
/// Err if resume failed with `Error`.
pub type Result = ::std::result::Result<State, Error>;

/// Resume Error
pub enum Error {
    /// Coroutine is already finished
    Finished,

    /// Coroutine is waiting for its child to yield (state is Normal)
    Waiting,

    /// Coroutine is panicked
    Panicked,

    /// Coroutine is panicking, carry with the parameter of `panic!()`
    Panicking(Box<Any + Send>),
}

impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::Finished => write!(f, "Finished"),
            &Error::Waiting => write!(f, "Waiting"),
            &Error::Panicked => write!(f, "Panicked"),
            &Error::Panicking(ref err) => {
                let msg = match err.downcast_ref::<&'static str>() {
                    Some(s) => *s,
                    None => match err.downcast_ref::<String>() {
                        Some(s) => &s[..],
                        None => "Box<Any>",
                    }
                };
                write!(f, "Panicking({})", msg)
            }
        }
    }
}
<commit_msg>Implement std::error::Error for coroutine errors<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// #![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico")]

#![allow(unused_features)]
#![feature(std_misc, libc, asm, core, alloc, test, unboxed_closures, page_size, core_simd, rt)]
#![feature(rustc_private)]
#![feature(unique)]

#[macro_use] extern crate log;
extern crate libc;
extern crate test;
extern crate mmap;
#[cfg(feature = "enable-clonable-handle")]
extern crate spin;

use std::any::Any;
use std::error;
use std::fmt::{self, Display};

#[cfg(feature = "enable-clonable-handle")]
pub use coroutine_clonable as coroutine;

#[cfg(not(feature = "enable-clonable-handle"))]
pub use coroutine_unique as coroutine;

pub use builder::Builder;
pub use coroutine::{Coroutine, Handle};
pub use options::Options;

mod context;
#[cfg(feature = "enable-clonable-handle")]
pub mod coroutine_clonable;
#[cfg(not(feature = "enable-clonable-handle"))]
pub mod coroutine_unique;

pub mod builder;
pub mod options;
mod stack;
mod thunk; // use self-maintained thunk, because std::thunk is temporary. May be replaced by FnBox in the future.
mod sys;
mod environment;

#[cfg(test)]
mod tests;
#[cfg(test)]
mod benchmarks;

/// Spawn a new Coroutine
///
/// Equavalent to `Coroutine::spawn`.
pub fn spawn<F>(f: F) -> Handle
    where F: FnOnce() + Send + 'static
{
    Builder::new().spawn(f)
}

/// Get the current Coroutine
///
/// Equavalent to `Coroutine::current`.
pub fn current() -> &'static Handle {
    Coroutine::current()
}

/// Resume a Coroutine
///
/// Equavalent to `Coroutine::resume`.
pub fn resume(coro: &Handle) -> Result {
    coro.resume()
}

/// Yield the current Coroutine with `Suspended` state
///
/// Equavalent to `Coroutine::sched`.
pub fn sched() {
    Coroutine::sched()
}

/// Yield the current Coroutine with `Blocked` state
///
/// Equavalent to `Coroutine::block`.
pub fn block() {
    Coroutine::block()
}

/// State of a Coroutine
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum State {
    /// Waiting its child to return
    Normal,

    /// Suspended. Can be waked up by `resume`
    Suspended,

    /// Blocked. Can be waked up by `resume`
    Blocked,

    /// Running
    Running,

    /// Finished
    Finished,

    /// Panic happened inside, cannot be resumed again
    Panicked,
}

/// Return type of resuming. Ok if resume successfully with the current state,
/// Err if resume failed with `Error`.
pub type Result = ::std::result::Result<State, Error>;

/// Resume Error
#[derive(Debug)]
pub enum Error {
    /// Coroutine is already finished
    Finished,

    /// Coroutine is waiting for its child to yield (state is Normal)
    Waiting,

    /// Coroutine is panicked
    Panicked,

    /// Coroutine is panicking, carry with the parameter of `panic!()`
    Panicking(Box<Any + Send>),
}

impl Error {
    fn description(&self) -> &str {
        match *self {
            Error::Finished => "Finished",
            Error::Waiting => "Waiting",
            Error::Panicked => "Panicked",
            Error::Panicking(ref err) => {
                match err.downcast_ref::<&'static str>() {
                    Some(s) => *s,
                    None => match err.downcast_ref::<String>() {
                        Some(s) => &s[..],
                        None => "Box<Any>",
                    }
                }
            }
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        self.description()
    }

    fn cause(&self) -> Option<&error::Error> {
        Some(self)
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs,
        missing_debug_implementations, missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unstable_features,
        unused_import_braces, unused_qualifications)]
#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]
//! Media Types also known as MIME types describe the nature of data they are
//! used in email to describe the file type of attachments and in HTTP to to
//! give
//! the type of a resource.
//!
//! There are many RFCs describing media types the two most important for this
//! crate is
//! [RFC 2046 - Multipurpose Internet Mail Extensions (MIME) Part Two: Media
//! Types]
//! (https://tools.ietf.org/html/rfc2046).

extern crate charsets;

use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt::{self, Display, Formatter};
use std::str::{FromStr, from_utf8};

pub use charsets::Charset;

pub use self::Type::{Application, Audio, Image, Message, Model, Multipart, Text, Video};
pub use self::Tree::{Personal, Private, Standards, Vendor};
pub use error::{Error, Result};

mod error;
mod utils;

/// A Media Type commonly used to describe the contents of a resource.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct MediaType {
    /// The top-level type or `None` to match all types.
    pub type_: Option<Type>,
    /// A subtype describing the concrete file format. The first element of the tuple is the
    /// registration tree, it describes if they are registered by a standards organization,
    /// a vendor, or if they are only for private use. The second tuple element is the subtype,
    /// it describes the resource. The last part is the suffix it tells how the file was encoded
    /// common values are "xml" and "json".
    pub subtype: Option<(Tree, Cow<'static, str>, Option<Cow<'static, str>>)>,
    /// Media types can contain optional parameters for example for charsets or video codes.
    pub parameters: HashMap<Cow<'static, str>, Cow<'static, str>>,
}

/// Provides the six discrete and the two composite top-level media types.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Type {
    /// The "text" top-level type is intended for sending material that is
    /// principally textual in form.
    Text,
    /// A top-level type of "image" indicates that the content specifies one
    /// or more individual images.
    Image,
    /// A top-level type of "audio" indicates that the content contains audio data.
    Audio,
    /// A top-level type of "video" indicates that the content specifies a
    /// time-varying-picture image, possibly with color and coordinated sound.
    Video,
    /// The "application" top-level type is to be used for discrete data that
    /// do not fit under any of the other type names, and particularly for
    /// data to be processed by some type of application program.
    Application,
    /// The "multipart" top-level type is to be used for data consisting of multiple
    /// entities of independent data types.
    Multipart,
    /// A body of media type "message" is itself all or a portion of some
    /// kind of message object.
    Message,
    /// The "model" media type is used for 3D-models.
    Model,
    /// Less common top-level types.
    Unregistered(Cow<'static, str>),
}

impl Display for Type {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.write_str(match *self {
            Text => "text",
            Image => "image",
            Audio => "audio",
            Video => "video",
            Application => "application",
            Multipart => "multipart",
            Message => "message",
            Model => "model",
            Type::Unregistered(ref string) => &string[..],
        })
    }
}

/// Provides the four registration trees.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Tree {
    /// The standards tree is intended for types of general interest to the Internet community.
    Standards,
    /// The vendor tree is used for media types associated with publicly available products.
    Vendor,
    /// Registrations for media types created experimentally or as part of
    /// products that are not distributed commercially may be registered in
    /// the personal or vanity tree.
    Personal,
    /// Subtype names with "x." as the first facet may be used for types intended exclusively for
    /// use in private, local environments.
    Private,
    /// Other unofficial trees.
    Unregistered(Cow<'static, str>),
}

impl Display for Tree {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            Standards => Ok(()),
            Vendor => f.write_str("vnd."),
            Personal => f.write_str("prs."),
            Private => f.write_str("x."),
            Tree::Unregistered(ref string) => write!(f, "{}.", &string[..]),
        }
    }
}

impl MediaType {
    /// Creates the wildcard media type `*/*`.
    pub fn wildcard() -> MediaType {
        MediaType {
            type_: None,
            subtype: None,
            parameters: HashMap::new(),
        }
    }

    /// Creates a media type with only a concrete type and no subtype like `image/*`.
    pub fn wildcard_subtype(type_: Type) -> MediaType {
        MediaType {
            type_: Some(type_),
            subtype: None,
            parameters: HashMap::new(),
        }
    }

    /// Creates a new media type.
    pub fn new<A>(type_: Type, tree: Tree, subtype: A) -> MediaType
        where A: Into<Cow<'static, str>>
    {
        MediaType {
            type_: Some(type_),
            subtype: Some((tree, subtype.into(), None)),
            parameters: HashMap::new(),
        }
    }

    /// Creates a new media type with suffix.
    pub fn new_with_suffix<A, B>(type_: Type, tree: Tree, subtype: A, suffix: B) -> MediaType
        where A: Into<Cow<'static, str>>,
              B: Into<Cow<'static, str>>
    {
        MediaType {
            type_: Some(type_),
            subtype: Some((tree, subtype.into(), Some(suffix.into()))),
            parameters: HashMap::new(),
        }
    }

    /// Accesses the tree component of the subtype.
    pub fn tree(&self) -> Option<&Tree> {
        if let Some(ref subtype) = self.subtype {
            Some(&subtype.0)
        } else {
            None
        }
    }

    /// Accesses the sub component of the subtype containing the resource type.
    pub fn sub(&self) -> Option<&Cow<'static, str>> {
        if let Some(ref subtype) = self.subtype {
            Some(&subtype.1)
        } else {
            None
        }
    }

    /// Accesses the suffix of the type.
    pub fn suffix(&self) -> Option<&Cow<'static, str>> {
        if let Some(ref subtype) = self.subtype {
            if let Some(ref string) = subtype.2 {
                return Some(&string);
            }
        }
        None
    }

    /// The boundary parameter is used to separate different blocks of multipart resources.
    ///
    /// It is defined in [RFC2046 - Multipurpose Internet Mail Extensions (MIME) Part Two:
    /// Media Types #5.1.  Multipart Media Type](https://tools.ietf.org/html/rfc2046#section-5.1).
    pub fn boundary(&self) -> Result<&str> {
        let boundary = try!(self.parameters.get("boundary").ok_or(Error::NotFound));
        if !utils::boundary(boundary) {
            return Err(Error::Invalid);
        }
        Ok(&boundary[..])
    }

    /// The charset parameter is defined for `text/*` types, it carries information about the
    /// charset.
    ///
    /// The relevant RFCs are [RFC2046 - Multipurpose Internet Mail Extensions (MIME) Part Two:
    /// Media Types #4.1.2. Charset Parameter](https://tools.ietf.org/html/rfc2046#section-4.1.2)
    /// and [RFC6657 - Update to MIME regarding "charset" Parameter Handling in Textual Media Types]
    /// (https://tools.ietf.org/html/rfc6657).
    pub fn charset(&self) -> Result<Charset> {
        let charset = try!(self.parameters.get("charset").ok_or(Error::NotFound));
        Ok(try!(charset.parse()))
    }

    /// Sets the charset parameter to the given charset and returns the old value if present.
    pub fn set_charset(&mut self, charset: Charset) -> Option<Cow<'static, str>> {
        self.parameters.insert("charset".into(), Cow::Owned(charset.to_string()))
    }

    /// Sets the charset to UTF-8.
    pub fn set_charset_utf8(&mut self) -> Option<Cow<'static, str>> {
        self.set_charset(Charset::Utf8)
    }

    /// Compares the mime type portion (the media type without parameters) of two media types.
    pub fn eq_mime_portion(&self, other: &MediaType) -> bool {
        self.type_ == other.type_ && self.subtype == other.subtype
    }

    /// Returns true if the mime type portions differ, strict inverse of `eq_mime_portion()`.
    pub fn ne_mime_portion(&self, other: &MediaType) -> bool {
        !self.eq_mime_portion(other)
    }

    /// Checks if the media type is an image type.
    ///
    /// Implements the [MIME Sniffing standard]
    /// (https://mimesniff.spec.whatwg.org/#mime-type-groups) for MIME type groups.
    pub fn is_image_type(&self) -> bool {
        self.type_ == Some(Image)
    }

    /// Checks if the media type is an audio or video type.
    ///
    /// Implements the [MIME Sniffing standard]
    /// (https://mimesniff.spec.whatwg.org/#mime-type-groups) for MIME type groups.
    pub fn is_audio_or_video_type(&self) -> bool {
        self.type_ == Some(Audio) || self.type_ == Some(Video) ||
        MediaType::new(Application, Standards, "ogg").eq_mime_portion(self)
    }

    /// Checks if the media type is a font type.
    ///
    /// Implements the [MIME Sniffing standard]
    /// (https://mimesniff.spec.whatwg.org/#mime-type-groups) for MIME type groups.
    pub fn is_font_type(&self) -> bool {
        [MediaType::new(Application, Standards, "font-ttf"),
         MediaType::new(Application, Standards, "font-cff"),
         MediaType::new(Application, Standards, "font-off"),
         MediaType::new(Application, Standards, "font-sfnt"),
         MediaType::new(Application, Vendor, "ms-opentype"),
         MediaType::new(Application, Standards, "font-woff"),
         MediaType::new(Application, Vendor, "ms-fontobject")]
            .iter()
            .any(|x| x.eq_mime_portion(self))
    }

    /// Checks if the media type is a zip based type.
    ///
    /// Implements the [MIME Sniffing standard]
    /// (https://mimesniff.spec.whatwg.org/#mime-type-groups) for MIME type groups.
    pub fn is_zip_based_type(&self) -> bool {
        self.suffix() == Some(&"zip".into()) ||
        MediaType::new(Application, Standards, "zip").eq_mime_portion(self)
    }

    /// Checks if the media type is an archive type.
    ///
    /// Implements the [MIME Sniffing standard]
    /// (https://mimesniff.spec.whatwg.org/#mime-type-groups) for MIME type groups.
    pub fn is_archive_type(&self) -> bool {
        [MediaType::new(Application, Standards, "x-rar-compressed"),
         MediaType::new(Application, Standards, "zip"),
         MediaType::new(Application, Standards, "x-gzip")]
            .iter()
            .any(|x| x.eq_mime_portion(self))
    }

    /// Checks if the media type is an XML type.
    ///
    /// Implements the [MIME Sniffing standard]
    /// (https://mimesniff.spec.whatwg.org/#mime-type-groups) for MIME type groups.
    pub fn is_xml_type(&self) -> bool {
        self.suffix() == Some(&"xml".into()) ||
        [MediaType::new(Text, Standards, "xml"), MediaType::new(Application, Standards, "xml")]
            .iter()
            .any(|x| x.eq_mime_portion(self))
    }

    /// Checks if the media type is a scriptable type, HTML or PDF.
    ///
    /// Implements the [MIME Sniffing standard]
    /// (https://mimesniff.spec.whatwg.org/#mime-type-groups) for MIME type groups.
    pub fn is_scriptable_mime_type(&self) -> bool {
        [MediaType::new(Text, Standards, "html"), MediaType::new(Application, Standards, "pdf")]
            .iter()
            .any(|x| x.eq_mime_portion(self))
    }
}

/// top-level type name / [ tree. ] subtype name [ +suffix ] [ ; parameters ]
impl FromStr for MediaType {
    type Err = Error;
    fn from_str(s: &str) -> Result<MediaType> {
        let (raw_type, raw_subtype, raw_parameters) = try!(utils::parse_media_type(s.as_bytes()));
        println!("{:?}, {:?}, {:?}", raw_type, raw_subtype, raw_parameters);
        let type_ = match &raw_type[..] {
            b"*" => None,
            b"text" => Some(Text),
            b"image" => Some(Image),
            b"audio" => Some(Audio),
            b"video" => Some(Video),
            b"application" => Some(Application),
            b"multipart" => Some(Multipart),
            b"message" => Some(Message),
            b"model" => Some(Model),
            _ => Some(Type::Unregistered(Cow::Owned(try!(String::from_utf8(raw_type))))),
        };
        let mut parameters = HashMap::new();
        for (key, value) in raw_parameters {
            parameters.insert(try!(String::from_utf8(key)).into(),
                              try!(String::from_utf8(value)).into());
        }
        if raw_subtype == b"*" {
            Ok(MediaType {
                type_: type_,
                subtype: None,
                parameters: parameters,
            })
        } else {
            let subtype = try!(String::from_utf8(raw_subtype));
            let (prefix, suffix) = if subtype.contains('+') {
                let mut parts = subtype.rsplitn(2, '+');
                let suffix = parts.next().unwrap();
                let prefix = parts.next().unwrap();
                (prefix, Some(suffix))
            } else {
                (&subtype[..], None)
            };
            let (tree, sub) = if prefix.contains('.') {
                let mut parts = prefix.splitn(2, '.');
                let tree = match parts.next().unwrap() {
                    "vnd" => Vendor,
                    "prs" => Personal,
                    "x" => Private,
                    s => Tree::Unregistered(Cow::Owned(s.to_owned())),
                };
                (tree, parts.next().unwrap())
            } else {
                (Standards, prefix)
            };
            Ok(MediaType {
                type_: type_,
                subtype: Some((tree,
                               Cow::Owned(sub.to_owned()),
                               suffix.map(|x| Cow::Owned(x.to_owned())))),
                parameters: parameters,
            })
        }
    }
}

impl Display for MediaType {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        if let Some(ref type_) = self.type_ {
            try!(write!(f, "{}/", type_));
            if let Some((ref tree, ref subtype, ref suffix_opt)) = self.subtype {
                try!(tree.fmt(f));
                try!(subtype.fmt(f));
                if let Some(ref suffix) = *suffix_opt {
                    try!(write!(f, "+{}", suffix));
                }
            } else {
                try!(f.write_str("*"));
            }
        } else {
            try!(f.write_str("*/*"))
        }
        let mut items: Vec<(&Cow<'static, str>, &Cow<'static, str>)> = self.parameters
                                                                           .iter()
                                                                           .collect();
        items.sort_by(|&(ref first, _), &(ref second, _)| first.cmp(second));
        for (ref key, ref value) in items {
            if utils::token(&value) {
                try!(write!(f, "; {}={}", key, value));
            } else {
                try!(write!(f, "; {}=\"{}\"", key, value));
            }
        }
        Ok(())
    }
}
<commit_msg>fix(stable): fix stable builds<commit_after>#![cfg_attr(feature = "dev", deny(missing_docs, missing_debug_implementations,
                                  missing_copy_implementations, trivial_casts,
                                  trivial_numeric_casts, unsafe_code,
                                  unused_import_braces, unused_qualifications,
                                  warnings))]
#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]
//! Media Types also known as MIME types describe the nature of data they are
//! used in email to describe the file type of attachments and in HTTP to to
//! give
//! the type of a resource.
//!
//! There are many RFCs describing media types the two most important for this
//! crate is
//! [RFC 2046 - Multipurpose Internet Mail Extensions (MIME) Part Two: Media
//! Types]
//! (https://tools.ietf.org/html/rfc2046).

extern crate charsets;

use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt::{self, Display, Formatter};
use std::str::{FromStr, from_utf8};

pub use charsets::Charset;

pub use self::Type::{Application, Audio, Image, Message, Model, Multipart, Text, Video};
pub use self::Tree::{Personal, Private, Standards, Vendor};
pub use error::{Error, Result};

mod error;
mod utils;

/// A Media Type commonly used to describe the contents of a resource.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct MediaType {
    /// The top-level type or `None` to match all types.
    pub type_: Option<Type>,
    /// A subtype describing the concrete file format. The first element of the tuple is the
    /// registration tree, it describes if they are registered by a standards organization,
    /// a vendor, or if they are only for private use. The second tuple element is the subtype,
    /// it describes the resource. The last part is the suffix it tells how the file was encoded
    /// common values are "xml" and "json".
    pub subtype: Option<(Tree, Cow<'static, str>, Option<Cow<'static, str>>)>,
    /// Media types can contain optional parameters for example for charsets or video codes.
    pub parameters: HashMap<Cow<'static, str>, Cow<'static, str>>,
}

/// Provides the six discrete and the two composite top-level media types.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Type {
    /// The "text" top-level type is intended for sending material that is
    /// principally textual in form.
    Text,
    /// A top-level type of "image" indicates that the content specifies one
    /// or more individual images.
    Image,
    /// A top-level type of "audio" indicates that the content contains audio data.
    Audio,
    /// A top-level type of "video" indicates that the content specifies a
    /// time-varying-picture image, possibly with color and coordinated sound.
    Video,
    /// The "application" top-level type is to be used for discrete data that
    /// do not fit under any of the other type names, and particularly for
    /// data to be processed by some type of application program.
    Application,
    /// The "multipart" top-level type is to be used for data consisting of multiple
    /// entities of independent data types.
    Multipart,
    /// A body of media type "message" is itself all or a portion of some
    /// kind of message object.
    Message,
    /// The "model" media type is used for 3D-models.
    Model,
    /// Less common top-level types.
    Unregistered(Cow<'static, str>),
}

impl Display for Type {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.write_str(match *self {
            Text => "text",
            Image => "image",
            Audio => "audio",
            Video => "video",
            Application => "application",
            Multipart => "multipart",
            Message => "message",
            Model => "model",
            Type::Unregistered(ref string) => &string[..],
        })
    }
}

/// Provides the four registration trees.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Tree {
    /// The standards tree is intended for types of general interest to the Internet community.
    Standards,
    /// The vendor tree is used for media types associated with publicly available products.
    Vendor,
    /// Registrations for media types created experimentally or as part of
    /// products that are not distributed commercially may be registered in
    /// the personal or vanity tree.
    Personal,
    /// Subtype names with "x." as the first facet may be used for types intended exclusively for
    /// use in private, local environments.
    Private,
    /// Other unofficial trees.
    Unregistered(Cow<'static, str>),
}

impl Display for Tree {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            Standards => Ok(()),
            Vendor => f.write_str("vnd."),
            Personal => f.write_str("prs."),
            Private => f.write_str("x."),
            Tree::Unregistered(ref string) => write!(f, "{}.", &string[..]),
        }
    }
}

impl MediaType {
    /// Creates the wildcard media type `*/*`.
    pub fn wildcard() -> MediaType {
        MediaType {
            type_: None,
            subtype: None,
            parameters: HashMap::new(),
        }
    }

    /// Creates a media type with only a concrete type and no subtype like `image/*`.
    pub fn wildcard_subtype(type_: Type) -> MediaType {
        MediaType {
            type_: Some(type_),
            subtype: None,
            parameters: HashMap::new(),
        }
    }

    /// Creates a new media type.
    pub fn new<A>(type_: Type, tree: Tree, subtype: A) -> MediaType
        where A: Into<Cow<'static, str>>
    {
        MediaType {
            type_: Some(type_),
            subtype: Some((tree, subtype.into(), None)),
            parameters: HashMap::new(),
        }
    }

    /// Creates a new media type with suffix.
    pub fn new_with_suffix<A, B>(type_: Type, tree: Tree, subtype: A, suffix: B) -> MediaType
        where A: Into<Cow<'static, str>>,
              B: Into<Cow<'static, str>>
    {
        MediaType {
            type_: Some(type_),
            subtype: Some((tree, subtype.into(), Some(suffix.into()))),
            parameters: HashMap::new(),
        }
    }

    /// Accesses the tree component of the subtype.
    pub fn tree(&self) -> Option<&Tree> {
        if let Some(ref subtype) = self.subtype {
            Some(&subtype.0)
        } else {
            None
        }
    }

    /// Accesses the sub component of the subtype containing the resource type.
    pub fn sub(&self) -> Option<&Cow<'static, str>> {
        if let Some(ref subtype) = self.subtype {
            Some(&subtype.1)
        } else {
            None
        }
    }

    /// Accesses the suffix of the type.
    pub fn suffix(&self) -> Option<&Cow<'static, str>> {
        if let Some(ref subtype) = self.subtype {
            if let Some(ref string) = subtype.2 {
                return Some(&string);
            }
        }
        None
    }

    /// The boundary parameter is used to separate different blocks of multipart resources.
    ///
    /// It is defined in [RFC2046 - Multipurpose Internet Mail Extensions (MIME) Part Two:
    /// Media Types #5.1.  Multipart Media Type](https://tools.ietf.org/html/rfc2046#section-5.1).
    pub fn boundary(&self) -> Result<&str> {
        let boundary = try!(self.parameters.get("boundary").ok_or(Error::NotFound));
        if !utils::boundary(boundary) {
            return Err(Error::Invalid);
        }
        Ok(&boundary[..])
    }

    /// The charset parameter is defined for `text/*` types, it carries information about the
    /// charset.
    ///
    /// The relevant RFCs are [RFC2046 - Multipurpose Internet Mail Extensions (MIME) Part Two:
    /// Media Types #4.1.2. Charset Parameter](https://tools.ietf.org/html/rfc2046#section-4.1.2)
    /// and [RFC6657 - Update to MIME regarding "charset" Parameter Handling in Textual Media Types]
    /// (https://tools.ietf.org/html/rfc6657).
    pub fn charset(&self) -> Result<Charset> {
        let charset = try!(self.parameters.get("charset").ok_or(Error::NotFound));
        Ok(try!(charset.parse()))
    }

    /// Sets the charset parameter to the given charset and returns the old value if present.
    pub fn set_charset(&mut self, charset: Charset) -> Option<Cow<'static, str>> {
        self.parameters.insert("charset".into(), Cow::Owned(charset.to_string()))
    }

    /// Sets the charset to UTF-8.
    pub fn set_charset_utf8(&mut self) -> Option<Cow<'static, str>> {
        self.set_charset(Charset::Utf8)
    }

    /// Compares the mime type portion (the media type without parameters) of two media types.
    pub fn eq_mime_portion(&self, other: &MediaType) -> bool {
        self.type_ == other.type_ && self.subtype == other.subtype
    }

    /// Returns true if the mime type portions differ, strict inverse of `eq_mime_portion()`.
    pub fn ne_mime_portion(&self, other: &MediaType) -> bool {
        !self.eq_mime_portion(other)
    }

    /// Checks if the media type is an image type.
    ///
    /// Implements the [MIME Sniffing standard]
    /// (https://mimesniff.spec.whatwg.org/#mime-type-groups) for MIME type groups.
    pub fn is_image_type(&self) -> bool {
        self.type_ == Some(Image)
    }

    /// Checks if the media type is an audio or video type.
    ///
    /// Implements the [MIME Sniffing standard]
    /// (https://mimesniff.spec.whatwg.org/#mime-type-groups) for MIME type groups.
    pub fn is_audio_or_video_type(&self) -> bool {
        self.type_ == Some(Audio) || self.type_ == Some(Video) ||
        MediaType::new(Application, Standards, "ogg").eq_mime_portion(self)
    }

    /// Checks if the media type is a font type.
    ///
    /// Implements the [MIME Sniffing standard]
    /// (https://mimesniff.spec.whatwg.org/#mime-type-groups) for MIME type groups.
    pub fn is_font_type(&self) -> bool {
        [MediaType::new(Application, Standards, "font-ttf"),
         MediaType::new(Application, Standards, "font-cff"),
         MediaType::new(Application, Standards, "font-off"),
         MediaType::new(Application, Standards, "font-sfnt"),
         MediaType::new(Application, Vendor, "ms-opentype"),
         MediaType::new(Application, Standards, "font-woff"),
         MediaType::new(Application, Vendor, "ms-fontobject")]
            .iter()
            .any(|x| x.eq_mime_portion(self))
    }

    /// Checks if the media type is a zip based type.
    ///
    /// Implements the [MIME Sniffing standard]
    /// (https://mimesniff.spec.whatwg.org/#mime-type-groups) for MIME type groups.
    pub fn is_zip_based_type(&self) -> bool {
        self.suffix() == Some(&"zip".into()) ||
        MediaType::new(Application, Standards, "zip").eq_mime_portion(self)
    }

    /// Checks if the media type is an archive type.
    ///
    /// Implements the [MIME Sniffing standard]
    /// (https://mimesniff.spec.whatwg.org/#mime-type-groups) for MIME type groups.
    pub fn is_archive_type(&self) -> bool {
        [MediaType::new(Application, Standards, "x-rar-compressed"),
         MediaType::new(Application, Standards, "zip"),
         MediaType::new(Application, Standards, "x-gzip")]
            .iter()
            .any(|x| x.eq_mime_portion(self))
    }

    /// Checks if the media type is an XML type.
    ///
    /// Implements the [MIME Sniffing standard]
    /// (https://mimesniff.spec.whatwg.org/#mime-type-groups) for MIME type groups.
    pub fn is_xml_type(&self) -> bool {
        self.suffix() == Some(&"xml".into()) ||
        [MediaType::new(Text, Standards, "xml"), MediaType::new(Application, Standards, "xml")]
            .iter()
            .any(|x| x.eq_mime_portion(self))
    }

    /// Checks if the media type is a scriptable type, HTML or PDF.
    ///
    /// Implements the [MIME Sniffing standard]
    /// (https://mimesniff.spec.whatwg.org/#mime-type-groups) for MIME type groups.
    pub fn is_scriptable_mime_type(&self) -> bool {
        [MediaType::new(Text, Standards, "html"), MediaType::new(Application, Standards, "pdf")]
            .iter()
            .any(|x| x.eq_mime_portion(self))
    }
}

/// top-level type name / [ tree. ] subtype name [ +suffix ] [ ; parameters ]
impl FromStr for MediaType {
    type Err = Error;
    fn from_str(s: &str) -> Result<MediaType> {
        let (raw_type, raw_subtype, raw_parameters) = try!(utils::parse_media_type(s.as_bytes()));
        println!("{:?}, {:?}, {:?}", raw_type, raw_subtype, raw_parameters);
        let type_ = match &raw_type[..] {
            b"*" => None,
            b"text" => Some(Text),
            b"image" => Some(Image),
            b"audio" => Some(Audio),
            b"video" => Some(Video),
            b"application" => Some(Application),
            b"multipart" => Some(Multipart),
            b"message" => Some(Message),
            b"model" => Some(Model),
            _ => Some(Type::Unregistered(Cow::Owned(try!(String::from_utf8(raw_type))))),
        };
        let mut parameters = HashMap::new();
        for (key, value) in raw_parameters {
            parameters.insert(try!(String::from_utf8(key)).into(),
                              try!(String::from_utf8(value)).into());
        }
        if raw_subtype == b"*" {
            Ok(MediaType {
                type_: type_,
                subtype: None,
                parameters: parameters,
            })
        } else {
            let subtype = try!(String::from_utf8(raw_subtype));
            let (prefix, suffix) = if subtype.contains('+') {
                let mut parts = subtype.rsplitn(2, '+');
                let suffix = parts.next().unwrap();
                let prefix = parts.next().unwrap();
                (prefix, Some(suffix))
            } else {
                (&subtype[..], None)
            };
            let (tree, sub) = if prefix.contains('.') {
                let mut parts = prefix.splitn(2, '.');
                let tree = match parts.next().unwrap() {
                    "vnd" => Vendor,
                    "prs" => Personal,
                    "x" => Private,
                    s => Tree::Unregistered(Cow::Owned(s.to_owned())),
                };
                (tree, parts.next().unwrap())
            } else {
                (Standards, prefix)
            };
            Ok(MediaType {
                type_: type_,
                subtype: Some((tree,
                               Cow::Owned(sub.to_owned()),
                               suffix.map(|x| Cow::Owned(x.to_owned())))),
                parameters: parameters,
            })
        }
    }
}

impl Display for MediaType {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        if let Some(ref type_) = self.type_ {
            try!(write!(f, "{}/", type_));
            if let Some((ref tree, ref subtype, ref suffix_opt)) = self.subtype {
                try!(tree.fmt(f));
                try!(subtype.fmt(f));
                if let Some(ref suffix) = *suffix_opt {
                    try!(write!(f, "+{}", suffix));
                }
            } else {
                try!(f.write_str("*"));
            }
        } else {
            try!(f.write_str("*/*"))
        }
        let mut items: Vec<(&Cow<'static, str>, &Cow<'static, str>)> = self.parameters
                                                                           .iter()
                                                                           .collect();
        items.sort_by(|&(ref first, _), &(ref second, _)| first.cmp(second));
        for (ref key, ref value) in items {
            if utils::token(&value) {
                try!(write!(f, "; {}={}", key, value));
            } else {
                try!(write!(f, "; {}=\"{}\"", key, value));
            }
        }
        Ok(())
    }
}
<|endoftext|>