<commit_before>/*
 * Copyright 2015-2019 Ben Ashford
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! A client for ElasticSearch's REST API
//!
//! The `Client` itself is used as the central access point, from which numerous
//! operations are defined implementing each of the specific ElasticSearch APIs.
//!
//! Warning: at the time of writing the majority of such APIs are currently
//! unimplemented.

#[cfg(test)]
#[macro_use]
extern crate doc_comment;

#[cfg(test)]
doctest!("../README.md");

#[macro_use]
pub mod util;

#[macro_use]
pub mod json;

pub mod error;
pub mod operations;
pub mod query;
pub mod units;

use std::time;

use reqwest::{header::CONTENT_TYPE, RequestBuilder, StatusCode, Url};

use serde::{de::DeserializeOwned, ser::Serialize};

use crate::error::EsError;

pub trait EsResponse {
    fn status_code(&self) -> StatusCode;
    fn read_response<R>(self) -> Result<R, EsError>
    where
        R: DeserializeOwned;
}

impl EsResponse for reqwest::Response {
    fn status_code(&self) -> StatusCode {
        self.status()
    }

    fn read_response<R>(self) -> Result<R, EsError>
    where
        R: DeserializeOwned,
    {
        Ok(serde_json::from_reader(self)?)
    }
}

// The client

/// Process the result of an HTTP request, returning the status code and the
/// `Json` result (if the result had a body) or an `EsError` if there were any
/// errors
///
/// This function is exposed to allow extensions to certain operations, it is
/// not expected to be used by consumers of the library
fn do_req(resp: reqwest::Response) -> Result<reqwest::Response, EsError> {
    let mut resp = resp;
    let status = resp.status();
    match status {
        StatusCode::OK | StatusCode::CREATED | StatusCode::NOT_FOUND => Ok(resp),
        _ => Err(EsError::from(&mut resp)),
    }
}

/// The core of the ElasticSearch client, owns a HTTP connection.
///
/// Each instance of `Client` is reusable, but only one thread can use each one
/// at once.  This will be enforced by the borrow-checker as most methods are
/// defined on `&mut self`.
///
/// To create a `Client`, the URL needs to be specified.
///
/// Each ElasticSearch API operation is defined as a method on `Client`.  Any
/// compulsory parameters must be given as arguments to this method.  It returns
/// an operation builder that can be used to add any optional parameters.
///
/// Finally `send` is called to submit the operation:
///
/// # Examples
///
/// ```
/// use rs_es::Client;
///
/// let mut client = Client::init("http://localhost:9200");
/// ```
///
/// See the specific operations and their builder objects for details.
#[derive(Debug)]
pub struct Client {
    base_url: Url,
    http_client: reqwest::Client,
}

impl Client {
    fn do_es_op(
        &self,
        url: &str,
        action: impl FnOnce(Url) -> RequestBuilder,
    ) -> Result<reqwest::Response, EsError> {
        let url = self.full_url(url);
        let username = self.base_url.username();
        let mut method = action(url);
        if !username.is_empty() {
            method = method.basic_auth(username, self.base_url.password());
        }
        let result = method.header(CONTENT_TYPE, "application/json").send()?;
        do_req(result)
    }
}

/// Create a HTTP function for the given method (GET/PUT/POST/DELETE)
macro_rules! es_op {
    ($n:ident,$cn:ident) => {
        fn $n(&self, url: &str) -> Result<reqwest::Response, EsError> {
            log::info!("Doing {} on {}", stringify!($n), url);
            self.do_es_op(url, |url| self.http_client.$cn(url.clone()))
        }
    }
}

/// Create a HTTP function with a request body for the given method
/// (GET/PUT/POST/DELETE)
///
macro_rules! es_body_op {
    ($n:ident,$cn:ident) => {
        fn $n<E>(&mut self, url: &str, body: &E) -> Result<reqwest::Response, EsError>
            where E: Serialize {

            log::info!("Doing {} on {}", stringify!($n), url);
            let json_string = serde_json::to_string(body)?;
            log::debug!("With body: {}", &json_string);

            self.do_es_op(url, |url| {
                self.http_client.$cn(url.clone()).body(json_string)
            })
        }
    }
}

impl Client {
    /// Create a new client
    pub fn init(url_s: &str) -> Result<Client, reqwest::UrlError> {
        let url = Url::parse(url_s)?;

        Ok(Client {
            http_client: reqwest::Client::new(),
            base_url: url,
        })
    }

    // TODO - this should be replaced with a builder object, especially if more options are going
    // to be allowed
    pub fn init_with_timeout(
        url_s: &str,
        timeout: Option<time::Duration>,
    ) -> Result<Client, reqwest::UrlError> {
        let url = Url::parse(url_s)?;

        Ok(Client {
            http_client: reqwest::Client::builder()
                .timeout(timeout)
                .build()
                .expect("Failed to build client"),
            base_url: url,
        })
    }

    /// Take a nearly complete ElasticSearch URL, and stick
    /// the URL on the front.
    pub fn full_url(&self, suffix: &str) -> Url {
        self.base_url.join(suffix).expect("Invalid URL created")
    }

    es_op!(get_op, get);

    es_op!(post_op, post);
    es_body_op!(post_body_op, post);
    es_op!(put_op, put);
    es_body_op!(put_body_op, put);
    es_op!(delete_op, delete);
}

#[cfg(test)]
pub mod tests {
    use std::env;

    use serde::{Deserialize, Serialize};
    use serde_json::Value;

    use super::{
        operations::{bulk::Action, search::ScanResult},
        query::Query,
        units::Duration,
        Client,
    };

    // test setup

    pub fn make_client() -> Client {
        let hostname = match env::var("ES_HOST") {
            Ok(val) => val,
            Err(_) => "http://localhost:9200".to_owned(),
        };
        Client::init(&hostname).unwrap()
    }

    #[derive(Debug, Serialize, Deserialize)]
    pub struct TestDocument {
        pub str_field: String,
        pub int_field: i64,
        pub bool_field: bool,
    }

    #[allow(clippy::new_without_default)]
    impl TestDocument {
        pub fn new() -> TestDocument {
            TestDocument {
                str_field: "I am a test".to_owned(),
                int_field: 1,
                bool_field: true,
            }
        }

        pub fn with_str_field(mut self, s: &str) -> TestDocument {
            self.str_field = s.to_owned();
            self
        }

        pub fn with_int_field(mut self, i: i64) -> TestDocument {
            self.int_field = i;
            self
        }

        pub fn with_bool_field(mut self, b: bool) -> TestDocument {
            self.bool_field = b;
            self
        }
    }

    pub fn setup_test_data(client: &mut Client, index_name: &str) {
        // TODO - this should use the Bulk API
        let documents = vec![
            TestDocument::new()
                .with_str_field("Document A123")
                .with_int_field(1),
            TestDocument::new()
                .with_str_field("Document B456")
                .with_int_field(2),
            TestDocument::new()
                .with_str_field("Document 1ABC")
                .with_int_field(3),
        ];
        for doc in documents.iter() {
            client
                .index(index_name, "test_type")
                .with_doc(doc)
                .send()
                .unwrap();
        }
        client.refresh().with_indexes(&[index_name]).send().unwrap();
    }

    pub fn clean_db(mut client: &mut Client, test_idx: &str) {
        let scroll = Duration::minutes(1);
        let mut scan: ScanResult<Value> = match client
            .search_query()
            .with_indexes(&[test_idx])
            .with_query(&Query::build_match_all().build())
            .scan(&scroll)
        {
            Ok(scan) => scan,
            Err(e) => {
                log::warn!("Scan error: {:?}", e);
                return; // Ignore not-found errors
            }
        };

        loop {
            let page = scan.scroll(&mut client, &scroll).unwrap();
            let hits = page.hits.hits;
            if hits.is_empty() {
                break;
            }
            let actions: Vec<Action<()>> = hits
                .into_iter()
                .map(|hit| {
                    Action::delete(hit.id)
                        .with_index(test_idx)
                        .with_doc_type(hit.doc_type)
                })
                .collect();
            client.bulk(&actions).send().unwrap();
        }

        scan.close(&mut client).unwrap();
    }
}
<commit_msg>add a way to clone the client<commit_after>/*
 * Copyright 2015-2019 Ben Ashford
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! A client for ElasticSearch's REST API
//!
//! The `Client` itself is used as the central access point, from which numerous
//! operations are defined implementing each of the specific ElasticSearch APIs.
//!
//! Warning: at the time of writing the majority of such APIs are currently
//! unimplemented.

#[cfg(test)]
#[macro_use]
extern crate doc_comment;

#[cfg(test)]
doctest!("../README.md");

#[macro_use]
pub mod util;

#[macro_use]
pub mod json;

pub mod error;
pub mod operations;
pub mod query;
pub mod units;

use std::time;

use reqwest::{header::CONTENT_TYPE, RequestBuilder, StatusCode, Url};

use serde::{de::DeserializeOwned, ser::Serialize};

use crate::error::EsError;

pub trait EsResponse {
    fn status_code(&self) -> StatusCode;
    fn read_response<R>(self) -> Result<R, EsError>
    where
        R: DeserializeOwned;
}

impl EsResponse for reqwest::Response {
    fn status_code(&self) -> StatusCode {
        self.status()
    }

    fn read_response<R>(self) -> Result<R, EsError>
    where
        R: DeserializeOwned,
    {
        Ok(serde_json::from_reader(self)?)
    }
}

// The client

/// Process the result of an HTTP request, returning the status code and the
/// `Json` result (if the result had a body) or an `EsError` if there were any
/// errors
///
/// This function is exposed to allow extensions to certain operations, it is
/// not expected to be used by consumers of the library
fn do_req(resp: reqwest::Response) -> Result<reqwest::Response, EsError> {
    let mut resp = resp;
    let status = resp.status();
    match status {
        StatusCode::OK | StatusCode::CREATED | StatusCode::NOT_FOUND => Ok(resp),
        _ => Err(EsError::from(&mut resp)),
    }
}

/// The core of the ElasticSearch client, owns a HTTP connection.
///
/// Each instance of `Client` is reusable, but only one thread can use each one
/// at once.  This will be enforced by the borrow-checker as most methods are
/// defined on `&mut self`.
///
/// To create a `Client`, the URL needs to be specified.
///
/// Each ElasticSearch API operation is defined as a method on `Client`.  Any
/// compulsory parameters must be given as arguments to this method.  It returns
/// an operation builder that can be used to add any optional parameters.
///
/// Finally `send` is called to submit the operation:
///
/// # Examples
///
/// ```
/// use rs_es::Client;
///
/// let mut client = Client::init("http://localhost:9200");
/// ```
///
/// See the specific operations and their builder objects for details.
#[derive(Debug, Clone)]
pub struct Client {
    base_url: Url,
    http_client: reqwest::Client,
}

impl Client {
    fn do_es_op(
        &self,
        url: &str,
        action: impl FnOnce(Url) -> RequestBuilder,
    ) -> Result<reqwest::Response, EsError> {
        let url = self.full_url(url);
        let username = self.base_url.username();
        let mut method = action(url);
        if !username.is_empty() {
            method = method.basic_auth(username, self.base_url.password());
        }
        let result = method.header(CONTENT_TYPE, "application/json").send()?;
        do_req(result)
    }
}

/// Create a HTTP function for the given method (GET/PUT/POST/DELETE)
macro_rules! es_op {
    ($n:ident,$cn:ident) => {
        fn $n(&self, url: &str) -> Result<reqwest::Response, EsError> {
            log::info!("Doing {} on {}", stringify!($n), url);
            self.do_es_op(url, |url| self.http_client.$cn(url.clone()))
        }
    }
}

/// Create a HTTP function with a request body for the given method
/// (GET/PUT/POST/DELETE)
///
macro_rules! es_body_op {
    ($n:ident,$cn:ident) => {
        fn $n<E>(&mut self, url: &str, body: &E) -> Result<reqwest::Response, EsError>
            where E: Serialize {

            log::info!("Doing {} on {}", stringify!($n), url);
            let json_string = serde_json::to_string(body)?;
            log::debug!("With body: {}", &json_string);

            self.do_es_op(url, |url| {
                self.http_client.$cn(url.clone()).body(json_string)
            })
        }
    }
}

impl Client {
    /// Create a new client
    pub fn init(url_s: &str) -> Result<Client, reqwest::UrlError> {
        let url = Url::parse(url_s)?;

        Ok(Client {
            http_client: reqwest::Client::new(),
            base_url: url,
        })
    }

    // TODO - this should be replaced with a builder object, especially if more options are going
    // to be allowed
    pub fn init_with_timeout(
        url_s: &str,
        timeout: Option<time::Duration>,
    ) -> Result<Client, reqwest::UrlError> {
        let url = Url::parse(url_s)?;

        Ok(Client {
            http_client: reqwest::Client::builder()
                .timeout(timeout)
                .build()
                .expect("Failed to build client"),
            base_url: url,
        })
    }

    /// Take a nearly complete ElasticSearch URL, and stick
    /// the URL on the front.
    pub fn full_url(&self, suffix: &str) -> Url {
        self.base_url.join(suffix).expect("Invalid URL created")
    }

    es_op!(get_op, get);

    es_op!(post_op, post);
    es_body_op!(post_body_op, post);
    es_op!(put_op, put);
    es_body_op!(put_body_op, put);
    es_op!(delete_op, delete);
}

#[cfg(test)]
pub mod tests {
    use std::env;

    use serde::{Deserialize, Serialize};
    use serde_json::Value;

    use super::{
        operations::{bulk::Action, search::ScanResult},
        query::Query,
        units::Duration,
        Client,
    };

    // test setup

    pub fn make_client() -> Client {
        let hostname = match env::var("ES_HOST") {
            Ok(val) => val,
            Err(_) => "http://localhost:9200".to_owned(),
        };
        Client::init(&hostname).unwrap()
    }

    #[derive(Debug, Serialize, Deserialize)]
    pub struct TestDocument {
        pub str_field: String,
        pub int_field: i64,
        pub bool_field: bool,
    }

    #[allow(clippy::new_without_default)]
    impl TestDocument {
        pub fn new() -> TestDocument {
            TestDocument {
                str_field: "I am a test".to_owned(),
                int_field: 1,
                bool_field: true,
            }
        }

        pub fn with_str_field(mut self, s: &str) -> TestDocument {
            self.str_field = s.to_owned();
            self
        }

        pub fn with_int_field(mut self, i: i64) -> TestDocument {
            self.int_field = i;
            self
        }

        pub fn with_bool_field(mut self, b: bool) -> TestDocument {
            self.bool_field = b;
            self
        }
    }

    pub fn setup_test_data(client: &mut Client, index_name: &str) {
        // TODO - this should use the Bulk API
        let documents = vec![
            TestDocument::new()
                .with_str_field("Document A123")
                .with_int_field(1),
            TestDocument::new()
                .with_str_field("Document B456")
                .with_int_field(2),
            TestDocument::new()
                .with_str_field("Document 1ABC")
                .with_int_field(3),
        ];
        for doc in documents.iter() {
            client
                .index(index_name, "test_type")
                .with_doc(doc)
                .send()
                .unwrap();
        }
        client.refresh().with_indexes(&[index_name]).send().unwrap();
    }

    pub fn clean_db(mut client: &mut Client, test_idx: &str) {
        let scroll = Duration::minutes(1);
        let mut scan: ScanResult<Value> = match client
            .search_query()
            .with_indexes(&[test_idx])
            .with_query(&Query::build_match_all().build())
            .scan(&scroll)
        {
            Ok(scan) => scan,
            Err(e) => {
                log::warn!("Scan error: {:?}", e);
                return; // Ignore not-found errors
            }
        };

        loop {
            let page = scan.scroll(&mut client, &scroll).unwrap();
            let hits = page.hits.hits;
            if hits.is_empty() {
                break;
            }
            let actions: Vec<Action<()>> = hits
                .into_iter()
                .map(|hit| {
                    Action::delete(hit.id)
                        .with_index(test_idx)
                        .with_doc_type(hit.doc_type)
                })
                .collect();
            client.bulk(&actions).send().unwrap();
        }

        scan.close(&mut client).unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;

mod client;
mod channel;
mod connection;
mod command;
mod error;
pub mod map;

use std::result;

pub use client::{Client, ClientList};
pub use channel::{Channel, ChannelList};
pub use connection::Connection;
pub use command::Command;
pub use error::{Error, SQError};

pub type Result<T> = result::Result<T, Error>;
<commit_msg>adding mod escaping to lib.rs<commit_after>extern crate rustc_serialize;

mod client;
mod channel;
mod connection;
mod command;
mod error;
pub mod map;
pub mod escaping;

use std::result;

pub use client::{Client, ClientList};
pub use channel::{Channel, ChannelList};
pub use connection::Connection;
pub use command::Command;
pub use error::{Error, SQError};

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


<commit_before>use std::collections::HashMap;

extern crate regex;

use regex::Regex;

pub fn puzzle(input: &str) -> u32 {
    0
}

pub struct Room {
    name: String,
    sector_id: u32,
    checksum: String,
}

impl Room {
    fn new(description: &str) -> Room {
        let regex = Regex::new(r"(?x)
            (?P<name>[a-z-]+)
            -
            (?P<sector_id>[0-9]+)
            \[(?P<checksum>[a-z]{5})\]").expect("Regex is invalid");

        let caps = regex.captures(description).expect("Can't capture");

        Room {
            name: caps.name("name").expect("No name").to_string(),
            sector_id: caps.name("sector_id").expect("No sector id").parse().expect("Can't parse"),
            checksum: caps.name("checksum").expect("No checksum").to_string(),
        }
    }

    fn is_real(&self) -> bool {
        self.checksum == self.computed_checksum()
    }

    fn computed_checksum(&self) -> String {
        self.five_most_common_chars().sort().join("")
    }

    fn five_most_common_chars(&self) -> Vec<char> {
        self.chars_by_frequency_desc().take(5)
    }

    fn chars_by_frequency_desc(&self) -> Vec<char> {
        self.chars_by_frequency()
            .sort_by(|(_, v)| v)
            .rev()
            .map( |(k, _)| k )
            .collect()
    }

    fn chars_by_frequency(&self) -> HashMap<char, u32> {
        let mut freqs = HashMap::new();
        for c in self.name.chars() {
            let count = freqs.entry(c).or_insert(0);
            *count += 1;
        }
        freqs
    }
}

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

    #[test]
    fn test_extraction() {
        let description = "aaaaa-bbb-z-y-x-123[abxyz]";
        let room = Room::new(description);

        assert_eq!(room.name, "aaaaa-bbb-z-y-x");
        assert_eq!(room.sector_id, 123);
        assert_eq!(room.checksum, "abxyz");
    }

    #[test]
    fn real_rooms() {
        assert!(Room::new("aaaaa-bbb-z-y-x-123[abxyz]").is_real());
        assert!(Room::new("a-b-c-d-e-f-g-h-987[abcde]").is_real());
        assert!(Room::new("not-a-real-room-404[oarel]").is_real());
    }

    #[test]
    fn decoy_rooms() {
        assert!( ! Room::new("totally-real-room-200[decoy]").is_real() );
    }
}
<commit_msg>Get the code i wanted to actually compile<commit_after>use std::collections::HashMap;

extern crate regex;

use regex::Regex;

pub fn puzzle(input: &str) -> u32 {
    0
}

pub struct Room {
    name: String,
    sector_id: u32,
    checksum: String,
}

impl Room {
    fn new(description: &str) -> Room {
        let regex = Regex::new(r"(?x)
            (?P<name>[a-z-]+)
            -
            (?P<sector_id>[0-9]+)
            \[(?P<checksum>[a-z]{5})\]").expect("Regex is invalid");

        let caps = regex.captures(description).expect("Can't capture");

        Room {
            name: caps.name("name").expect("No name").to_string(),
            sector_id: caps.name("sector_id").expect("No sector id").parse().expect("Can't parse"),
            checksum: caps.name("checksum").expect("No checksum").to_string(),
        }
    }

    fn is_real(&self) -> bool {
        self.checksum == self.computed_checksum()
    }

    fn computed_checksum(&self) -> String {
        let mut most_common = self.five_most_common_chars();
        most_common.sort();
        let mut s = String::new();
        for &c in most_common.iter() {
            s.push(c);
        }
        s
    }

    fn five_most_common_chars(&self) -> Vec<char> {
        self.chars_by_frequency_desc().into_iter().take(5).collect()
    }

    fn chars_by_frequency_desc(&self) -> Vec<char> {
        let mut tuples: Vec<(char, u32)> = self.chars_by_frequency()
                                               .into_iter()
                                               .collect();
        tuples.sort_by(|a, b| b.1.cmp(&a.1) );
        tuples.iter().map( |&(k, _)| k ).collect()
    }

    fn chars_by_frequency(&self) -> HashMap<char, u32> {
        let mut freqs = HashMap::new();
        for c in self.name.chars() {
            let count = freqs.entry(c).or_insert(0);
            *count += 1;
        }
        freqs
    }
}

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

    #[test]
    fn test_extraction() {
        let description = "aaaaa-bbb-z-y-x-123[abxyz]";
        let room = Room::new(description);

        assert_eq!(room.name, "aaaaa-bbb-z-y-x");
        assert_eq!(room.sector_id, 123);
        assert_eq!(room.checksum, "abxyz");
    }

    #[test]
    fn real_rooms() {
        assert!(Room::new("aaaaa-bbb-z-y-x-123[abxyz]").is_real());
        assert!(Room::new("a-b-c-d-e-f-g-h-987[abcde]").is_real());
        assert!(Room::new("not-a-real-room-404[oarel]").is_real());
    }

    #[test]
    fn decoy_rooms() {
        assert!( ! Room::new("totally-real-room-200[decoy]").is_real() );
    }
}
<|endoftext|>


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

mod morphism;

use morphism::Morphism;

pub trait Param { type Param; }

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

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

pub trait NaturalTransform<T: Param<Param=Self::Param>>: Param {
    fn transform(self) -> T;
}

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

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

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

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

}

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

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

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

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

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

impl<A> NaturalTransform<Option<A>> for Box<A> {
    fn transform(self) -> Option<A> {
        Option::Some(*self)
    }
}

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

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

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

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

impl<A, E> NaturalTransform<Option<A>> for Result<A, E> {
    fn transform(self) -> Option<A> {
        match self {
            Ok(a) => Some(a),
            Err(_) => None
        }
    }
}

mod test {
#![cfg(test)]

    use super::*;

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

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

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

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

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

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

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

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

mod morphism;

use morphism::Morphism;

pub trait Param { type Param; }

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

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

pub trait NaturalTransform<T: Param<Param=Self::Param>>: Param {
    fn transform(self) -> T;
}

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

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

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

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

}

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

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

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

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

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

impl<A> NaturalTransform<Option<A>> for Box<A> {
    fn transform(self) -> Option<A> {
        Option::Some(*self)
    }
}

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

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

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

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

impl<A, E> NaturalTransform<Option<A>> for Result<A, E> {
    fn transform(self) -> Option<A> {
        match self {
            Ok(a) => Some(a),
            Err(_) => None
        }
    }
}

mod test {
#![cfg(test)]

    use super::*;

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

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

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

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

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

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

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

}
<|endoftext|>


<commit_before>use std::io::Write;

pub struct Progress {
    current: usize,
    total: usize,

    started: bool
}

impl Progress {
    pub fn new(current: usize, total: usize) -> Self {
        Progress { current: current, total: total, started: false }
    }

    pub fn default() -> Self {
        Progress::new(0, 100)
    }

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

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

    pub fn increment(&mut self) -> &Self {
        if self.current < self.total {
            self.current += 1;
        }
        print_bar(self);
        self
    }

    pub fn decrement(&mut self) -> &Self {
        if self.current > 0 {
            self.current -= 1;
        }
        self
    }

    pub fn finished(&self) -> bool {
        self.current >= self.total
    }

    pub fn process(&self) -> u8 {
        (self.current * 100 / self.total) as u8
    }

    pub fn start(&mut self) -> &Self {
        self.started = true;
        self
    }
}

fn print_bar(p: &Progress) {
    let p_info = format!("{current} / {total} ({process})",
                         current = p.current(),
                         total   = p.total(),
                         process = p.process());
    let caption = "Progress";

    let bar_width  = 79 - p_info.len() - caption.len() - 3 - 2;
    let done_width = (bar_width * p.process() as usize) / 100;
    let todo_width = bar_width - done_width;
    let done_bar   = std::iter::repeat("#").take(done_width).collect::<String>();
    let todo_bar   = std::iter::repeat("-").take(todo_width).collect::<String>();
    let bar = format!("|{}{}|", done_bar, todo_bar);

    print!("{caption}: {bar} {info}\r",
           caption = caption, bar = bar, info = p_info);
    std::io::stdout().flush().unwrap();
}
<commit_msg>A little bit of documentation.<commit_after>use std::io::Write;

/// Tracks progress of a task
pub struct Progress {
    current: usize,
    total: usize,

    started: bool
}

impl Progress {
    /// Creates a new one
    pub fn new(current: usize, total: usize) -> Self {
        Progress { current: current, total: total, started: false }
    }

    /// Creates a new progress with default values.
    pub fn default() -> Self {
        Progress::new(0, 100)
    }

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

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

    pub fn increment(&mut self) -> &Self {
        if self.current < self.total {
            self.current += 1;
        }
        print_bar(self);
        self
    }

    pub fn decrement(&mut self) -> &Self {
        if self.current > 0 {
            self.current -= 1;
        }
        self
    }

    pub fn finished(&self) -> bool {
        self.current >= self.total
    }

    pub fn process(&self) -> u8 {
        (self.current * 100 / self.total) as u8
    }

    pub fn start(&mut self) -> &Self {
        self.started = true;
        self
    }
}

fn print_bar(p: &Progress) {
    let p_info = format!("{current} / {total} ({process})",
                         current = p.current(),
                         total   = p.total(),
                         process = p.process());
    let caption = "Progress";

    let bar_width  = 79 - p_info.len() - caption.len() - 3 - 2;
    let done_width = (bar_width * p.process() as usize) / 100;
    let todo_width = bar_width - done_width;
    let done_bar   = std::iter::repeat("#").take(done_width).collect::<String>();
    let todo_bar   = std::iter::repeat("-").take(todo_width).collect::<String>();
    let bar = format!("|{}{}|", done_bar, todo_bar);

    print!("{caption}: {bar} {info}\r",
           caption = caption, bar = bar, info = p_info);
    std::io::stdout().flush().unwrap();
}
<|endoftext|>


<commit_before>/// Data-structure for storing a sequence of 4-bit values.
pub struct NibbleVec {
    offset: bool,
    length: uint,
    data: Vec<u8>
}

impl NibbleVec {
    pub fn new() -> NibbleVec {
        NibbleVec {
            offset: false,
            length: 0,
            data: Vec::new()
        }
    }

    pub fn from_byte_vec(vec: Vec<u8>) -> NibbleVec {
        let length = 2 * vec.len();
        NibbleVec {
            offset: false,
            length: length,
            data: vec
        }
    }

    pub fn get(&self, idx: uint) -> Option<u8> {
        if idx >= self.length {
            return None;
        }
        let vec_idx = idx / 2;
        match (self.offset, idx % 2) {
            // Take the most significant bits.
            (false, 0) | (true, 1) => Some(self.data[vec_idx] >> 4),
            // Take the least significant bits.
            _ => Some(self.data[vec_idx] & 0x0f)
        }
    }
}

#[cfg(test)]
mod test {
    use NibbleVec;

    #[test]
    fn get() {
        let nv = NibbleVec::from_byte_vec(vec![(1 << 6) + (1 << 3)]);
        assert_eq!(nv.get(0).unwrap(), 4u8);
        assert_eq!(nv.get(1).unwrap(), 8u8);
    }
}
<commit_msg>Push and split methods.<commit_after>/// A data-structure for storing a sequence of 4-bit values.
///
/// Values are stored in a Vec<u8>, with two values per byte.
///
/// Values at *even* indices are stored in the most-significant half of their byte,
/// while values at odd indices are stored in the least-significant half.
///
/// Imagine a vector of MSB bytes, and you'll be right.
///
/// n = [_ _ | _ _ | _ _]
pub struct NibbleVec {
    length: uint,
    data: Vec<u8>
}

impl NibbleVec {
    pub fn new() -> NibbleVec {
        NibbleVec {
            length: 0,
            data: Vec::new()
        }
    }

    pub fn from_byte_vec(vec: Vec<u8>) -> NibbleVec {
        let length = 2 * vec.len();
        NibbleVec {
            length: length,
            data: vec
        }
    }

    pub fn len(&self) -> uint {
        self.length
    }

    pub fn get(&self, idx: uint) -> Option<u8> {
        if idx >= self.length {
            return None;
        }
        let vec_idx = idx / 2;
        // If the index is even, take the first (most significant) half of the stored byte.
        // Otherwise, take the second (least significant) half.
        match idx % 2 {
            0 => Some(self.data[vec_idx] >> 4),
            _ => Some(self.data[vec_idx] & 0x0f)
        }
    }

    pub fn push(&mut self, val: u8) {
        if self.length % 2 == 0 {
            self.data.push(val << 4);
        } else {
            let vec_len = self.data.len();
            self.data[vec_len - 1] |= val & 0x0F;
        }
        self.length += 1;
    }

    /// Cut the vector into two parts.
    ///
    /// All elements at or following the given index are returned in a new `NibbleVec`.
    ///
    /// *Panics* if `idx > self.len()`.
    pub fn split(&mut self, idx: uint) -> NibbleVec {
        if idx > self.length {
            panic!("attempted to split past vector end. len is {}, index is {}", self.length, idx);
        } else if idx == self.length {
            NibbleVec::new()
        } else if idx % 2 == 0 {
            self.split_even(idx)
        } else {
            self.split_odd(idx)
        }
    }

    #[inline(always)]
    fn split_odd(&mut self, idx: uint) -> NibbleVec {
        let tail_vec_size = (self.length - idx) / 2;
        let mut tail_vec = Vec::with_capacity(tail_vec_size);

        // Copy the bytes, crossing boundaries in the original vec.
        for i in range(idx / 2, self.data.len() - 1) {
            // The first half is the second half of the old entry.
            let first_half = self.data[i] & 0x0f;

            // The second half is the first half of the next entry.
            let second_half = self.data[i + 1] >> 4;

            tail_vec.push((first_half << 4) | second_half);
        }

        // If the new length is odd, get the trailing half-byte from the old vector.
        let tail_length = self.length - idx;

        if tail_length % 2 == 1 {
            let last = self.data[self.data.len() - 1] & 0x0f;
            tail_vec.push(last << 4);
        }

        // Remove the copied bytes, being careful to skip the idx byte.
        for _ in range(idx / 2 + 1, self.data.len()) {
            self.data.pop();
        }

        // Update the length of the first NibbleVec.
        self.length = idx;

        NibbleVec {
            length: tail_length,
            data: tail_vec
        }
    }

    #[inline(always)]
    fn split_even(&mut self, idx: uint) -> NibbleVec {
        // Avoid allocating a temporary vector by copying all the bytes in order, then popping them.
        let tail_vec_size = (self.length - idx) / 2;
        let mut tail_vec = Vec::with_capacity(tail_vec_size);

        // Copy the bytes.
        for i in range(idx / 2, self.data.len()) {
            tail_vec.push(self.data[i]);
        }

        // Pop the same bytes.
        for _ in range(0, tail_vec_size) {
            self.data.pop();
        }

        let tail_length = self.length - idx;
        self.length = idx;

        NibbleVec {
            length: tail_length,
            data: tail_vec
        }
    }
}

#[cfg(test)]
mod test {
    use NibbleVec;

    #[test]
    fn get() {
        let nv = NibbleVec::from_byte_vec(vec![4 << 4 | 8]);
        assert_eq!(nv.get(0).unwrap(), 4u8);
        assert_eq!(nv.get(1).unwrap(), 8u8);
    }

    #[test]
    fn push() {
        let mut nv = NibbleVec::new();
        let data: Vec<u8> = vec![0, 1, 3, 5, 7, 9, 11, 15];
        for val in data.iter() {
            nv.push(*val);
        }

        for (i, val) in data.iter().enumerate() {
            assert_eq!(nv.get(i).unwrap(), *val);
        }
    }

    #[test]
    fn split_even_idx() {
        // Even index, even length.
        let mut nv = NibbleVec::from_byte_vec(vec![
            10 << 4 | 11,
            12 << 4 | 13
        ]);

        let tail = nv.split(2);
        assert_eq!(nv.len(), 2u);
        assert_eq!(tail.len(), 2u);
        assert_eq!(nv.get(0).unwrap(), 10u8);
        assert_eq!(nv.get(1).unwrap(), 11u8);
        assert_eq!(tail.get(0).unwrap(), 12u8);
        assert_eq!(tail.get(1).unwrap(), 13u8);

        // Even index, odd length.
        nv.push(14u8);
        let tail = nv.split(2);
        assert_eq!(nv.len(), 2u);
        assert_eq!(tail.len(), 1u);
        assert_eq!(nv.get(0).unwrap(), 10u8);
        assert_eq!(nv.get(1).unwrap(), 11u8);
        assert_eq!(tail.get(0).unwrap(), 14u8);
    }

    #[test]
    fn split_odd_idx() {
        // Odd index, even length.
        let mut nv = NibbleVec::from_byte_vec(vec![
            10 << 4 | 11,
            12 << 4 | 13
        ]);

        let tail = nv.split(3);
        assert_eq!(nv.len(), 3u);
        assert_eq!(tail.len(), 1u);
        for i in range(0, nv.len()) {
            assert_eq!(nv.get(i).unwrap(), (i + 10) as u8);
        }
        assert_eq!(tail.get(0).unwrap(), 13u8);

        // Odd index, odd length.
        let tail = nv.split(1);
        assert_eq!(nv.len(), 1u);
        assert_eq!(tail.len(), 2u);
        assert_eq!(nv.get(0).unwrap(), 10u8);
        assert_eq!(tail.get(0).unwrap(), 11u8);
        assert_eq!(tail.get(1).unwrap(), 12u8);
    }
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate unicase;
extern crate hyper;

use unicase::UniCase;
use iron::prelude::*;
use iron::method::Method;
use iron::method::Method::*;
use iron::status;
use iron::headers::Origin as OriginHeader;
use iron::headers::{AccessControlRequestMethod, AccessControlRequestHeaders,
                    AccessControlAllowOrigin, AccessControlAllowHeaders, AccessControlMaxAge,
                    AccessControlAllowMethods, AccessControlAllowCredentials};
use iron::middleware::{AroundMiddleware, Handler};
use std::collections::HashSet;
use std::iter::FromIterator;
use hyper::Url;

// A struct which implements origin as defined in
// https://tools.ietf.org/html/rfc6454
//
// Does not cover the unique identifyer approach for
// non-hierarchical naming authority
//
// also see https://en.wikipedia.org/wiki/Same-origin_policy
//
#[derive(PartialEq, Hash)]
pub struct Origin {
    pub scheme: String,
    pub host: String,
    pub port: Option<u16>,
}

impl Origin {
    fn parse(s: &str) -> Result<Origin, String> {
        match Url::parse(s) {
            Err(_) => Err("Could not be parsed as Url".to_owned()),
            Ok(url) => {
                match url.host() {
                    Some(host) => {
                        Ok(Origin {
                               scheme: url.scheme().to_owned(),
                               host: host.to_string(),
                               port: url.port(),
                           })
                    }
                    None => Err("No host in URL".to_owned()),
                }
            }
        }
    }
}

// Using case-sensitive match of protocol://host:port
// For a formal definition, see
// https://tools.ietf.org/html/rfc6454#section-4
pub enum AllowedOrigins {
    Any { prefer_wildcard: bool },
    Specific(HashSet<Url>),
}

impl AllowedOrigins {
    fn allowed_for(&self, origin: &String, allow_credentials: bool) -> Option<String> {
        match Url::parse(origin) {
            Err(_) => None,
            Ok(origin_url) => {
                match self {
                    &AllowedOrigins::Any { prefer_wildcard } => {
                        if allow_credentials {
                            // Allow credentials does not permit using wildcard
                            Some(origin.clone())
                        } else {
                            // Use wildcard if preferred
                            Some(if prefer_wildcard {
                                     "*".to_owned()
                                 } else {
                                     origin.clone()
                                 })
                        }
                    }
                    &AllowedOrigins::Specific(ref allowed) => {
                        if allowed.contains(&origin_url) {
                            Some(origin.clone())
                        } else {
                            None
                        }
                    }
                }
            }
        }

    }
}

pub struct CorsMiddleware {
    pub allowed_origins: AllowedOrigins,
    // Having allowed methods "any" would not make much sense
    // since we need to enumerate all methods when returning
    // the allowed-methods header
    pub allowed_methods: Vec<Method>,
    pub allowed_headers: Vec<UniCase<String>>,
    pub exposed_headers: Vec<String>,
    pub allow_credentials: bool,
    pub max_age_seconds: u32,
}

impl CorsMiddleware {
    pub fn new() -> CorsMiddleware {
        let allowed_methods: Vec<Method> = vec![Options, Get, Post, Put, Delete, Head, Trace,
                                                Connect, Patch];
        let allowed_headers: Vec<unicase::UniCase<String>> =
            vec![// To allow application/json
                 UniCase("Content-Type".to_owned()),
                 // Set by some js libs
                 UniCase("X-Requested-With".to_owned())];
        let exposed_headers: Vec<String> = Vec::new();
        CorsMiddleware {
            allowed_origins: AllowedOrigins::Any { prefer_wildcard: false },
            allowed_methods: allowed_methods,
            allowed_headers: allowed_headers,
            exposed_headers: exposed_headers,
            allow_credentials: false,
            max_age_seconds: 60 * 60,
        }
    }

    fn handle(&self, req: &mut Request, handler: &Handler) -> IronResult<Response> {
        // http://stackoverflow.com/questions/14015118/
        // what-is-the-expected-response-to-an-invalid-cors-request
        // http://stackoverflow.com/questions/32331737/
        // how-can-i-identify-a-cors-preflight-request
        if req.method == Options && req.headers.get::<AccessControlRequestMethod>().is_some() {
            self.handle_preflight(req, handler)
        } else {
            self.handle_normal(req, handler)
        }
    }

    fn handle_preflight(&self, req: &mut Request, _: &Handler) -> IronResult<Response> {
        // Successful preflight status code is NoContent
        let mut res = Response::with((status::NoContent));

        // - Preflight request
        // - 1.If the Origin header is not present terminate this set of steps. The request is
        // - outside the scope of this specification.
        let maybe_origin = req.headers.get::<OriginHeader>();
        if maybe_origin.is_none() {
            let resp = Response::with((status::BadRequest,
                                       "Preflight request without Origin header"));
            return Ok(resp);
        }
        let origin = maybe_origin.unwrap();
        //
        // - 2.If the value of the Origin header is not a case-sensitive match for any of the
        // - values in list of origins do not set any additional headers and terminate this
        // - set of steps.
        //
        // - Note: Always matching is acceptable since the list of origins can be unbounded.
        //
        // - Note: The Origin header can only contain a single origin as the user agent
        //       will not follow redirects.
        //
        let origin_str = origin.to_string();
        let allowed_origin = self.allowed_origins.allowed_for(&origin_str, self.allow_credentials);
        if allowed_origin.is_none() {
            let resp = Response::with((status::BadRequest,
                                       format!("Preflight request requesting \
                                       disallowed origin '{}'",
                                               origin_str)));
            return Ok(resp);
        }
        //
        // - 3. Let method be the value as result of parsing the Access-Control-Request-Method
        // - header.
        //
        // - If there is no Access-Control-Request-Method header or if parsing failed, do not
        // - set any additional headers and terminate this set of steps. The request is
        // - outside the scope of this specification.

        // We can assume that this header exists, since we already checked that before
        // classifying the request as preflight
        let requested_method = req.headers.get::<AccessControlRequestMethod>().unwrap();

        //
        // - 4. Let header field-names be the values as result of parsing the
        // - Access-Control-Request-Headers headers.
        //
        // - If there are no Access-Control-Request-Headers headers let header field-names be
        // - the empty list.
        //
        // - If parsing failed do not set any additional headers and terminate this set of
        // - steps. The request is outside the scope of this specification.
        //
        let empty_vec: Vec<UniCase<String>> = vec![];
        let maybe_requested_headers = req.headers.get::<AccessControlRequestHeaders>();
        let requested_headers: &Vec<UniCase<String>> = if maybe_requested_headers.is_some() {
            &maybe_requested_headers.unwrap().0
        } else {
            &empty_vec
        };
        // - 5.If method is not a case-sensitive match for any of the values in list of
        // -   methods do not set any additional headers and terminate this set of steps.
        //
        // - Always matching is acceptable since the list of methods can be unbounded.
        //
        if !self.allowed_methods.contains(requested_method) {
            return Ok(Response::with((status::BadRequest,
                                      format!("Preflight request requesting disallowed method {}",
                                              requested_method))));
        }
        // - 6. If any of the header field-names is not a ASCII case-insensitive match for any
        // - of the values in list of headers do not set any additional headers and terminate
        // - this set of steps.
        let requested_headers_set: HashSet<UniCase<String>> =
            HashSet::from_iter(requested_headers.iter().cloned());
        let allowed_headers_set: HashSet<UniCase<String>> =
            HashSet::from_iter(self.allowed_headers.iter().cloned());
        let disallowed_headers: HashSet<UniCase<String>> =
            requested_headers_set.difference(&allowed_headers_set).cloned().collect();
        if !disallowed_headers.is_empty() {
            let a = disallowed_headers.iter()
                .map(|uh| uh.to_string())
                .collect::<Vec<_>>()
                .join(",");
            let msg = format!("Preflight request requesting disallowed header(s) {}", a);
            return Ok(Response::with((status::BadRequest, msg)));

        }
        //
        // - Always matching is acceptable since the list of headers can be unbounded.
        //
        // - 7. If the resource supports credentials add a single Access-Control-Allow-Origin
        // - header, with the value of the Origin header as value, and add a single
        // - Access-Control-Allow-Credentials header with the case-sensitive string "true" as
        // - value.
        //
        // - Otherwise, add a single Access-Control-Allow-Origin header, with either the
        // - value of the Origin header or the string "*" as value.
        //
        // - The string "*" cannot be used for a resource that supports credentials.
        //
        if self.allow_credentials {
            res.headers.set(AccessControlAllowCredentials);
        }
        res.headers.set(AccessControlAllowOrigin::Value(allowed_origin.unwrap()));
        // - 8. Optionally add a single Access-Control-Max-Age header with as value the amount
        // - of seconds the user agent is allowed to cache the result of the request.
        res.headers.set(AccessControlMaxAge(self.max_age_seconds));
        //
        // - 9. If method is a simple method this step may be skipped.
        //
        // - Add one or more Access-Control-Allow-Methods headers consisting of (a subset of)
        // - the list of methods.
        //
        // - If a method is a simple method it does not need to be listed, but this is not
        // - prohibited.
        //
        // - Since the list of methods can be unbounded, simply returning the method
        // - indicated by Access-Control-Request-Method (if supported) can be enough.
        //
        res.headers.set(AccessControlAllowMethods(self.allowed_methods.clone()));
        // - 10.If each of the header field-names is a simple header and none is Content-Type,
        // - this step may be skipped.
        //
        // - Add one or more Access-Control-Allow-Headers headers consisting of (a subset of)
        // - the list of headers.
        //
        // - If a header field name is a simple header and is not Content-Type, it is not
        // - required to be listed. Content-Type is to be listed as only a subset of its
        // - values makes it qualify as simple header.
        //
        // - Since the list of headers can be unbounded, simply returning supported headers
        // - from Access-Control-Allow-Headers can be enough.
        res.headers.set(AccessControlAllowHeaders(self.allowed_headers.clone()));
        Ok(res)
    }

    fn handle_normal(&self, req: &mut Request, handler: &Handler) -> IronResult<Response> {
        // Normal request
        // 1.If the Origin header is not present terminate this set of steps. The request is
        // outside the scope of this specification.
        let has_origin = req.headers.get::<OriginHeader>().is_some();
        if !has_origin {
            return handler.handle(req);
        }
        //
        // 2.If the value of the Origin header is not a case-sensitive match for any of the
        // values in list of origins, do not set any additional headers and terminate this
        // set of steps.
        //
        // Note: Always matching is acceptable since the list of origins can be unbounded.
        //
        // 3. If the resource supports credentials add a single Access-Control-Allow-Origin
        // header, with the value of the Origin header as value, and add a single
        // Access-Control-Allow-Credentials header with the case-sensitive string "true" as
        // value.
        //
        // Otherwise, add a single Access-Control-Allow-Origin header, with either the
        // value of the Origin header or the string "*" as value.
        //
        // Note: The string "*" cannot be used for a resource that supports credentials.
        //
        // 4. If the list of exposed headers is not empty add one or more
        // Access-Control-Expose-Headers headers, with as values the header field names
        // given in the list of exposed headers.
        let result = handler.handle(req);
        match result {
            Ok(mut res) => {
                // And set CORS headers
                let origin = req.headers.get::<OriginHeader>().unwrap();
                res.headers.set(AccessControlAllowOrigin::Value(format!("{}", origin)));
                Ok(res)
            }
            _ => result,
        }
    }
}

impl AroundMiddleware for CorsMiddleware {
    fn around(self, handler: Box<Handler>) -> Box<Handler> {
        Box::new(move |req: &mut Request| self.handle(req, &handler))
    }
}
<commit_msg>origin with host lowercasing<commit_after>extern crate iron;
extern crate unicase;
extern crate hyper;

use unicase::UniCase;
use iron::prelude::*;
use iron::method::Method;
use iron::method::Method::*;
use iron::status;
use iron::headers::Origin as OriginHeader;
use iron::headers::{AccessControlRequestMethod, AccessControlRequestHeaders,
                    AccessControlAllowOrigin, AccessControlAllowHeaders, AccessControlMaxAge,
                    AccessControlAllowMethods, AccessControlAllowCredentials};
use iron::middleware::{AroundMiddleware, Handler};
use std::collections::HashSet;
use std::iter::FromIterator;
use hyper::Url;
use std::ascii::AsciiExt;

// A struct which implements origin as defined in
// https://tools.ietf.org/html/rfc6454
//
// Does not cover the unique identifyer approach for
// non-hierarchical naming authority
//
// also see https://en.wikipedia.org/wiki/Same-origin_policy
//
#[derive(PartialEq, Hash)]
pub struct Origin {
    pub scheme: String,
    pub host: String,
    pub port: Option<u16>,
}

impl Origin {
    fn parse(s: &str) -> Result<Origin, String> {
        match Url::parse(s) {
            Err(_) => Err("Could not be parsed as Url".to_owned()),
            Ok(url) => {
                // - 1.  If the URI does not use a hierarchical element as a naming
                // - authority (see [RFC3986], Section 3.2) or if the URI is not an
                // - absolute URI, then generate a fresh globally unique identifier
                // - and return that value.
                //
                // From https://hyper.rs/hyper/0.8.0/hyper/struct.Url.html#method.host:
                // host(): If the URL is in a relative scheme, return its structured host.
                match url.host_str() {
                    None => Err(format!("No host in URL '{}'", url)),
                    Some(host_str) => {
                        // - 2. Let uri-scheme be the scheme component of the URI, converted to
                        // - lowercase.
                        let uri_scheme = url.scheme().to_owned().to_lowercase();

                        //  4.  If uri-scheme is "file", the implementation MAY return an
                        //  - implementation-defined value...
                        // NOTE: file scheme not supported, would have bailed already

                        // - 5. Let uri-host be the host component of the URI, converted to lower
                        // - case (using the i;ascii-casemap collation defined in [RFC4790]).
                        //
                        // regarding i;ascii-casemap:
                        // - Its equality, ordering, and substring operations are as for i;octet,
                        // - except that at first, the lower-case letters (octet values 97-122) in
                        // - each input string are changed to upper case (octet values 65-90).

                        let uri_host = host_str.to_ascii_lowercase();

                        // 6.  If there is no port component of the URI:
                        //    1.  Let uri-port be the default port for the protocol given by
                        //        uri-scheme.
                        //        Otherwise:
                        //    2.  Let uri-port be the port component of the URI.
                        let uri_port = url.port_or_known_default();

                        // - 3.  If the implementation doesn't support the protocol given by uri-
                        // - scheme, then generate a fresh globally unique identifier and
                        // - return that value.
                        match uri_port {
                            None => Err(format!("Unsupported URL scheme	'{}'", uri_scheme)),
                            Some(port) => {

                            //   7.  Return the triple (uri-scheme, uri-host, uri-port).
                            Ok(Origin {
                                   scheme: uri_scheme,
                                   host: uri_host,
                                   port: uri_port,
                               })
                               }
                        }
                    }
                }
            }
        }
    }
}

// Using case-sensitive match of protocol://host:port
// For a formal definition, see
// https://tools.ietf.org/html/rfc6454#section-4
pub enum AllowedOrigins {
    Any { prefer_wildcard: bool },
    Specific(HashSet<Url>),
}

impl AllowedOrigins {
    fn allowed_for(&self, origin: &String, allow_credentials: bool) -> Option<String> {
        match Url::parse(origin) {
            Err(_) => None,
            Ok(origin_url) => {
                match self {
                    &AllowedOrigins::Any { prefer_wildcard } => {
                        if allow_credentials {
                            // Allow credentials does not permit using wildcard
                            Some(origin.clone())
                        } else {
                            // Use wildcard if preferred
                            Some(if prefer_wildcard {
                                     "*".to_owned()
                                 } else {
                                     origin.clone()
                                 })
                        }
                    }
                    &AllowedOrigins::Specific(ref allowed) => {
                        if allowed.contains(&origin_url) {
                            Some(origin.clone())
                        } else {
                            None
                        }
                    }
                }
            }
        }

    }
}

pub struct CorsMiddleware {
    pub allowed_origins: AllowedOrigins,
    // Having allowed methods "any" would not make much sense
    // since we need to enumerate all methods when returning
    // the allowed-methods header
    pub allowed_methods: Vec<Method>,
    pub allowed_headers: Vec<UniCase<String>>,
    pub exposed_headers: Vec<String>,
    pub allow_credentials: bool,
    pub max_age_seconds: u32,
}

impl CorsMiddleware {
    pub fn new() -> CorsMiddleware {
        let allowed_methods: Vec<Method> = vec![Options, Get, Post, Put, Delete, Head, Trace,
                                                Connect, Patch];
        let allowed_headers: Vec<unicase::UniCase<String>> =
            vec![// To allow application/json
                 UniCase("Content-Type".to_owned()),
                 // Set by some js libs
                 UniCase("X-Requested-With".to_owned())];
        let exposed_headers: Vec<String> = Vec::new();
        CorsMiddleware {
            allowed_origins: AllowedOrigins::Any { prefer_wildcard: false },
            allowed_methods: allowed_methods,
            allowed_headers: allowed_headers,
            exposed_headers: exposed_headers,
            allow_credentials: false,
            max_age_seconds: 60 * 60,
        }
    }

    fn handle(&self, req: &mut Request, handler: &Handler) -> IronResult<Response> {
        // http://stackoverflow.com/questions/14015118/
        // what-is-the-expected-response-to-an-invalid-cors-request
        // http://stackoverflow.com/questions/32331737/
        // how-can-i-identify-a-cors-preflight-request
        if req.method == Options && req.headers.get::<AccessControlRequestMethod>().is_some() {
            self.handle_preflight(req, handler)
        } else {
            self.handle_normal(req, handler)
        }
    }

    fn handle_preflight(&self, req: &mut Request, _: &Handler) -> IronResult<Response> {
        // Successful preflight status code is NoContent
        let mut res = Response::with((status::NoContent));

        // - Preflight request
        // - 1.If the Origin header is not present terminate this set of steps. The request is
        // - outside the scope of this specification.
        let maybe_origin = req.headers.get::<OriginHeader>();
        if maybe_origin.is_none() {
            let resp = Response::with((status::BadRequest,
                                       "Preflight request without Origin header"));
            return Ok(resp);
        }
        let origin = maybe_origin.unwrap();
        //
        // - 2.If the value of the Origin header is not a case-sensitive match for any of the
        // - values in list of origins do not set any additional headers and terminate this
        // - set of steps.
        //
        // - Note: Always matching is acceptable since the list of origins can be unbounded.
        //
        // - Note: The Origin header can only contain a single origin as the user agent
        //       will not follow redirects.
        //
        let origin_str = origin.to_string();
        let allowed_origin = self.allowed_origins.allowed_for(&origin_str, self.allow_credentials);
        if allowed_origin.is_none() {
            let resp = Response::with((status::BadRequest,
                                       format!("Preflight request requesting \
                                       disallowed origin '{}'",
                                               origin_str)));
            return Ok(resp);
        }
        //
        // - 3. Let method be the value as result of parsing the Access-Control-Request-Method
        // - header.
        //
        // - If there is no Access-Control-Request-Method header or if parsing failed, do not
        // - set any additional headers and terminate this set of steps. The request is
        // - outside the scope of this specification.

        // We can assume that this header exists, since we already checked that before
        // classifying the request as preflight
        let requested_method = req.headers.get::<AccessControlRequestMethod>().unwrap();

        //
        // - 4. Let header field-names be the values as result of parsing the
        // - Access-Control-Request-Headers headers.
        //
        // - If there are no Access-Control-Request-Headers headers let header field-names be
        // - the empty list.
        //
        // - If parsing failed do not set any additional headers and terminate this set of
        // - steps. The request is outside the scope of this specification.
        //
        let empty_vec: Vec<UniCase<String>> = vec![];
        let maybe_requested_headers = req.headers.get::<AccessControlRequestHeaders>();
        let requested_headers: &Vec<UniCase<String>> = if maybe_requested_headers.is_some() {
            &maybe_requested_headers.unwrap().0
        } else {
            &empty_vec
        };
        // - 5.If method is not a case-sensitive match for any of the values in list of
        // -   methods do not set any additional headers and terminate this set of steps.
        //
        // - Always matching is acceptable since the list of methods can be unbounded.
        //
        if !self.allowed_methods.contains(requested_method) {
            return Ok(Response::with((status::BadRequest,
                                      format!("Preflight request requesting disallowed method {}",
                                              requested_method))));
        }
        // - 6. If any of the header field-names is not a ASCII case-insensitive match for any
        // - of the values in list of headers do not set any additional headers and terminate
        // - this set of steps.
        let requested_headers_set: HashSet<UniCase<String>> =
            HashSet::from_iter(requested_headers.iter().cloned());
        let allowed_headers_set: HashSet<UniCase<String>> =
            HashSet::from_iter(self.allowed_headers.iter().cloned());
        let disallowed_headers: HashSet<UniCase<String>> =
            requested_headers_set.difference(&allowed_headers_set).cloned().collect();
        if !disallowed_headers.is_empty() {
            let a = disallowed_headers.iter()
                .map(|uh| uh.to_string())
                .collect::<Vec<_>>()
                .join(",");
            let msg = format!("Preflight request requesting disallowed header(s) {}", a);
            return Ok(Response::with((status::BadRequest, msg)));

        }
        //
        // - Always matching is acceptable since the list of headers can be unbounded.
        //
        // - 7. If the resource supports credentials add a single Access-Control-Allow-Origin
        // - header, with the value of the Origin header as value, and add a single
        // - Access-Control-Allow-Credentials header with the case-sensitive string "true" as
        // - value.
        //
        // - Otherwise, add a single Access-Control-Allow-Origin header, with either the
        // - value of the Origin header or the string "*" as value.
        //
        // - The string "*" cannot be used for a resource that supports credentials.
        //
        if self.allow_credentials {
            res.headers.set(AccessControlAllowCredentials);
        }
        res.headers.set(AccessControlAllowOrigin::Value(allowed_origin.unwrap()));
        // - 8. Optionally add a single Access-Control-Max-Age header with as value the amount
        // - of seconds the user agent is allowed to cache the result of the request.
        res.headers.set(AccessControlMaxAge(self.max_age_seconds));
        //
        // - 9. If method is a simple method this step may be skipped.
        //
        // - Add one or more Access-Control-Allow-Methods headers consisting of (a subset of)
        // - the list of methods.
        //
        // - If a method is a simple method it does not need to be listed, but this is not
        // - prohibited.
        //
        // - Since the list of methods can be unbounded, simply returning the method
        // - indicated by Access-Control-Request-Method (if supported) can be enough.
        //
        res.headers.set(AccessControlAllowMethods(self.allowed_methods.clone()));
        // - 10.If each of the header field-names is a simple header and none is Content-Type,
        // - this step may be skipped.
        //
        // - Add one or more Access-Control-Allow-Headers headers consisting of (a subset of)
        // - the list of headers.
        //
        // - If a header field name is a simple header and is not Content-Type, it is not
        // - required to be listed. Content-Type is to be listed as only a subset of its
        // - values makes it qualify as simple header.
        //
        // - Since the list of headers can be unbounded, simply returning supported headers
        // - from Access-Control-Allow-Headers can be enough.
        res.headers.set(AccessControlAllowHeaders(self.allowed_headers.clone()));
        Ok(res)
    }

    fn handle_normal(&self, req: &mut Request, handler: &Handler) -> IronResult<Response> {
        // Normal request
        // 1.If the Origin header is not present terminate this set of steps. The request is
        // outside the scope of this specification.
        let has_origin = req.headers.get::<OriginHeader>().is_some();
        if !has_origin {
            return handler.handle(req);
        }
        //
        // 2.If the value of the Origin header is not a case-sensitive match for any of the
        // values in list of origins, do not set any additional headers and terminate this
        // set of steps.
        //
        // Note: Always matching is acceptable since the list of origins can be unbounded.
        //
        // 3. If the resource supports credentials add a single Access-Control-Allow-Origin
        // header, with the value of the Origin header as value, and add a single
        // Access-Control-Allow-Credentials header with the case-sensitive string "true" as
        // value.
        //
        // Otherwise, add a single Access-Control-Allow-Origin header, with either the
        // value of the Origin header or the string "*" as value.
        //
        // Note: The string "*" cannot be used for a resource that supports credentials.
        //
        // 4. If the list of exposed headers is not empty add one or more
        // Access-Control-Expose-Headers headers, with as values the header field names
        // given in the list of exposed headers.
        let result = handler.handle(req);
        match result {
            Ok(mut res) => {
                // And set CORS headers
                let origin = req.headers.get::<OriginHeader>().unwrap();
                res.headers.set(AccessControlAllowOrigin::Value(format!("{}", origin)));
                Ok(res)
            }
            _ => result,
        }
    }
}

impl AroundMiddleware for CorsMiddleware {
    fn around(self, handler: Box<Handler>) -> Box<Handler> {
        Box::new(move |req: &mut Request| self.handle(req, &handler))
    }
}
<|endoftext|>


<commit_before>//! Demangle Rust compiler symbol names.
//!
//! This crate provides a `demangle` function which will return a `Demangle`
//! sentinel value that can be used to learn about the demangled version of a
//! symbol name. The demangled representation will be the same as the original
//! if it doesn't look like a mangled symbol name.
//!
//! # Examples
//!
//! ```
//! use rustc_demangle::demangle;
//!
//! assert_eq!(demangle("_ZN4testE").to_string(), "test");
//! assert_eq!(demangle("_ZN3foo3barE").to_string(), "foo::bar");
//! assert_eq!(demangle("foo").to_string(), "foo");
//! ```

#![no_std]
#![deny(missing_docs)]

#[cfg(test)]
#[macro_use]
extern crate std;

use core::fmt;

/// Representation of a demangled symbol name.
pub struct Demangle<'a> {
    original: &'a str,
    inner: &'a str,
    valid: bool,
}

/// De-mangles a Rust symbol into a more readable version
///
/// All rust symbols by default are mangled as they contain characters that
/// cannot be represented in all object files. The mangling mechanism is similar
/// to C++'s, but Rust has a few specifics to handle items like lifetimes in
/// symbols.
///
/// This function will take a **mangled** symbol (typically acquired from a
/// `Symbol` which is in turn resolved from a `Frame`) and then writes the
/// de-mangled version into the given `writer`. If the symbol does not look like
/// a mangled symbol, it is still written to `writer`.
///
/// # Examples
///
/// ```
/// use rustc_demangle::demangle;
///
/// assert_eq!(demangle("_ZN4testE").to_string(), "test");
/// assert_eq!(demangle("_ZN3foo3barE").to_string(), "foo::bar");
/// assert_eq!(demangle("foo").to_string(), "foo");
/// ```

// All rust symbols are in theory lists of "::"-separated identifiers. Some
// assemblers, however, can't handle these characters in symbol names. To get
// around this, we use C++-style mangling. The mangling method is:
//
// 1. Prefix the symbol with "_ZN"
// 2. For each element of the path, emit the length plus the element
// 3. End the path with "E"
//
// For example, "_ZN4testE" => "test" and "_ZN3foo3barE" => "foo::bar".
//
// We're the ones printing our backtraces, so we can't rely on anything else to
// demangle our symbols. It's *much* nicer to look at demangled symbols, so
// this function is implemented to give us nice pretty output.
//
// Note that this demangler isn't quite as fancy as it could be. We have lots
// of other information in our symbols like hashes, version, type information,
// etc. Additionally, this doesn't handle glue symbols at all.
pub fn demangle(s: &str) -> Demangle {
    // First validate the symbol. If it doesn't look like anything we're
    // expecting, we just print it literally. Note that we must handle non-rust
    // symbols because we could have any function in the backtrace.
    let mut valid = true;
    let mut inner = s;
    if s.len() > 4 && s.starts_with("_ZN") && s.ends_with("E") {
        inner = &s[3 .. s.len() - 1];
    // On Windows, dbghelp strips leading underscores, so we accept "ZN...E"
    // form too.
    } else if s.len() > 3 && s.starts_with("ZN") && s.ends_with("E") {
        inner = &s[2 .. s.len() - 1];
    } else {
        valid = false;
    }

    if valid {
        let mut chars = inner.chars();
        while valid {
            let mut i = 0;
            for c in chars.by_ref() {
                if c.is_digit(10) {
                    i = i * 10 + c as usize - '0' as usize;
                } else {
                    break
                }
            }
            if i == 0 {
                valid = chars.next().is_none();
                break
            } else if chars.by_ref().take(i - 1).count() != i - 1 {
                valid = false;
            }
        }
    }

    Demangle { inner: inner, valid: valid, original: s }
}

impl<'a> Demangle<'a> {
    /// Returns the underlying string that's being demangled.
    pub fn as_str(&self) -> &'a str {
        self.original
    }
}

impl<'a> fmt::Display for Demangle<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Alright, let's do this.
        if !self.valid {
            return f.write_str(self.inner);
        }

        let mut inner = self.inner;
        let mut first = true;
        while !inner.is_empty() {
            if !first {
                try!(f.write_str("::"));
            } else {
                first = false;
            }
            let mut rest = inner;
            while rest.chars().next().unwrap().is_digit(10) {
                rest = &rest[1..];
            }
            let i: usize = inner[..(inner.len() - rest.len())].parse().unwrap();
            inner = &rest[i..];
            rest = &rest[..i];
            while !rest.is_empty() {
                if rest.starts_with("$") {
                    macro_rules! demangle {
                        ($($pat:expr, => $demangled:expr),*) => ({
                            $(if rest.starts_with($pat) {
                                try!(f.write_str($demangled));
                                rest = &rest[$pat.len()..];
                              } else)*
                            {
                                try!(f.write_str(rest));
                                break;
                            }

                        })
                    }

                    // see src/librustc_trans/back/symbol_names.rs for these
                    // mappings, historical ones also included.
                    demangle! {
                        "$SP$", => "@",
                        "$BP$", => "*",
                        "$RF$", => "&",
                        "$LT$", => "<",
                        "$GT$", => ">",
                        "$LP$", => "(",
                        "$RP$", => ")",
                        "$C$", => ",",

                        // in theory we can demangle any Unicode code point, but
                        // for simplicity we just catch the common ones.
                        "$u7e$", => "~",
                        "$u20$", => " ",
                        "$u27$", => "'",
                        "$u5b$", => "[",
                        "$u5d$", => "]",
                        "$u7b$", => "{",
                        "$u7d$", => "}"
                    }
                } else {
                    let idx = rest.find('$').unwrap_or(rest.len());
                    try!(f.write_str(&rest[..idx]));
                    rest = &rest[idx..];
                }
            }
        }

        Ok(())
    }
}

impl<'a> fmt::Debug for Demangle<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

#[cfg(test)]
mod tests {
    use std::prelude::v1::*;

    macro_rules! t {
        ($a:expr, $b:expr) => ({
            assert_eq!(super::demangle($a).to_string(), $b);
        })
    }

    #[test]
    fn demangle() {
        t!("test", "test");
        t!("_ZN4testE", "test");
        t!("_ZN4test", "_ZN4test");
        t!("_ZN4test1a2bcE", "test::a::bc");
    }

    #[test]
    fn demangle_dollars() {
        t!("_ZN4$RP$E", ")");
        t!("_ZN8$RF$testE", "&test");
        t!("_ZN8$BP$test4foobE", "*test::foob");
        t!("_ZN9$u20$test4foobE", " test::foob");
    }

    #[test]
    fn demangle_many_dollars() {
        t!("_ZN13test$u20$test4foobE", "test test::foob");
        t!("_ZN12test$BP$test4foobE", "test*test::foob");
    }

    #[test]
    fn demangle_windows() {
        t!("ZN4testE", "test");
        t!("ZN13test$u20$test4foobE", "test test::foob");
        t!("ZN12test$RF$test4foobE", "test&test::foob");
    }
}
<commit_msg>Update to match rust-lang/rust#36059<commit_after>//! Demangle Rust compiler symbol names.
//!
//! This crate provides a `demangle` function which will return a `Demangle`
//! sentinel value that can be used to learn about the demangled version of a
//! symbol name. The demangled representation will be the same as the original
//! if it doesn't look like a mangled symbol name.
//!
//! # Examples
//!
//! ```
//! use rustc_demangle::demangle;
//!
//! assert_eq!(demangle("_ZN4testE").to_string(), "test");
//! assert_eq!(demangle("_ZN3foo3barE").to_string(), "foo::bar");
//! assert_eq!(demangle("foo").to_string(), "foo");
//! ```

#![no_std]
#![deny(missing_docs)]

#[cfg(test)]
#[macro_use]
extern crate std;

use core::fmt;

/// Representation of a demangled symbol name.
pub struct Demangle<'a> {
    original: &'a str,
    inner: &'a str,
    valid: bool,
}

/// De-mangles a Rust symbol into a more readable version
///
/// All rust symbols by default are mangled as they contain characters that
/// cannot be represented in all object files. The mangling mechanism is similar
/// to C++'s, but Rust has a few specifics to handle items like lifetimes in
/// symbols.
///
/// This function will take a **mangled** symbol (typically acquired from a
/// `Symbol` which is in turn resolved from a `Frame`) and then writes the
/// de-mangled version into the given `writer`. If the symbol does not look like
/// a mangled symbol, it is still written to `writer`.
///
/// # Examples
///
/// ```
/// use rustc_demangle::demangle;
///
/// assert_eq!(demangle("_ZN4testE").to_string(), "test");
/// assert_eq!(demangle("_ZN3foo3barE").to_string(), "foo::bar");
/// assert_eq!(demangle("foo").to_string(), "foo");
/// ```

// All rust symbols are in theory lists of "::"-separated identifiers. Some
// assemblers, however, can't handle these characters in symbol names. To get
// around this, we use C++-style mangling. The mangling method is:
//
// 1. Prefix the symbol with "_ZN"
// 2. For each element of the path, emit the length plus the element
// 3. End the path with "E"
//
// For example, "_ZN4testE" => "test" and "_ZN3foo3barE" => "foo::bar".
//
// We're the ones printing our backtraces, so we can't rely on anything else to
// demangle our symbols. It's *much* nicer to look at demangled symbols, so
// this function is implemented to give us nice pretty output.
//
// Note that this demangler isn't quite as fancy as it could be. We have lots
// of other information in our symbols like hashes, version, type information,
// etc. Additionally, this doesn't handle glue symbols at all.
pub fn demangle(s: &str) -> Demangle {
    // First validate the symbol. If it doesn't look like anything we're
    // expecting, we just print it literally. Note that we must handle non-rust
    // symbols because we could have any function in the backtrace.
    let mut valid = true;
    let mut inner = s;
    if s.len() > 4 && s.starts_with("_ZN") && s.ends_with('E') {
        inner = &s[3..s.len() - 1];
    } else if s.len() > 3 && s.starts_with("ZN") && s.ends_with('E') {
        // On Windows, dbghelp strips leading underscores, so we accept "ZN...E"
        // form too.
        inner = &s[2..s.len() - 1];
    } else {
        valid = false;
    }

    if valid {
        let mut chars = inner.chars();
        while valid {
            let mut i = 0;
            for c in chars.by_ref() {
                if c.is_digit(10) {
                    i = i * 10 + c as usize - '0' as usize;
                } else {
                    break;
                }
            }
            if i == 0 {
                valid = chars.next().is_none();
                break;
            } else if chars.by_ref().take(i - 1).count() != i - 1 {
                valid = false;
            }
        }
    }

    Demangle {
        inner: inner,
        valid: valid,
        original: s,
    }
}

impl<'a> Demangle<'a> {
    /// Returns the underlying string that's being demangled.
    pub fn as_str(&self) -> &'a str {
        self.original
    }
}

impl<'a> fmt::Display for Demangle<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Alright, let's do this.
        if !self.valid {
            return f.write_str(self.inner);
        }

        let mut inner = self.inner;
        let mut first = true;
        while !inner.is_empty() {
            if !first {
                try!(f.write_str("::"));
            } else {
                first = false;
            }
            let mut rest = inner;
            while rest.chars().next().unwrap().is_digit(10) {
                rest = &rest[1..];
            }
            let i: usize = inner[..(inner.len() - rest.len())].parse().unwrap();
            inner = &rest[i..];
            rest = &rest[..i];
            if rest.starts_with("_$") {
                rest = &rest[1..];
            }
            while !rest.is_empty() {
                if rest.starts_with('.') {
                    if let Some('.') = rest[1..].chars().next() {
                        try!(f.write_str("::"));
                        rest = &rest[2..];
                    } else {
                        try!(f.write_str("."));
                        rest = &rest[1..];
                    }
                } else if rest.starts_with('$') {
                    macro_rules! demangle {
                        ($($pat:expr => $demangled:expr),*) => ({
                            $(if rest.starts_with($pat) {
                                try!(f.write_str($demangled));
                                rest = &rest[$pat.len()..];
                              } else)*
                            {
                                try!(f.write_str(rest));
                                break;
                            }

                        })
                    }

                    // see src/librustc/back/link.rs for these mappings
                    demangle! {
                        "$SP$" => "@",
                        "$BP$" => "*",
                        "$RF$" => "&",
                        "$LT$" => "<",
                        "$GT$" => ">",
                        "$LP$" => "(",
                        "$RP$" => ")",
                        "$C$" => ",",

                        // in theory we can demangle any Unicode code point, but
                        // for simplicity we just catch the common ones.
                        "$u7e$" => "~",
                        "$u20$" => " ",
                        "$u27$" => "'",
                        "$u5b$" => "[",
                        "$u5d$" => "]",
                        "$u7b$" => "{",
                        "$u7d$" => "}",
                        "$u3b$" => ";",
                        "$u2b$" => "+",
                        "$u22$" => "\""
                    }
                } else {
                    let idx = match rest.char_indices().find(|&(_, c)| c == '$' || c == '.') {
                        None => rest.len(),
                        Some((i, _)) => i,
                    };
                    try!(f.write_str(&rest[..idx]));
                    rest = &rest[idx..];
                }
            }
        }

        Ok(())
    }
}

impl<'a> fmt::Debug for Demangle<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

#[cfg(test)]
mod tests {
    use std::prelude::v1::*;

    macro_rules! t {
        ($a:expr, $b:expr) => ({
            assert_eq!(super::demangle($a).to_string(), $b);
        })
    }

    #[test]
    fn demangle() {
        t!("test", "test");
        t!("_ZN4testE", "test");
        t!("_ZN4test", "_ZN4test");
        t!("_ZN4test1a2bcE", "test::a::bc");
    }

    #[test]
    fn demangle_dollars() {
        t!("_ZN4$RP$E", ")");
        t!("_ZN8$RF$testE", "&test");
        t!("_ZN8$BP$test4foobE", "*test::foob");
        t!("_ZN9$u20$test4foobE", " test::foob");
        t!("_ZN35Bar$LT$$u5b$u32$u3b$$u20$4$u5d$$GT$E", "Bar<[u32; 4]>");
    }

    #[test]
    fn demangle_many_dollars() {
        t!("_ZN13test$u20$test4foobE", "test test::foob");
        t!("_ZN12test$BP$test4foobE", "test*test::foob");
    }

    #[test]
    fn demangle_windows() {
        t!("ZN4testE", "test");
        t!("ZN13test$u20$test4foobE", "test test::foob");
        t!("ZN12test$RF$test4foobE", "test&test::foob");
    }

    #[test]
    fn demangle_elements_beginning_with_underscore() {
        t!("_ZN13_$LT$test$GT$E", "<test>");
        t!("_ZN28_$u7b$$u7b$closure$u7d$$u7d$E", "{{closure}}");
        t!("_ZN15__STATIC_FMTSTRE", "__STATIC_FMTSTR");
    }

    #[test]
    fn demangle_trait_impls() {
        t!("_ZN71_$LT$Test$u20$$u2b$$u20$$u27$static$u20$as$u20$foo..Bar$LT$Test$GT$$GT$3barE",
           "<Test + 'static as foo::Bar<Test>>::bar");
    }
}
<|endoftext|>