<commit_before>use chrono::*;
use http_headers::*;
use hyper::header::Headers;
use openssl::hash::{MessageDigest, hash};
use openssl::rsa::Rsa;
use openssl::rsa::PKCS1_PADDING;
use rustc_serialize::base64::ToBase64;
use std::fmt;
use std::fs::File;
use std::io::Read;
use utils::{squeeze_path, expand_string};
use authentication::{BASE64_AUTH, Authenticator};
use errors::*;
use std::ascii::AsciiExt;

#[derive(Clone)]
pub struct Auth11 {
    api_version: String,
    body: Option<String>,
    date: String,
    pub headers: Headers,
    keypath: String,
    method: String,
    path: String,
    userid: String,
    version: String,
}

impl fmt::Debug for Auth11 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Auth11")
            .field("method", &self.method)
            .field("userid", &self.userid)
            .field("path", &self.path)
            .field("body", &self.body)
            .field("keypath", &self.keypath)
            .finish()
    }
}

impl Auth11 {
    pub fn new(path: &str,
               key: &str,
               method: &str,
               userid: &str,
               api_version: &str,
               body: Option<String>)
        -> impl Authenticator {
            let dt = UTC::now().format("%Y-%m-%dT%H:%M:%SZ").to_string();

            let userid: String = userid.into();
            let method = String::from(method).to_ascii_uppercase();

            let mut headers = Headers::new();
            headers.set(OpsSign(String::from("algorithm=sha1;version=1.1")));
            headers.set(OpsTimestamp(dt.clone()));
            headers.set(OpsUserId(userid.clone()));

            Auth11 {
                api_version: api_version.into(),
                body: body,
                date: dt,
                headers: headers,
                keypath: key.into(),
                method: method.into(),
                path: squeeze_path(path.into()),
                userid: userid,
                version: String::from("1.1"),
            }
        }

    fn hashed_path(&self) -> Result<String> {
        debug!("Path is: {:?}", &self.path);
        let hash = hash(MessageDigest::sha1(), &self.path.as_bytes())?.to_base64(BASE64_AUTH);
        Ok(hash)
    }

    fn content_hash(&self) -> Result<String> {
        let body = expand_string(&self.body);
        let content = hash(MessageDigest::sha1(), body.as_bytes())?.to_base64(BASE64_AUTH);
        debug!("{:?}", content);
        Ok(content)
    }

    fn set_content_hash(mut self) -> Result<Auth11> {
        let hsh = try!(self.content_hash());
        self.headers.set(OpsContentHash(hsh));
        Ok(self)
    }

    fn canonical_user_id(&self) -> Result<String> {
        hash(MessageDigest::sha1(), &self.userid.as_bytes())
            .and_then(|res| Ok(res.to_base64(BASE64_AUTH)))
            .map_err(|res| res.into())
    }

    fn canonical_request(&self) -> Result<String> {
        let cr = format!("Method:{}\nHashed Path:{}\n\
                          X-Ops-Content-Hash:{}\n\
                          X-Ops-Timestamp:{}\nX-Ops-UserId:{}",
                          &self.method,
                          try!(self.hashed_path()),
                          try!(self.content_hash()),
                          self.date,
                          try!(self.canonical_user_id()));
        debug!("Canonical Request is: {:?}", cr);
        Ok(cr)
    }

    fn encrypted_request(&self) -> Result<String> {
        let mut key: Vec<u8> = vec![];
        match File::open(&self.keypath) {
            Ok(mut fh) => {
                try!(fh.read_to_end(&mut key));
                let key = try!(Rsa::private_key_from_pem(key.as_slice()));

                let cr = try!(self.canonical_request());
                let cr = cr.as_bytes();

                let mut hash: Vec<u8> = vec![0; key.size()];
                try!(key.private_encrypt(cr, &mut hash, PKCS1_PADDING));
                Ok(hash.to_base64(BASE64_AUTH))
            }
            Err(_) => Err(ErrorKind::PrivateKeyError(self.keypath.clone()).into()),
        }
    }
}

impl Authenticator for Auth11 {
    fn headers(self) -> Result<Headers> {
        let fin = try!(self.set_content_hash());
        let enc = try!(fin.encrypted_request());
        let mut headers = fin.headers;
        let mut i = 1;
        for h in enc.split('\n') {
            let key = format!("X-Ops-Authorization-{}", i);
            headers.set_raw(key, vec![h.as_bytes().to_vec()]);
            i += 1;
        }
        Ok(headers)
    }
}

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

    use authentication::Authenticator;
    use http_headers::*;
    use hyper::header::Headers;

    const PATH: &'static str = "/organizations/clownco";
    const BODY: &'static str = "Spec Body";
    const USER: &'static str = "spec-user";
    const DT: &'static str = "2009-01-01T12:00:00Z";

    const PRIVATE_KEY: &'static str = "fixtures/spec-user.pem";

    #[test]
    fn test_userid() {
        let auth = Auth11::new(PATH, PRIVATE_KEY, "GET", USER, "0", None);
        assert_eq!(auth.headers().unwrap().get::<OpsUserId>().unwrap().to_string(), "spec-user")
    }

    #[test]
    fn test_canonical_user_id() {
        let auth = Auth11 {
            api_version: String::from("1"),
            body: Some(String::from(BODY)),
            date: String::from(DT),
            headers: Headers::new(),
            keypath: String::from(PRIVATE_KEY),
            method: String::from("POST"),
            path: String::from(PATH),
            userid: String::from(USER),
            version: String::from("1.1"),
        };
        assert_eq!(auth.canonical_user_id().unwrap(), "EAF7Wv/hbAudWV5ZkwKz40Z/lO0=")
    }

    #[test]
    fn test_canonical_request() {
        let auth = Auth11 {
            api_version: String::from("1"),
            body: Some(String::from(BODY)),
            date: String::from(DT),
            headers: Headers::new(),
            keypath: String::from(""),
            method: String::from("POST"),
            path: String::from(PATH),
            userid: String::from(USER),
            version: String::from("1.1"),
        };
        assert_eq!(auth.canonical_request().unwrap(),
        "Method:POST\nHashed \
        Path:YtBWDn1blGGuFIuKksdwXzHU9oE=\nX-Ops-Content-Hash:\
                    DFteJZPVv6WKdQmMqZUQUumUyRs=\nX-Ops-Timestamp:2009-01-01T12:00:\
                    00Z\nX-Ops-UserId:EAF7Wv/hbAudWV5ZkwKz40Z/lO0=")
    }

    #[test]
    fn test_private_key() {
        let auth = Auth11 {
            api_version: String::from("1"),
            body: Some(String::from(BODY)),
            date: String::from(DT),
            headers: Headers::new(),
            keypath: String::from(PRIVATE_KEY),
            method: String::from("POST"),
            path: String::from(PATH),
            userid: String::from(USER),
            version: String::from("1.1"),
        };
        assert_eq!(&auth.encrypted_request().unwrap(),
        "UfZD9dRz6rFu6LbP5Mo1oNHcWYxpNIcUfFCffJS1FQa0GtfU/vkt3/O5HuCM\n1wIFl/U0f5faH9EW\
        pXWY5NwKR031Myxcabw4t4ZLO69CIh/3qx1XnjcZvt2w\nc2R9bx/43IWA/r8w8Q6decuu0f6ZlNhe\
                    JeJhaYPI8piX/aH+uHBH8zTACZu8\nvMnl5MF3/OIlsZc8cemq6eKYstp8a8KYq9OmkB5IXIX6qVMJ\
                    HA6fRvQEB/7j\n281Q7oI/O+lE8AmVyBbwruPb7Mp6s4839eYiOdjbDwFjYtbS3XgAjrHlaD7W\nFD\
                    lbAG7H8Dmvo+wBxmtNkszhzbBnEYtuwQqT8nM/8A==")
    }

    #[test]
    fn test_headers() {
        let auth = Auth11::new(PATH,
                               PRIVATE_KEY,
                               "GET",
                               USER,
                               "0",
                               None);
        let headers = auth.headers().unwrap();

        assert!(headers.get_raw("x-ops-authorization-1").is_some())
    }
}
<commit_msg>rustfmt<commit_after>use chrono::*;
use http_headers::*;
use hyper::header::Headers;
use openssl::hash::{MessageDigest, hash};
use openssl::rsa::Rsa;
use openssl::rsa::PKCS1_PADDING;
use rustc_serialize::base64::ToBase64;
use std::fmt;
use std::fs::File;
use std::io::Read;
use utils::{squeeze_path, expand_string};
use authentication::{BASE64_AUTH, Authenticator};
use errors::*;
use std::ascii::AsciiExt;

#[derive(Clone)]
pub struct Auth11 {
    api_version: String,
    body: Option<String>,
    date: String,
    pub headers: Headers,
    keypath: String,
    method: String,
    path: String,
    userid: String,
    version: String,
}

impl fmt::Debug for Auth11 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Auth11")
            .field("method", &self.method)
            .field("userid", &self.userid)
            .field("path", &self.path)
            .field("body", &self.body)
            .field("keypath", &self.keypath)
            .finish()
    }
}

impl Auth11 {
    pub fn new(path: &str,
               key: &str,
               method: &str,
               userid: &str,
               api_version: &str,
               body: Option<String>)
               -> impl Authenticator {
        let dt = UTC::now().format("%Y-%m-%dT%H:%M:%SZ").to_string();

        let userid: String = userid.into();
        let method = String::from(method).to_ascii_uppercase();

        let mut headers = Headers::new();
        headers.set(OpsSign(String::from("algorithm=sha1;version=1.1")));
        headers.set(OpsTimestamp(dt.clone()));
        headers.set(OpsUserId(userid.clone()));

        Auth11 {
            api_version: api_version.into(),
            body: body,
            date: dt,
            headers: headers,
            keypath: key.into(),
            method: method.into(),
            path: squeeze_path(path.into()),
            userid: userid,
            version: String::from("1.1"),
        }
    }

    fn hashed_path(&self) -> Result<String> {
        debug!("Path is: {:?}", &self.path);
        let hash = hash(MessageDigest::sha1(), &self.path.as_bytes())?.to_base64(BASE64_AUTH);
        Ok(hash)
    }

    fn content_hash(&self) -> Result<String> {
        let body = expand_string(&self.body);
        let content = hash(MessageDigest::sha1(), body.as_bytes())?.to_base64(BASE64_AUTH);
        debug!("{:?}", content);
        Ok(content)
    }

    fn set_content_hash(mut self) -> Result<Auth11> {
        let hsh = try!(self.content_hash());
        self.headers.set(OpsContentHash(hsh));
        Ok(self)
    }

    fn canonical_user_id(&self) -> Result<String> {
        hash(MessageDigest::sha1(), &self.userid.as_bytes())
            .and_then(|res| Ok(res.to_base64(BASE64_AUTH)))
            .map_err(|res| res.into())
    }

    fn canonical_request(&self) -> Result<String> {
        let cr = format!("Method:{}\nHashed Path:{}\n\
                          X-Ops-Content-Hash:{}\n\
                          X-Ops-Timestamp:{}\nX-Ops-UserId:{}",
                         &self.method,
                         try!(self.hashed_path()),
                         try!(self.content_hash()),
                         self.date,
                         try!(self.canonical_user_id()));
        debug!("Canonical Request is: {:?}", cr);
        Ok(cr)
    }

    fn encrypted_request(&self) -> Result<String> {
        let mut key: Vec<u8> = vec![];
        match File::open(&self.keypath) {
            Ok(mut fh) => {
                try!(fh.read_to_end(&mut key));
                let key = try!(Rsa::private_key_from_pem(key.as_slice()));

                let cr = try!(self.canonical_request());
                let cr = cr.as_bytes();

                let mut hash: Vec<u8> = vec![0; key.size()];
                try!(key.private_encrypt(cr, &mut hash, PKCS1_PADDING));
                Ok(hash.to_base64(BASE64_AUTH))
            }
            Err(_) => Err(ErrorKind::PrivateKeyError(self.keypath.clone()).into()),
        }
    }
}

impl Authenticator for Auth11 {
    fn headers(self) -> Result<Headers> {
        let fin = try!(self.set_content_hash());
        let enc = try!(fin.encrypted_request());
        let mut headers = fin.headers;
        let mut i = 1;
        for h in enc.split('\n') {
            let key = format!("X-Ops-Authorization-{}", i);
            headers.set_raw(key, vec![h.as_bytes().to_vec()]);
            i += 1;
        }
        Ok(headers)
    }
}

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

    use authentication::Authenticator;
    use http_headers::*;
    use hyper::header::Headers;

    const PATH: &'static str = "/organizations/clownco";
    const BODY: &'static str = "Spec Body";
    const USER: &'static str = "spec-user";
    const DT: &'static str = "2009-01-01T12:00:00Z";

    const PRIVATE_KEY: &'static str = "fixtures/spec-user.pem";

    #[test]
    fn test_userid() {
        let auth = Auth11::new(PATH, PRIVATE_KEY, "GET", USER, "0", None);
        assert_eq!(auth.headers().unwrap().get::<OpsUserId>().unwrap().to_string(),
                   "spec-user")
    }

    #[test]
    fn test_canonical_user_id() {
        let auth = Auth11 {
            api_version: String::from("1"),
            body: Some(String::from(BODY)),
            date: String::from(DT),
            headers: Headers::new(),
            keypath: String::from(PRIVATE_KEY),
            method: String::from("POST"),
            path: String::from(PATH),
            userid: String::from(USER),
            version: String::from("1.1"),
        };
        assert_eq!(auth.canonical_user_id().unwrap(),
                   "EAF7Wv/hbAudWV5ZkwKz40Z/lO0=")
    }

    #[test]
    fn test_canonical_request() {
        let auth = Auth11 {
            api_version: String::from("1"),
            body: Some(String::from(BODY)),
            date: String::from(DT),
            headers: Headers::new(),
            keypath: String::from(""),
            method: String::from("POST"),
            path: String::from(PATH),
            userid: String::from(USER),
            version: String::from("1.1"),
        };
        assert_eq!(auth.canonical_request().unwrap(),
                   "Method:POST\nHashed \
                    Path:YtBWDn1blGGuFIuKksdwXzHU9oE=\nX-Ops-Content-Hash:\
                    DFteJZPVv6WKdQmMqZUQUumUyRs=\nX-Ops-Timestamp:2009-01-01T12:00:\
                    00Z\nX-Ops-UserId:EAF7Wv/hbAudWV5ZkwKz40Z/lO0=")
    }

    #[test]
    fn test_private_key() {
        let auth = Auth11 {
            api_version: String::from("1"),
            body: Some(String::from(BODY)),
            date: String::from(DT),
            headers: Headers::new(),
            keypath: String::from(PRIVATE_KEY),
            method: String::from("POST"),
            path: String::from(PATH),
            userid: String::from(USER),
            version: String::from("1.1"),
        };
        assert_eq!(&auth.encrypted_request().unwrap(),
                   "UfZD9dRz6rFu6LbP5Mo1oNHcWYxpNIcUfFCffJS1FQa0GtfU/vkt3/O5HuCM\n\
                   1wIFl/U0f5faH9EWpXWY5NwKR031Myxcabw4t4ZLO69CIh/3qx1XnjcZvt2w\n\
                   c2R9bx/43IWA/r8w8Q6decuu0f6ZlNheJeJhaYPI8piX/aH+uHBH8zTACZu8\n\
                   vMnl5MF3/OIlsZc8cemq6eKYstp8a8KYq9OmkB5IXIX6qVMJHA6fRvQEB/7j\n\
                   281Q7oI/O+lE8AmVyBbwruPb7Mp6s4839eYiOdjbDwFjYtbS3XgAjrHlaD7W\n\
                   FDlbAG7H8Dmvo+wBxmtNkszhzbBnEYtuwQqT8nM/8A==")
    }

    #[test]
    fn test_headers() {
        let auth = Auth11::new(PATH, PRIVATE_KEY, "GET", USER, "0", None);
        let headers = auth.headers().unwrap();

        assert!(headers.get_raw("x-ops-authorization-1").is_some())
    }
}
<|endoftext|>


<commit_before>//! Error types that can be emitted from this library

use std::io;

use thiserror::Error;

/// Generic result type with ZipError as its error variant
pub type ZipResult<T> = Result<T, ZipError>;

/// Error type for Zip
#[derive(Debug, Error)]
pub enum ZipError {
    /// An Error caused by I/O
    #[error(transparent)]
    Io(#[from] io::Error),

    /// This file is probably not a zip archive
    #[error("invalid Zip archive")]
    InvalidArchive(&'static str),

    /// This archive is not supported
    #[error("unsupported Zip archive")]
    UnsupportedArchive(&'static str),

    /// The requested file could not be found in the archive
    #[error("specified file not found in archive")]
    FileNotFound,
}<commit_msg>Run cargo fmt<commit_after>//! Error types that can be emitted from this library

use std::io;

use thiserror::Error;

/// Generic result type with ZipError as its error variant
pub type ZipResult<T> = Result<T, ZipError>;

/// Error type for Zip
#[derive(Debug, Error)]
pub enum ZipError {
    /// An Error caused by I/O
    #[error(transparent)]
    Io(#[from] io::Error),

    /// This file is probably not a zip archive
    #[error("invalid Zip archive")]
    InvalidArchive(&'static str),

    /// This archive is not supported
    #[error("unsupported Zip archive")]
    UnsupportedArchive(&'static str),

    /// The requested file could not be found in the archive
    #[error("specified file not found in archive")]
    FileNotFound,
}
<|endoftext|>


<commit_before>use std::iter::Iterator;
use std::collections::HashSet;
use std::hash::Hash;

struct Visited<T> {
    hash_set: HashSet<T>
}

impl<T> Visited<T> where T: Hash + Clone + Eq {
    fn new() -> Visited<T> {
        Visited {
            hash_set: HashSet::new()
        }
    }

    fn insert(&mut self, value: &T) -> bool {
        self.hash_set.insert(value.clone())
    }
}

pub trait SearchGoal<T> {
    fn is_goal(&self, state: &T) -> bool;
}

impl<T> SearchGoal<T> for T where T: PartialEq {
    fn is_goal(&self, state: &T) -> bool {
        *self == *state
    }
}

pub trait SearchSpace {
    type State: Hash + Clone + Eq;
    type Action: Clone;
    type Iterator: Iterator<Item=(Self::Action, Self::State)>;

    fn expand(&self, state: &Self::State) -> Self::Iterator;

    fn dfs<G>(&self, start: Self::State, goal: G) -> Option<Vec<Self::Action>>
    where G: SearchGoal<Self::State> {
        if goal.is_goal(&start) {
            return Some(vec![]);
        }

        let mut visited = Visited::new();
        let mut stack: Vec<(Self::Iterator, Option<Self::Action>)> = vec![];
        stack.push((self.expand(&start), None));

        loop {
            let next = match stack.last_mut() {
                None => return None,
                Some(&mut (ref mut iter, _)) => iter.next()
            };
            if let Some((action, state)) = next {
                if !visited.insert(&state) {
                    continue;
                }
                if goal.is_goal(&state) {
                    return Some(
                        stack.iter()
                             .map(|&(_, ref a)| a)
                             .cloned()
                             .filter_map(|x| x)
                             .chain(Some(action).into_iter())
                             .collect()
                    )
                }
                stack.push((self.expand(&state), Some(action)));
            } else {
                stack.pop();
            }
        }
    }
}

#[cfg(test)]
pub mod tests {
    use std::vec::IntoIter;
    use super::SearchSpace;

    #[test]
    pub fn test_dfs() {
        struct TestSearch;

        #[derive(Debug, PartialEq, Clone)]
        enum Dir { Left, Right }

        impl SearchSpace for TestSearch {
            type State = i32;
            type Action = Dir;
            type Iterator = IntoIter<(Self::Action, Self::State)>;

            fn expand(&self, state: &Self::State) -> Self::Iterator {
                if *state == 0 {
                    vec![(Dir::Left, 1), (Dir::Right, 2)].into_iter()
                } else if *state == 1 {
                    vec![(Dir::Left, 3), (Dir::Right, 4)].into_iter()
                } else if *state == 2 {
                    vec![(Dir::Left, 2)].into_iter()
                } else {
                    vec![].into_iter()
                }
            }
        }

        let ts = TestSearch;

        assert_eq!(ts.dfs(0, 0).unwrap(), vec![]);
        assert_eq!(ts.dfs(0, 1).unwrap(), vec![Dir::Left]);
        assert_eq!(ts.dfs(0, 2).unwrap(), vec![Dir::Right]);
        assert_eq!(ts.dfs(0, 3).unwrap(), vec![Dir::Left, Dir::Left]);
        assert_eq!(ts.dfs(0, 4).unwrap(), vec![Dir::Left, Dir::Right]);
        assert_eq!(ts.dfs(2, 2).unwrap(), vec![]);
        assert!(ts.dfs(2, 0).is_none());
        assert!(ts.dfs(5, 0).is_none());
    }
}
<commit_msg>Simplify stack initialization<commit_after>use std::iter::Iterator;
use std::collections::HashSet;
use std::hash::Hash;

struct Visited<T> {
    hash_set: HashSet<T>
}

impl<T> Visited<T> where T: Hash + Clone + Eq {
    fn new() -> Visited<T> {
        Visited {
            hash_set: HashSet::new()
        }
    }

    fn insert(&mut self, value: &T) -> bool {
        self.hash_set.insert(value.clone())
    }
}

pub trait SearchGoal<T> {
    fn is_goal(&self, state: &T) -> bool;
}

impl<T> SearchGoal<T> for T where T: PartialEq {
    fn is_goal(&self, state: &T) -> bool {
        *self == *state
    }
}

pub trait SearchSpace {
    type State: Hash + Clone + Eq;
    type Action: Clone;
    type Iterator: Iterator<Item=(Self::Action, Self::State)>;

    fn expand(&self, state: &Self::State) -> Self::Iterator;

    fn dfs<G>(&self, start: Self::State, goal: G) -> Option<Vec<Self::Action>>
    where G: SearchGoal<Self::State> {
        if goal.is_goal(&start) {
            return Some(vec![]);
        }

        let mut visited = Visited::new();
        let mut stack = vec![(self.expand(&start), None)];

        loop {
            let next = match stack.last_mut() {
                None => return None,
                Some(&mut (ref mut iter, _)) => iter.next()
            };
            if let Some((action, state)) = next {
                if !visited.insert(&state) {
                    continue;
                }
                if goal.is_goal(&state) {
                    return Some(
                        stack.iter()
                             .map(|&(_, ref a)| a)
                             .cloned()
                             .filter_map(|x| x)
                             .chain(Some(action).into_iter())
                             .collect()
                    )
                }
                stack.push((self.expand(&state), Some(action)));
            } else {
                stack.pop();
            }
        }
    }
}

#[cfg(test)]
pub mod tests {
    use std::vec::IntoIter;
    use super::SearchSpace;

    #[test]
    pub fn test_dfs() {
        struct TestSearch;

        #[derive(Debug, PartialEq, Clone)]
        enum Dir { Left, Right }

        impl SearchSpace for TestSearch {
            type State = i32;
            type Action = Dir;
            type Iterator = IntoIter<(Self::Action, Self::State)>;

            fn expand(&self, state: &Self::State) -> Self::Iterator {
                if *state == 0 {
                    vec![(Dir::Left, 1), (Dir::Right, 2)].into_iter()
                } else if *state == 1 {
                    vec![(Dir::Left, 3), (Dir::Right, 4)].into_iter()
                } else if *state == 2 {
                    vec![(Dir::Left, 2)].into_iter()
                } else {
                    vec![].into_iter()
                }
            }
        }

        let ts = TestSearch;

        assert_eq!(ts.dfs(0, 0).unwrap(), vec![]);
        assert_eq!(ts.dfs(0, 1).unwrap(), vec![Dir::Left]);
        assert_eq!(ts.dfs(0, 2).unwrap(), vec![Dir::Right]);
        assert_eq!(ts.dfs(0, 3).unwrap(), vec![Dir::Left, Dir::Left]);
        assert_eq!(ts.dfs(0, 4).unwrap(), vec![Dir::Left, Dir::Right]);
        assert_eq!(ts.dfs(2, 2).unwrap(), vec![]);
        assert!(ts.dfs(2, 0).is_none());
        assert!(ts.dfs(5, 0).is_none());
    }
}
<|endoftext|>


<commit_before>use caseless::Caseless;
use std::borrow::Borrow;
use std::collections::{Bound, BTreeMap};
use unicode_normalization::UnicodeNormalization;
use unicode_segmentation::UnicodeSegmentation;

#[derive(Debug)]
pub struct SearchIndex<K> {
    index: BTreeMap<String, BTreeMap<K, u64>>,
}

impl<K: Clone + Ord> SearchIndex<K> {
    pub fn new() -> Self {
        SearchIndex {
            index: BTreeMap::new(),
        }
    }

    pub fn add(&mut self, key: K, text: &str, weight: u64) {
        for word in text.unicode_words().map(nfkd_case_fold) {
            self.add_word(key.clone(), word, weight);
        }
    }

    fn add_word(&mut self, key: K, word: String, weight: u64) {
        let count = self.index
            .entry(word).or_insert_with(BTreeMap::new)
            .entry(key).or_insert(0);
        *count += weight;
    }

    #[allow(dead_code)]  // ... for now!
    pub fn remove<Q: ?Sized>(&mut self, key: &Q, text: &str, weight: u64) where
        K: Borrow<Q>, Q: Ord
    {
        for word in text.unicode_words().map(nfkd_case_fold) {
            self.remove_word(key, &word, weight);
        }
    }

    fn remove_word<Q: ?Sized>(&mut self, key: &Q, word: &str, weight: u64) where
        K: Borrow<Q>, Q: Ord
    {
        let mut zero = false;
        if let Some(count) = self.index.get_mut(word).and_then(|m| m.get_mut(key)) {
            *count -= weight;
            zero = *count == 0;
        }
        if zero {
            self.index.get_mut(word).unwrap().remove(key);
        }
    }

    pub fn query(&self, text: &str) -> Vec<(K, u64)> where K: ::std::fmt::Debug {
        // Split text into words
        let mut results = text.unicode_words().map(nfkd_case_fold)
            // Look up each word
            .map(|word| {
                // Match words by prefix so that e.g. "quie" matches "QuietMisdreavus"
                let mut result = BTreeMap::new();
                for (key, count) in
                    self.index.range(Bound::Included(&word), Bound::Unbounded::<&str>)
                        .take_while(|&(key, _)| key.starts_with(&word))
                        .flat_map(|(_, result)| result)
                {
                    *result.entry(key.clone()).or_insert(0) += *count;
                }
                result
            })
            // Intersect the results for each word
            .fold(None, |uberresult, result| {
                if let Some(mut uberresult) = uberresult {
                    for entry in &mut uberresult {
                        let (uberkey, ubercount): (&K, &mut u64) = entry;
                        *ubercount *= *result.get(uberkey).unwrap_or(&0);
                    }
                    Some(uberresult)
                } else {
                    Some(result)
                }
            })
            .unwrap_or_else(|| BTreeMap::new())
            .into_iter()
            // Delete the users for which at least one word doesn't appear
            .filter(|&(_, count)| count > 0)
            .collect::<Vec<_>>();
        // Sort by decreasing matchiness
        results.sort_by(|&(_, count1), &(_, count2)| count2.cmp(&count1));
        results
    }
}

fn nfkd_case_fold(text: &str) -> String {
    text.nfd().default_case_fold().nfkd().default_case_fold().nfkd().collect()
}
<commit_msg>Nuke methods for removing an entry from the index<commit_after>use caseless::Caseless;
use std::borrow::Borrow;
use std::collections::{Bound, BTreeMap};
use unicode_normalization::UnicodeNormalization;
use unicode_segmentation::UnicodeSegmentation;

#[derive(Debug)]
pub struct SearchIndex<K> {
    index: BTreeMap<String, BTreeMap<K, u64>>,
}

impl<K: Clone + Ord> SearchIndex<K> {
    pub fn new() -> Self {
        SearchIndex {
            index: BTreeMap::new(),
        }
    }

    pub fn add(&mut self, key: K, text: &str, weight: u64) {
        for word in text.unicode_words().map(nfkd_case_fold) {
            self.add_word(key.clone(), word, weight);
        }
    }

    fn add_word(&mut self, key: K, word: String, weight: u64) {
        let count = self.index
            .entry(word).or_insert_with(BTreeMap::new)
            .entry(key).or_insert(0);
        *count += weight;
    }

    pub fn query(&self, text: &str) -> Vec<(K, u64)> where K: ::std::fmt::Debug {
        // Split text into words
        let mut results = text.unicode_words().map(nfkd_case_fold)
            // Look up each word
            .map(|word| {
                // Match words by prefix so that e.g. "quie" matches "QuietMisdreavus"
                let mut result = BTreeMap::new();
                for (key, count) in
                    self.index.range(Bound::Included(&word), Bound::Unbounded::<&str>)
                        .take_while(|&(key, _)| key.starts_with(&word))
                        .flat_map(|(_, result)| result)
                {
                    *result.entry(key.clone()).or_insert(0) += *count;
                }
                result
            })
            // Intersect the results for each word
            .fold(None, |uberresult, result| {
                if let Some(mut uberresult) = uberresult {
                    for entry in &mut uberresult {
                        let (uberkey, ubercount): (&K, &mut u64) = entry;
                        *ubercount *= *result.get(uberkey).unwrap_or(&0);
                    }
                    Some(uberresult)
                } else {
                    Some(result)
                }
            })
            .unwrap_or_else(|| BTreeMap::new())
            .into_iter()
            // Delete the users for which at least one word doesn't appear
            .filter(|&(_, count)| count > 0)
            .collect::<Vec<_>>();
        // Sort by decreasing matchiness
        results.sort_by(|&(_, count1), &(_, count2)| count2.cmp(&count1));
        results
    }
}

fn nfkd_case_fold(text: &str) -> String {
    text.nfd().default_case_fold().nfkd().default_case_fold().nfkd().collect()
}
<|endoftext|>


<commit_before>use std::net::IpAddr;
use std::sync::{Arc, RwLock};
use std::collections::HashMap;
use hyper::server::{Request, Response, Handler};
use hyper::server::Server as HyperServer;

use middleware::MiddlewareStack;
use request;
use response;

pub struct Server {
    middleware_stack: MiddlewareStack,
    templates: response::TemplateCache
}

impl Handler for Arc<Server> {
    fn handle<'a>(&'a self, req: Request<'a>, res: Response<'a>) {
        let nickel_req = request::Request::from_internal(req);
        let nickel_res = response::Response::from_internal(res, &self.templates);

        self.middleware_stack.invoke(nickel_req, nickel_res);
    }
}

impl Server {
    pub fn new(middleware_stack: MiddlewareStack) -> Server {
        Server {
            middleware_stack: middleware_stack,
            templates: RwLock::new(HashMap::new())
        }
    }

    // why do we need this? Is the http::Server.serve_forever method protected in C# terms?
    pub fn serve(self, ip: IpAddr, port: u16) {
        let arc = Arc::new(self);
        let server = HyperServer::http(arc);
        let _ = server.listen(ip, port);
    }
}

<commit_msg>chore(doc): remove dead comment<commit_after>use std::net::IpAddr;
use std::sync::{Arc, RwLock};
use std::collections::HashMap;
use hyper::server::{Request, Response, Handler};
use hyper::server::Server as HyperServer;

use middleware::MiddlewareStack;
use request;
use response;

pub struct Server {
    middleware_stack: MiddlewareStack,
    templates: response::TemplateCache
}

impl Handler for Arc<Server> {
    fn handle<'a>(&'a self, req: Request<'a>, res: Response<'a>) {
        let nickel_req = request::Request::from_internal(req);
        let nickel_res = response::Response::from_internal(res, &self.templates);

        self.middleware_stack.invoke(nickel_req, nickel_res);
    }
}

impl Server {
    pub fn new(middleware_stack: MiddlewareStack) -> Server {
        Server {
            middleware_stack: middleware_stack,
            templates: RwLock::new(HashMap::new())
        }
    }

    pub fn serve(self, ip: IpAddr, port: u16) {
        let arc = Arc::new(self);
        let server = HyperServer::http(arc);
        let _ = server.listen(ip, port);
    }
}

<|endoftext|>


<commit_before>#![allow(unused_imports)]
#![forbid(unsafe_code)]

mod credentials;
pub use credentials::*;
pub mod error;
<commit_msg>Reexport time<commit_after>#![allow(unused_imports)]
#![forbid(unsafe_code)]

mod credentials;
pub use credentials::*;
pub mod error;

// Reexport for e.g. users who need to build Credentials
pub use time;
<|endoftext|>


<commit_before>use handlebars::{Handlebars, TemplateError, TemplateFileError};
use std::error::Error;
use std::fmt;

#[derive(Debug)]
pub struct SourceError {
    pub cause: Box<Error>
}

impl fmt::Display for SourceError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::Display::fmt(&*self.cause, f)
    }
}

impl Error for SourceError {
    fn description(&self) -> &str {
        self.cause.description()
    }

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

impl From<TemplateError> for SourceError {
    fn from(err: TemplateError) -> SourceError {
        SourceError { cause: Box::new(err) }
    }
}

impl From<TemplateFileError> for SourceError {
    fn from(err: TemplateFileError) -> SourceError {
        SourceError { cause: Box::new(err) }
    }
}

pub trait Source {
    fn load(&self, reg: &mut Handlebars) -> Result<(), SourceError>;
}
<commit_msg>implement `Send` for `SourceError`<commit_after>use handlebars::{Handlebars, TemplateError, TemplateFileError};
use std::error::Error;
use std::fmt;

#[derive(Debug)]
pub struct SourceError {
    pub cause: Box<Error + Send>,
}

impl fmt::Display for SourceError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::Display::fmt(&*self.cause, f)
    }
}

impl Error for SourceError {
    fn description(&self) -> &str {
        self.cause.description()
    }

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

impl From<TemplateError> for SourceError {
    fn from(err: TemplateError) -> SourceError {
        SourceError { cause: Box::new(err) }
    }
}

impl From<TemplateFileError> for SourceError {
    fn from(err: TemplateFileError) -> SourceError {
        SourceError { cause: Box::new(err) }
    }
}

pub trait Source {
    fn load(&self, reg: &mut Handlebars) -> Result<(), SourceError>;
}
<|endoftext|>


<commit_before>use std::time::duration::Duration;
use std::str::FromStr;
use std::io::{standard_error, IoErrorKind};
use std::error::FromError;
use std::iter::FromIterator;
use rustc_serialize::{Encoder, Encodable};

use error::MpdResult;
use songs::MpdQueuePlace;
use client::MpdPair;
use utils::ForceEncodable;

#[derive(Show, Copy, RustcEncodable)]
pub struct AudioFormat {
    pub rate: u32,
    pub bits: u8,
    pub chans: u8
}

impl FromStr for AudioFormat {
    fn from_str(s: &str) -> Option<AudioFormat> {
        let mut it = s.split(':');
        if let (Some(rate), Some(bits), Some(chans)) = (
            it.next().and_then(|v| v.parse()),
            it.next().and_then(|v| v.parse()),
            it.next().and_then(|v| v.parse())) {
            Some(AudioFormat {
                rate: rate,
                bits: bits,
                chans: chans
            })
        } else {
            None
        }
    }
}

#[derive(Show, Copy, RustcEncodable)]
pub enum MpdState {
    Stop,
    Play,
    Pause,
}

impl FromStr for MpdState {
    fn from_str(s: &str) -> Option<MpdState> {
        match s {
            "stop" => Some(MpdState::Stop),
            "play" => Some(MpdState::Play),
            "pause" => Some(MpdState::Pause),
            _ => None
        }
    }
}

#[derive(Show, RustcEncodable)]
pub struct MpdStatus {
    volume: uint,
    repeat: bool,
    random: bool,
    single: bool,
    consume: bool,
    queue_version: uint,
    queue_len: uint,
    state: MpdState,
    song: Option<MpdQueuePlace>,
    nextsong: Option<MpdQueuePlace>,
    time: Option<Duration>,
    elapsed: Option<Duration>,
    duration: Option<Duration>,
    bitrate: Option<uint>,
    crossfade: Option<u64>,
    mixrampdb: f32,
    mixrampdelay: Option<u64>,
    audio: Option<AudioFormat>,
    updating_db: Option<uint>,
    error: Option<String>
}

impl FromIterator<MpdResult<MpdPair>> for MpdResult<MpdStatus> {
    fn from_iter<T: Iterator<MpdResult<MpdPair>>>(iterator: T) -> MpdResult<MpdStatus> {
        let mut status = MpdStatus {
            volume: 0,
            repeat: false,
            random: false,
            single: false,
            consume: false,
            queue_version: 0,
            queue_len: 0,
            state: MpdState::Stop,
            song: None,
            nextsong: None,
            time: None,
            elapsed: None,
            duration: None,
            bitrate: None,
            crossfade: None,
            mixrampdb: 0.0f32,
            mixrampdelay: None,
            audio: None,
            updating_db: None,
            error: None
        };

        let mut iter = iterator;
        let mut song_place = MpdQueuePlace { id: 0, pos: 0, prio: 0 };
        let mut next_song_place = MpdQueuePlace { id: 0, pos: 0, prio: 0 };

        for field in iter {
            let MpdPair(key, value) = try!(field);
            match key[] {
                "volume"         => status.volume = value.parse().unwrap_or(0),
                "repeat"         => status.repeat = value[] == "1",
                "random"         => status.random = value[] == "1",
                "single"         => status.single = value[] == "1",
                "consume"        => status.consume = value[] == "1",
                "playlist"       => status.queue_version = value.parse().unwrap_or(0),
                "playlistlength" => status.queue_len = value.parse().unwrap_or(0),
                "state"          => status.state = value.parse().unwrap_or(MpdState::Stop),
                "song"           => song_place.pos = value.parse().unwrap_or(0),
                "songid"         => song_place.id = value.parse().unwrap_or(0),
                "nextsong"       => next_song_place.pos = value.parse().unwrap_or(0),
                "nextsongid"     => next_song_place.id = value.parse().unwrap_or(0),
                "time"           => status.time = value.parse().map(Duration::seconds),
                "elapsed"        => status.elapsed = value.parse().map(Duration::seconds),
                "duration"       => status.duration = value.parse().map(Duration::seconds),
                "bitrate"        => status.bitrate = value.parse(),
                "xfade"          => status.crossfade = value.parse(),
                "mixrampdb"      => status.mixrampdb = value.parse().unwrap_or(0f32),
                "mixrampdelay"   => status.mixrampdelay = value.parse(),
                "audio"          => status.audio = value.parse(),
                "updating_db"    => status.updating_db = value.parse(),
                "error"          => status.error = Some(value),
                _ => return Err(FromError::from_error(standard_error(IoErrorKind::InvalidInput)))
            }
        }

        if song_place.id > 0 {
            status.song = Some(song_place);
        }
        if next_song_place.id > 0 {
            status.nextsong = Some(next_song_place);
        }

        Ok(status)
    }
}

<commit_msg>parse status time<commit_after>use std::time::duration::Duration;
use std::str::FromStr;
use std::io::{standard_error, IoErrorKind};
use std::error::FromError;
use std::iter::FromIterator;
use rustc_serialize::{Encoder, Encodable};

use error::MpdResult;
use songs::MpdQueuePlace;
use client::MpdPair;
use utils::ForceEncodable;

#[derive(Show, Copy, RustcEncodable)]
pub struct AudioFormat {
    pub rate: u32,
    pub bits: u8,
    pub chans: u8
}

impl FromStr for AudioFormat {
    fn from_str(s: &str) -> Option<AudioFormat> {
        let mut it = s.split(':');
        if let (Some(rate), Some(bits), Some(chans)) = (
            it.next().and_then(|v| v.parse()),
            it.next().and_then(|v| v.parse()),
            it.next().and_then(|v| v.parse())) {
            Some(AudioFormat {
                rate: rate,
                bits: bits,
                chans: chans
            })
        } else {
            None
        }
    }
}

#[derive(Show, Copy, RustcEncodable)]
pub enum MpdState {
    Stop,
    Play,
    Pause,
}

impl FromStr for MpdState {
    fn from_str(s: &str) -> Option<MpdState> {
        match s {
            "stop" => Some(MpdState::Stop),
            "play" => Some(MpdState::Play),
            "pause" => Some(MpdState::Pause),
            _ => None
        }
    }
}

#[derive(Show, RustcEncodable)]
pub struct MpdStatus {
    volume: uint,
    repeat: bool,
    random: bool,
    single: bool,
    consume: bool,
    queue_version: uint,
    queue_len: uint,
    state: MpdState,
    song: Option<MpdQueuePlace>,
    nextsong: Option<MpdQueuePlace>,
    play_time: Option<Duration>,
    total_time: Option<Duration>,
    elapsed: Option<Duration>,
    duration: Option<Duration>,
    bitrate: Option<uint>,
    crossfade: Option<u64>,
    mixrampdb: f32,
    mixrampdelay: Option<u64>,
    audio: Option<AudioFormat>,
    updating_db: Option<uint>,
    error: Option<String>
}

impl FromIterator<MpdResult<MpdPair>> for MpdResult<MpdStatus> {
    fn from_iter<T: Iterator<MpdResult<MpdPair>>>(iterator: T) -> MpdResult<MpdStatus> {
        let mut status = MpdStatus {
            volume: 0,
            repeat: false,
            random: false,
            single: false,
            consume: false,
            queue_version: 0,
            queue_len: 0,
            state: MpdState::Stop,
            song: None,
            nextsong: None,
            play_time: None,
            total_time: None,
            elapsed: None,
            duration: None,
            bitrate: None,
            crossfade: None,
            mixrampdb: 0.0f32,
            mixrampdelay: None,
            audio: None,
            updating_db: None,
            error: None
        };

        let mut iter = iterator;
        let mut song_place = MpdQueuePlace { id: 0, pos: 0, prio: 0 };
        let mut next_song_place = MpdQueuePlace { id: 0, pos: 0, prio: 0 };

        for field in iter {
            let MpdPair(key, value) = try!(field);
            match key[] {
                "volume"         => status.volume = value.parse().unwrap_or(0),
                "repeat"         => status.repeat = value[] == "1",
                "random"         => status.random = value[] == "1",
                "single"         => status.single = value[] == "1",
                "consume"        => status.consume = value[] == "1",
                "playlist"       => status.queue_version = value.parse().unwrap_or(0),
                "playlistlength" => status.queue_len = value.parse().unwrap_or(0),
                "state"          => status.state = value.parse().unwrap_or(MpdState::Stop),
                "song"           => song_place.pos = value.parse().unwrap_or(0),
                "songid"         => song_place.id = value.parse().unwrap_or(0),
                "nextsong"       => next_song_place.pos = value.parse().unwrap_or(0),
                "nextsongid"     => next_song_place.id = value.parse().unwrap_or(0),
                "time"           => {
                    let mut splits = value.splitn(2, ':').flat_map(|v| v.parse::<i64>().into_iter()).map(Duration::seconds);
                    status.play_time = splits.next();
                    status.total_time = splits.next();
                },
                "elapsed"        => status.elapsed = value.parse::<f32>().map(|v| Duration::milliseconds((v * 1000f32) as i64)),
                "duration"       => status.duration = value.parse().map(Duration::seconds),
                "bitrate"        => status.bitrate = value.parse(),
                "xfade"          => status.crossfade = value.parse(),
                "mixrampdb"      => status.mixrampdb = value.parse().unwrap_or(0f32),
                "mixrampdelay"   => status.mixrampdelay = value.parse(),
                "audio"          => status.audio = value.parse(),
                "updating_db"    => status.updating_db = value.parse(),
                "error"          => status.error = Some(value),
                _ => return Err(FromError::from_error(standard_error(IoErrorKind::InvalidInput)))
            }
        }

        if song_place.id > 0 {
            status.song = Some(song_place);
        }
        if next_song_place.id > 0 {
            status.nextsong = Some(next_song_place);
        }

        Ok(status)
    }
}

<|endoftext|>


<commit_before>// Copyright 2019, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ::ffi::{self, cairo_status_t};
use ::{Status, Surface, UserDataKey};

use libc::{c_void, c_double, c_uchar, c_uint};
use std::any::Any;
use std::cell::UnsafeCell;
use std::io;
use std::panic::AssertUnwindSafe;
use std::rc::Rc;

macro_rules! for_stream_constructors {
    ($constructor_ffi: ident) => {
        /// Takes full ownership of the output stream,
        /// which is not allowed to borrow any lifetime shorter than `'static`.
        ///
        /// Because the underlying `cairo_surface_t` is reference-counted,
        /// a lifetime parameter in a Rust wrapper type would not be enough to track
        /// how long it can keep writing to the stream.
        pub fn for_stream<W: io::Write + 'static>(width: f64, height: f64, stream: W) -> Self {
            Self {
                inner: Surface::_for_stream(
                    ffi::$constructor_ffi,
                    width,
                    height,
                    stream,
                ),
            }
        }

        /// Allows writing to a borrowed stream. The lifetime of the borrow is not tracked.
        ///
        /// # Safety
        ///
        /// The value that `stream` points to must live at least until the underlying `cairo_surface_t`
        /// (which maybe be longer then the Rust `PdfSurface` wrapper, because of reference-counting),
        /// or until the output stream is removed from the surface with [`Surface::take_output_stream`].
        ///
        /// Since the former is hard to track for sure, the latter is strongly recommended.
        /// The concrete type behind the `Box<dyn Any>` value returned by `take_output_stream`
        /// is private, so you won’t be able to downcast it.
        /// But removing it anyway ensures that later writes do no go through a dangling pointer.
        pub unsafe fn for_raw_stream<W: io::Write + 'static>(width: f64, height: f64, stream: *mut W) -> Self {
            Self {
                inner: Surface::_for_raw_stream(
                    ffi::$constructor_ffi,
                    width,
                    height,
                    stream,
                ),
            }
        }
    };
}

impl Surface {
    pub(crate) fn _for_stream<W: io::Write + 'static>(
        constructor: Constructor,
        width: f64,
        height: f64,
        stream: W,
    ) -> Self {
        let env_rc = Rc::new(UnsafeCell::new(CallbackEnvironment {
            stream: Some(Box::new(stream)),
            io_error: None,
            unwind_payload: None,
        }));
        let env: *const UnsafeCell<CallbackEnvironment> = &*env_rc;
        unsafe {
            let ptr = constructor(Some(write_callback::<W>), env as *mut c_void, width, height);
            let surface = Surface::from_raw_full(ptr);
            surface.set_user_data(&STREAM_CALLBACK_ENVIRONMENT, env_rc);
            surface
        }
    }

    pub(crate) unsafe fn _for_raw_stream<W: io::Write + 'static>(
        constructor: Constructor,
        width: f64,
        height: f64,
        stream: *mut W,
    ) -> Self {
        Self::_for_stream(constructor, width, height, RawStream(stream))
    }

    fn with_stream_env<R, F>(&self, f: F) -> Option<R>
        where F: FnOnce(&mut CallbackEnvironment) -> Option<R>
    {
        let env = self.get_user_data_ptr(&STREAM_CALLBACK_ENVIRONMENT)?;

        // Safety: contract of `get_user_data_ptr`
        let env = unsafe { env.as_ref() };

        with_mut_env(env, |env| {
            if let Some(payload) = env.unwind_payload.take() {
                std::panic::resume_unwind(payload)
            }
            f(env)
        })
    }

    /// Remove and return the output stream, if any.
    ///
    /// This is relevant for surfaces created for example with [`PdfSurface::for_stream`].
    /// Consider calling [`Surface::finish`] first,
    /// to ensure that all writes to the stream are done.
    ///
    /// Use [`Box::downcast`] to recover the concrete type.
    pub fn take_output_stream(&self) -> Option<Box<dyn Any>> {
        self.with_stream_env(|env| env.stream.take())
    }

    /// Remove and return the last error that occurred while writing to the output stream, if any.
    pub fn take_io_error(&self) -> Result<(), io::Error> {
        match self.with_stream_env(|env| env.io_error.take()) {
            Some(error) => Err(error),
            None => Ok(()),
        }
    }

    /// Return whether the surface has an associated output stream (that hasn’t been removed yet).
    pub fn has_output_stream(&self) -> bool {
        self.with_stream_env(|env| Some(env.stream.is_some())).unwrap_or(false)
    }

    /// Return whether an error that occurred while writing to the output stream, if any.
    pub fn has_io_error(&self) -> bool {
        self.with_stream_env(|env| Some(env.io_error.is_some())).unwrap_or(false)
    }
}

pub(crate) type Constructor = unsafe extern fn(
    ffi::cairo_write_func_t,
    *mut c_void,
    c_double,
    c_double,
) -> *mut ffi::cairo_surface_t;

static STREAM_CALLBACK_ENVIRONMENT: UserDataKey<UnsafeCell<CallbackEnvironment>> =
    UserDataKey::new();

struct CallbackEnvironment {
    stream: Option<Box<dyn Any>>,
    io_error: Option<io::Error>,
    unwind_payload: Option<Box<dyn Any + Send + 'static>>,
}

// Safety: unwinding into C is undefined behavior (https://github.com/rust-lang/rust/issues/58794)
// so code outside of the `catch_unwind` call must never panic.
extern "C" fn write_callback<W: io::Write + 'static>(
    env: *mut c_void,
    data: *mut c_uchar,
    length: c_uint,
) -> cairo_status_t {
    // This is consistent with the type of `env` in `Surface::_for_stream`.
    let env: *const UnsafeCell<CallbackEnvironment> = env as _;

    // Safety: the user data entry keeps `Rc<UnsafeCell<CallbackEnvironment>>` alive
    // until the surface is destroyed.
    // If this is called by cairo, the surface is still alive.
    let env: &UnsafeCell<CallbackEnvironment> = unsafe { &*env };

    with_mut_env(env, |env| {
        if let CallbackEnvironment {
            stream: Some(stream),
            // Don’t attempt another write if a previous one errored or panicked:
            io_error: None,
            unwind_payload: None,
        } = env {
            // Safety: `write_callback<W>` was instanciated in `Surface::_for_stream`
            // with a W parameter consistent with the box that was unsized to `Box<dyn Any>`.
            let stream = unsafe {
                stream.downcast_mut_unchecked::<W>()
            };
            // Safety: this is the callback contract from cairo’s API
            let data = unsafe {
                std::slice::from_raw_parts(data, length as usize)
            };
            // Because `<W as Write>::write_all` is a generic,
            // we must conservatively assume that it can panic.
            let result = std::panic::catch_unwind(AssertUnwindSafe(|| stream.write_all(data)));
            match result {
                Ok(Ok(())) => {
                    return Status::Success
                }
                Ok(Err(error)) => {
                    env.io_error = Some(error);
                }
                Err(payload) => {
                    env.unwind_payload = Some(payload);
                }
            }
        }
        Status::WriteError
    }).into()
}

fn with_mut_env<R, F>(env: &UnsafeCell<CallbackEnvironment>, f: F) -> R
    where F: FnOnce(&mut CallbackEnvironment) -> R
{
    // Safety:
    //
    // * The only long-lived pointers to this environment are
    //   the `void` pointer passed to surface constructor, and the one in user data.
    // * `STREAM_CALLBACK_ENVIRONMENT` is private,
    //   so the user data entry is only accessible in this module.
    // * `Surface` is !Send and !Sync, so a given surface is only used on a single thread.
    //
    // Therefore, there are no other ongoing reference to (part of) this `CallbackEnvironment`
    // and it is sound to claim exclusive / mutable access with `&mut`.
    unsafe {
        f(&mut *env.get())
    }
}

struct RawStream<W>(*mut W);

impl<W: io::Write> io::Write for RawStream<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { unsafe { (*self.0).write(buf) }}
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { unsafe { (*self.0).write_all(buf) }}
    fn flush(&mut self) -> io::Result<()> { unsafe { (*self.0).flush() } }
}

trait AnyExt {
    /// Any::downcast_mut, but YOLO
    unsafe fn downcast_mut_unchecked<T>(&mut self) -> &mut T {
        let ptr = self as *mut Self as *mut T;
        &mut *ptr
    }
}
impl AnyExt for dyn Any {}
<commit_msg>UnsafeCell for output streams is unsound, use RefCell<commit_after>// Copyright 2019, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ::ffi::{self, cairo_status_t};
use ::{Status, Surface, UserDataKey};

use libc::{c_void, c_double, c_uchar, c_uint};
use std::any::Any;
use std::cell::{Cell, RefCell};
use std::io;
use std::panic::AssertUnwindSafe;
use std::rc::Rc;

macro_rules! for_stream_constructors {
    ($constructor_ffi: ident) => {
        /// Takes full ownership of the output stream,
        /// which is not allowed to borrow any lifetime shorter than `'static`.
        ///
        /// Because the underlying `cairo_surface_t` is reference-counted,
        /// a lifetime parameter in a Rust wrapper type would not be enough to track
        /// how long it can keep writing to the stream.
        pub fn for_stream<W: io::Write + 'static>(width: f64, height: f64, stream: W) -> Self {
            Self {
                inner: Surface::_for_stream(
                    ffi::$constructor_ffi,
                    width,
                    height,
                    stream,
                ),
            }
        }

        /// Allows writing to a borrowed stream. The lifetime of the borrow is not tracked.
        ///
        /// # Safety
        ///
        /// The value that `stream` points to must live at least until the underlying `cairo_surface_t`
        /// (which maybe be longer then the Rust `PdfSurface` wrapper, because of reference-counting),
        /// or until the output stream is removed from the surface with [`Surface::take_output_stream`].
        ///
        /// Since the former is hard to track for sure, the latter is strongly recommended.
        /// The concrete type behind the `Box<dyn Any>` value returned by `take_output_stream`
        /// is private, so you won’t be able to downcast it.
        /// But removing it anyway ensures that later writes do no go through a dangling pointer.
        pub unsafe fn for_raw_stream<W: io::Write + 'static>(width: f64, height: f64, stream: *mut W) -> Self {
            Self {
                inner: Surface::_for_raw_stream(
                    ffi::$constructor_ffi,
                    width,
                    height,
                    stream,
                ),
            }
        }
    };
}

impl Surface {
    pub(crate) fn _for_stream<W: io::Write + 'static>(
        constructor: Constructor,
        width: f64,
        height: f64,
        stream: W,
    ) -> Self {
        let env_rc = Rc::new(CallbackEnvironment {
            mutable: RefCell::new(MutableCallbackEnvironment {
                stream: Some(Box::new(stream)),
                io_error: None,
                unwind_payload: None,
            }),
            saw_already_borrowed: Cell::new(false),
        });
        let env: *const CallbackEnvironment = &*env_rc;
        unsafe {
            let ptr = constructor(Some(write_callback::<W>), env as *mut c_void, width, height);
            let surface = Surface::from_raw_full(ptr);
            surface.set_user_data(&STREAM_CALLBACK_ENVIRONMENT, env_rc);
            surface
        }
    }

    pub(crate) unsafe fn _for_raw_stream<W: io::Write + 'static>(
        constructor: Constructor,
        width: f64,
        height: f64,
        stream: *mut W,
    ) -> Self {
        Self::_for_stream(constructor, width, height, RawStream(stream))
    }

    fn with_stream_env<R, F>(&self, f: F) -> Option<R>
        where F: FnOnce(&mut MutableCallbackEnvironment) -> Option<R>
    {
        let env = self.get_user_data_ptr(&STREAM_CALLBACK_ENVIRONMENT)?;

        // Safety: contract of `get_user_data_ptr`
        let env = unsafe { env.as_ref() };

        if env.saw_already_borrowed.get() {
            panic!("The output stream’s RefCell was already borrowed when cairo attempted a write")
        }

        let mutable = &mut *env.mutable.borrow_mut();
        if let Some(payload) = mutable.unwind_payload.take() {
            std::panic::resume_unwind(payload)
        }
        f(mutable)
    }

    /// Remove and return the output stream, if any.
    ///
    /// This is relevant for surfaces created for example with [`PdfSurface::for_stream`].
    /// Consider calling [`Surface::finish`] first,
    /// to ensure that all writes to the stream are done.
    ///
    /// Use [`Box::downcast`] to recover the concrete type.
    pub fn take_output_stream(&self) -> Option<Box<dyn Any>> {
        self.with_stream_env(|env| env.stream.take())
    }

    /// Remove and return the last error that occurred while writing to the output stream, if any.
    pub fn take_io_error(&self) -> Result<(), io::Error> {
        match self.with_stream_env(|env| env.io_error.take()) {
            Some(error) => Err(error),
            None => Ok(()),
        }
    }

    /// Return whether the surface has an associated output stream (that hasn’t been removed yet).
    pub fn has_output_stream(&self) -> bool {
        self.with_stream_env(|env| Some(env.stream.is_some())).unwrap_or(false)
    }

    /// Return whether an error that occurred while writing to the output stream, if any.
    pub fn has_io_error(&self) -> bool {
        self.with_stream_env(|env| Some(env.io_error.is_some())).unwrap_or(false)
    }
}

pub(crate) type Constructor = unsafe extern fn(
    ffi::cairo_write_func_t,
    *mut c_void,
    c_double,
    c_double,
) -> *mut ffi::cairo_surface_t;

static STREAM_CALLBACK_ENVIRONMENT: UserDataKey<CallbackEnvironment> =
    UserDataKey::new();

struct CallbackEnvironment {
    mutable: RefCell<MutableCallbackEnvironment>,
    saw_already_borrowed: Cell<bool>,
}

struct MutableCallbackEnvironment {
    stream: Option<Box<dyn Any>>,
    io_error: Option<io::Error>,
    unwind_payload: Option<Box<dyn Any + Send + 'static>>,
}

// Safety: unwinding into C is undefined behavior (https://github.com/rust-lang/rust/issues/58794)
// so code outside of the `catch_unwind` call must never panic.
extern "C" fn write_callback<W: io::Write + 'static>(
    env: *mut c_void,
    data: *mut c_uchar,
    length: c_uint,
) -> cairo_status_t {
    // This is consistent with the type of `env` in `Surface::_for_stream`.
    let env: *const CallbackEnvironment = env as _;

    // Safety: the user data entry keeps `Rc<CallbackEnvironment>` alive
    // until the surface is destroyed.
    // If this is called by cairo, the surface is still alive.
    let env: &CallbackEnvironment = unsafe { &*env };

    if let Ok(mut mutable) = env.mutable.try_borrow_mut() {
        if let MutableCallbackEnvironment {
            stream: Some(stream),
            // Don’t attempt another write if a previous one errored or panicked:
            io_error: io_error @ None,
            unwind_payload: unwind_payload @ None,
        } = &mut *mutable {
            // Safety: `write_callback<W>` was instanciated in `Surface::_for_stream`
            // with a W parameter consistent with the box that was unsized to `Box<dyn Any>`.
            let stream = unsafe {
                stream.downcast_mut_unchecked::<W>()
            };
            // Safety: this is the callback contract from cairo’s API
            let data = unsafe {
                std::slice::from_raw_parts(data, length as usize)
            };
            // Because `<W as Write>::write_all` is a generic,
            // we must conservatively assume that it can panic.
            let result = std::panic::catch_unwind(AssertUnwindSafe(|| stream.write_all(data)));
            match result {
                Ok(Ok(())) => {
                    return Status::Success.into()
                }
                Ok(Err(error)) => {
                    *io_error = Some(error);
                }
                Err(payload) => {
                    *unwind_payload = Some(payload);
                }
            }
        }
    } else {
        // This can happen if `W` holds a reference to the surface,
        // and caused cairo to make a write while the previous one was still ongoing.
        env.saw_already_borrowed.set(true)
    }
    Status::WriteError.into()
}

struct RawStream<W>(*mut W);

impl<W: io::Write> io::Write for RawStream<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { unsafe { (*self.0).write(buf) }}
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { unsafe { (*self.0).write_all(buf) }}
    fn flush(&mut self) -> io::Result<()> { unsafe { (*self.0).flush() } }
}

trait AnyExt {
    /// Any::downcast_mut, but YOLO
    unsafe fn downcast_mut_unchecked<T>(&mut self) -> &mut T {
        let ptr = self as *mut Self as *mut T;
        &mut *ptr
    }
}
impl AnyExt for dyn Any {}
<|endoftext|>


<commit_before>//! Licensed under the Apache License, Version 2.0
//! http://www.apache.org/licenses/LICENSE-2.0 or the MIT license
//! http://opensource.org/licenses/MIT, at your
//! option. This file may not be copied, modified, or distributed
//! except according to those terms.

use std::fmt;
use std::kinds;
use std::mem;
use std::num;

/// Similar to the slice iterator, but with a certain number of steps
/// (stride) skipped per iteration.
///
/// Does not support zero-sized `A`.
///
/// Iterator element type is `&'a A`
pub struct Stride<'a, A> {
    /// base pointer -- does not change during iteration
    begin: *const A,
    /// current offset from begin
    offset: int,
    /// offset where we end (exclusive end).
    end: int,
    stride: int,
    life: kinds::marker::ContravariantLifetime<'a>,
}

/// Stride with mutable elements
///
/// Iterator element type is `&'a mut A`
pub struct StrideMut<'a, A> {
    begin: *mut A,
    offset: int,
    end: int,
    stride: int,
    life: kinds::marker::ContravariantLifetime<'a>,
    nocopy: kinds::marker::NoCopy
}

impl<'a, A> Stride<'a, A>
{
    /// Create Stride iterator from a raw pointer.
    pub unsafe fn from_ptr_len(begin: *const A, nelem: uint, stride: int) -> Stride<'a, A>
    {
        Stride {
            begin: begin,
            offset: 0,
            end: stride * nelem as int,
            stride: stride,
            life: kinds::marker::ContravariantLifetime,
        }
    }
}

impl<'a, A> StrideMut<'a, A>
{
    /// Create Stride iterator from a raw pointer.
    pub unsafe fn from_ptr_len(begin: *mut A, nelem: uint, stride: int) -> StrideMut<'a, A>
    {
        StrideMut {
            begin: begin,
            offset: 0,
            end: stride * nelem as int,
            stride: stride,
            life: kinds::marker::ContravariantLifetime,
            nocopy: kinds::marker::NoCopy,
        }
    }
}

macro_rules! stride_impl {
    (struct $name:ident -> $slice:ty, $getptr:ident, $ptr:ty, $elem:ty) => {
        impl<'a, A> $name<'a, A>
        {
            /// Create Stride iterator from a slice and the element step count.
            ///
            /// If `step` is negative, start from the back.
            ///
            /// ## Example
            ///
            /// ```
            /// use itertools::Stride;
            ///
            /// let xs = [0i, 1, 2, 3, 4, 5];
            ///
            /// let mut front = Stride::from_slice(xs.as_slice(), 2);
            /// assert_eq!(front[0], 0);
            /// assert_eq!(front[1], 2);
            ///
            /// let mut back = Stride::from_slice(xs.as_slice(), -2);
            /// assert_eq!(back[0], 5);
            /// assert_eq!(back[1], 3);
            /// ```
            #[inline]
            pub fn from_slice(xs: $slice, step: int) -> $name<'a, A>
            {
                assert!(mem::size_of::<A>() != 0);
                let ustep = if step < 0 { -step } else { step } as uint;
                let nelem = if ustep <= 1 {
                    xs.len()
                } else {
                    let (d, r) = num::div_rem(xs.len(), ustep);
                    d + if r > 0 { 1 } else { 0 }
                };
                let mut begin = xs. $getptr ();
                unsafe {
                    if step > 0 {
                        $name::from_ptr_len(begin, nelem, step)
                    } else {
                        if nelem != 0 {
                            begin = begin.offset(xs.len() as int - 1)
                        }
                        $name::from_ptr_len(begin, nelem, step)
                    }
                }
            }

            /// Create Stride iterator from an existing Stride iterator
            #[inline]
            pub fn from_stride(mut it: $name<'a, A>, mut step: int) -> $name<'a, A>
            {
                assert!(step != 0);
                if step < 0 {
                    it.swap_ends();
                    step = -step;
                }
                let len = (it.end - it.offset) / it.stride;
                let newstride = it.stride * step;
                let (d, r) = num::div_rem(len as uint, step as uint);
                let len = d as uint + if r > 0 { 1 } else { 0 };
                unsafe {
                    $name::from_ptr_len(it.begin, len, newstride)
                }
            }

            /// Swap the begin and end and reverse the stride,
            /// in effect reversing the iterator.
            #[inline]
            pub fn swap_ends(&mut self) {
                let len = (self.end - self.offset) / self.stride;
                if len > 0 {
                    unsafe {
                        let endptr = self.begin.offset((len - 1) * self.stride);
                        *self = $name::from_ptr_len(endptr, len as uint, -self.stride);
                    }
                }
            }
        }

        impl<'a, A> Iterator<$elem> for $name<'a, A>
        {
            #[inline]
            fn next(&mut self) -> Option<$elem>
            {
                if self.offset == self.end {
                    None
                } else {
                    unsafe {
                        let elt: $elem =
                            mem::transmute(self.begin.offset(self.offset));
                        self.offset += self.stride;
                        Some(elt)
                    }
                }
            }

            #[inline]
            fn size_hint(&self) -> (uint, Option<uint>) {
                let len = ((self.end - self.offset) / self.stride) as uint;
                (len, Some(len))
            }
        }

        impl<'a, A> DoubleEndedIterator<$elem> for $name<'a, A>
        {
            #[inline]
            fn next_back(&mut self) -> Option<$elem>
            {
                if self.offset == self.end {
                    None
                } else {
                    unsafe {
                        self.end -= self.stride;
                        let elt = mem::transmute(self.begin.offset(self.end));
                        Some(elt)
                    }
                }
            }
        }

        impl<'a, A> ExactSize<$elem> for $name<'a, A> { }

        impl<'a, A> Index<uint, A> for $name<'a, A>
        {
            fn index<'b>(&'b self, i: &uint) -> &'b A
            {
                assert!(*i < self.size_hint().val0());
                unsafe {
                    let ptr = self.begin.offset(self.offset + self.stride * (*i as int));
                    mem::transmute(ptr)
                }
            }
        }
    }
}

stride_impl!{struct Stride -> &'a [A], as_ptr, *const A, &'a A}
stride_impl!{struct StrideMut -> &'a mut [A], as_mut_ptr, *mut A, &'a mut A}

impl<'a, A: fmt::Show> fmt::Show for Stride<'a, A>
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        let it = *self;
        try!(write!(f, "["));
        for (i, elt) in it.enumerate() {
            if i != 0 {
                try!(write!(f, ", "));
            }
            try!(write!(f, "{}", *elt));
        }
        write!(f, "]")
    }
}

impl<'a, A> Clone for Stride<'a, A>
{
    fn clone(&self) -> Stride<'a, A>
    {
        *self
    }
}
<commit_msg>Stride: impl Show for StrideMut<commit_after>//! Licensed under the Apache License, Version 2.0
//! http://www.apache.org/licenses/LICENSE-2.0 or the MIT license
//! http://opensource.org/licenses/MIT, at your
//! option. This file may not be copied, modified, or distributed
//! except according to those terms.

use std::fmt;
use std::kinds;
use std::mem;
use std::num;

/// Similar to the slice iterator, but with a certain number of steps
/// (stride) skipped per iteration.
///
/// Does not support zero-sized `A`.
///
/// Iterator element type is `&'a A`
pub struct Stride<'a, A> {
    /// base pointer -- does not change during iteration
    begin: *const A,
    /// current offset from begin
    offset: int,
    /// offset where we end (exclusive end).
    end: int,
    stride: int,
    life: kinds::marker::ContravariantLifetime<'a>,
}

/// Stride with mutable elements
///
/// Iterator element type is `&'a mut A`
pub struct StrideMut<'a, A> {
    begin: *mut A,
    offset: int,
    end: int,
    stride: int,
    life: kinds::marker::ContravariantLifetime<'a>,
    nocopy: kinds::marker::NoCopy
}

impl<'a, A> Stride<'a, A>
{
    /// Create Stride iterator from a raw pointer.
    pub unsafe fn from_ptr_len(begin: *const A, nelem: uint, stride: int) -> Stride<'a, A>
    {
        Stride {
            begin: begin,
            offset: 0,
            end: stride * nelem as int,
            stride: stride,
            life: kinds::marker::ContravariantLifetime,
        }
    }
}

impl<'a, A> StrideMut<'a, A>
{
    /// Create Stride iterator from a raw pointer.
    pub unsafe fn from_ptr_len(begin: *mut A, nelem: uint, stride: int) -> StrideMut<'a, A>
    {
        StrideMut {
            begin: begin,
            offset: 0,
            end: stride * nelem as int,
            stride: stride,
            life: kinds::marker::ContravariantLifetime,
            nocopy: kinds::marker::NoCopy,
        }
    }
}

macro_rules! stride_impl {
    (struct $name:ident -> $slice:ty, $getptr:ident, $ptr:ty, $elem:ty) => {
        impl<'a, A> $name<'a, A>
        {
            /// Create Stride iterator from a slice and the element step count.
            ///
            /// If `step` is negative, start from the back.
            ///
            /// ## Example
            ///
            /// ```
            /// use itertools::Stride;
            ///
            /// let xs = [0i, 1, 2, 3, 4, 5];
            ///
            /// let mut front = Stride::from_slice(xs.as_slice(), 2);
            /// assert_eq!(front[0], 0);
            /// assert_eq!(front[1], 2);
            ///
            /// let mut back = Stride::from_slice(xs.as_slice(), -2);
            /// assert_eq!(back[0], 5);
            /// assert_eq!(back[1], 3);
            /// ```
            #[inline]
            pub fn from_slice(xs: $slice, step: int) -> $name<'a, A>
            {
                assert!(mem::size_of::<A>() != 0);
                let ustep = if step < 0 { -step } else { step } as uint;
                let nelem = if ustep <= 1 {
                    xs.len()
                } else {
                    let (d, r) = num::div_rem(xs.len(), ustep);
                    d + if r > 0 { 1 } else { 0 }
                };
                let mut begin = xs. $getptr ();
                unsafe {
                    if step > 0 {
                        $name::from_ptr_len(begin, nelem, step)
                    } else {
                        if nelem != 0 {
                            begin = begin.offset(xs.len() as int - 1)
                        }
                        $name::from_ptr_len(begin, nelem, step)
                    }
                }
            }

            /// Create Stride iterator from an existing Stride iterator
            #[inline]
            pub fn from_stride(mut it: $name<'a, A>, mut step: int) -> $name<'a, A>
            {
                assert!(step != 0);
                if step < 0 {
                    it.swap_ends();
                    step = -step;
                }
                let len = (it.end - it.offset) / it.stride;
                let newstride = it.stride * step;
                let (d, r) = num::div_rem(len as uint, step as uint);
                let len = d as uint + if r > 0 { 1 } else { 0 };
                unsafe {
                    $name::from_ptr_len(it.begin, len, newstride)
                }
            }

            /// Swap the begin and end and reverse the stride,
            /// in effect reversing the iterator.
            #[inline]
            pub fn swap_ends(&mut self) {
                let len = (self.end - self.offset) / self.stride;
                if len > 0 {
                    unsafe {
                        let endptr = self.begin.offset((len - 1) * self.stride);
                        *self = $name::from_ptr_len(endptr, len as uint, -self.stride);
                    }
                }
            }
        }

        impl<'a, A> Iterator<$elem> for $name<'a, A>
        {
            #[inline]
            fn next(&mut self) -> Option<$elem>
            {
                if self.offset == self.end {
                    None
                } else {
                    unsafe {
                        let elt: $elem =
                            mem::transmute(self.begin.offset(self.offset));
                        self.offset += self.stride;
                        Some(elt)
                    }
                }
            }

            #[inline]
            fn size_hint(&self) -> (uint, Option<uint>) {
                let len = ((self.end - self.offset) / self.stride) as uint;
                (len, Some(len))
            }
        }

        impl<'a, A> DoubleEndedIterator<$elem> for $name<'a, A>
        {
            #[inline]
            fn next_back(&mut self) -> Option<$elem>
            {
                if self.offset == self.end {
                    None
                } else {
                    unsafe {
                        self.end -= self.stride;
                        let elt = mem::transmute(self.begin.offset(self.end));
                        Some(elt)
                    }
                }
            }
        }

        impl<'a, A> ExactSize<$elem> for $name<'a, A> { }

        impl<'a, A> Index<uint, A> for $name<'a, A>
        {
            fn index<'b>(&'b self, i: &uint) -> &'b A
            {
                assert!(*i < self.size_hint().val0());
                unsafe {
                    let ptr = self.begin.offset(self.offset + self.stride * (*i as int));
                    mem::transmute(ptr)
                }
            }
        }

        impl<'a, A: fmt::Show> fmt::Show for $name<'a, A>
        {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
            {
                try!(write!(f, "["));
                for i in range(0, self.len()) {
                    if i != 0 {
                        try!(write!(f, ", "));
                    }
                    try!(write!(f, "{}", (*self)[i]));
                }
                write!(f, "]")
            }
        }
    }
}

stride_impl!{struct Stride -> &'a [A], as_ptr, *const A, &'a A}
stride_impl!{struct StrideMut -> &'a mut [A], as_mut_ptr, *mut A, &'a mut A}

impl<'a, A> Clone for Stride<'a, A>
{
    fn clone(&self) -> Stride<'a, A>
    {
        *self
    }
}
<|endoftext|>


<commit_before>use nom::error::ErrorKind;
use nom::number::streaming::{be_u16, be_u8};
use nom::{Err, IResult};

/// Named curves, as defined in [RFC4492](https://tools.ietf.org/html/rfc4492), [RFC7027](https://tools.ietf.org/html/rfc7027), [RFC7919](https://tools.ietf.org/html/rfc7919) and
/// [IANA Supported Groups
/// Registry](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8)
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct NamedGroup(pub u16);

newtype_enum! {
impl debug NamedGroup {
    Sect163k1 = 1,
    Sect163r1 = 2,
    Sect163r2 = 3,
    Sect193r1 = 4,
    Sect193r2 = 5,
    Sect233k1 = 6,
    Sect233r1 = 7,
    Sect239k1 = 8,
    Sect283k1 = 9,
    Sect283r1 = 10,
    Sect409k1 = 11,
    Sect409r1 = 12,
    Sect571k1 = 13,
    Sect571r1 = 14,
    Secp160k1 = 15,
    Secp160r1 = 16,
    Secp160r2 = 17,
    Secp192k1 = 18,
    Secp192r1 = 19,
    Secp224k1 = 20,
    Secp224r1 = 21,
    Secp256k1 = 22,
    Secp256r1 = 23,
    Secp384r1 = 24,
    Secp521r1 = 25,
    BrainpoolP256r1 = 26,
    BrainpoolP384r1 = 27,
    BrainpoolP512r1 = 28,
    EcdhX25519 = 29,
    EcdhX448 = 30,
    Sm2 = 41,
    Ffdhe2048 = 0x100,
    Ffdhe3072 = 0x101,
    Ffdhe4096 = 0x102,
    Ffdhe6144 = 0x103,
    Ffdhe8192 = 0x104,
    ArbitraryExplicitPrimeCurves = 0xFF01,
    ArbitraryExplicitChar2Curves = 0xFF02,
}
}

impl NamedGroup {
    /// Return key size of curve in bits, or None if unknown
    pub fn key_bits(self: &NamedGroup) -> Option<u16> {
        match *self {
            NamedGroup::Sect163k1 => Some(163),
            NamedGroup::Sect163r1 => Some(163),
            NamedGroup::Sect163r2 => Some(163),
            NamedGroup::Sect193r1 => Some(193),
            NamedGroup::Sect193r2 => Some(193),
            NamedGroup::Sect233k1 => Some(233),
            NamedGroup::Sect233r1 => Some(233),
            NamedGroup::Sect239k1 => Some(239),
            NamedGroup::Sect283k1 => Some(283),
            NamedGroup::Sect283r1 => Some(283),
            NamedGroup::Sect409k1 => Some(409),
            NamedGroup::Sect409r1 => Some(409),
            NamedGroup::Sect571k1 => Some(571),
            NamedGroup::Sect571r1 => Some(571),
            NamedGroup::Secp160k1 => Some(160),
            NamedGroup::Secp160r1 => Some(160),
            NamedGroup::Secp160r2 => Some(160),
            NamedGroup::Secp192k1 => Some(192),
            NamedGroup::Secp192r1 => Some(192),
            NamedGroup::Secp224k1 => Some(224),
            NamedGroup::Secp224r1 => Some(224),
            NamedGroup::Secp256k1 => Some(256),
            NamedGroup::Secp256r1 => Some(256),
            NamedGroup::Secp384r1 => Some(384),
            NamedGroup::Secp521r1 => Some(521),
            NamedGroup::BrainpoolP256r1 => Some(256),
            NamedGroup::BrainpoolP384r1 => Some(384),
            NamedGroup::BrainpoolP512r1 => Some(521),
            NamedGroup::EcdhX25519 => Some(253),
            _ => None,
        }
    }
}

/// Elliptic curve
///
/// a and b specify the coefficients of the curve
#[derive(Debug, PartialEq)]
pub struct ECCurve<'a> {
    pub a: &'a [u8],
    pub b: &'a [u8],
}

/// Elliptic curve types, as defined in the
/// [IANA EC Curve Type Registry
/// Registry](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-10)
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct ECCurveType(pub u8);

newtype_enum! {
impl display ECCurveType {
    ExplicitPrime = 1,
    ExplicitChar2 = 2,
    NamedGroup = 3,
}
}

/// EC Point
#[derive(Clone, Debug, PartialEq)]
pub struct ECPoint<'a> {
    pub point: &'a [u8],
}

/// Elliptic curve parameters, conveyed verbosely as a prime field, as
/// defined in [RFC4492](https://tools.ietf.org/html/rfc4492) section 5.4
#[derive(Debug, PartialEq)]
pub struct ExplicitPrimeContent<'a> {
    pub prime_p: &'a [u8],
    pub curve: ECCurve<'a>,
    pub base: ECPoint<'a>,
    pub order: &'a [u8],
    pub cofactor: &'a [u8],
}

/// Elliptic curve parameters content (depending on EC type)
#[derive(PartialEq)]
pub enum ECParametersContent<'a> {
    ExplicitPrime(ExplicitPrimeContent<'a>),
    // TODO ExplicitChar2 is defined in [RFC4492] section 5.4
    ExplicitChar2(&'a [u8]),
    NamedGroup(NamedGroup),
}

/// Elliptic curve parameters,
/// defined in [RFC4492](https://tools.ietf.org/html/rfc4492) section 5.4
#[derive(PartialEq)]
pub struct ECParameters<'a> {
    /// Should match a [ECCurveType](enum.ECCurveType.html) value
    pub curve_type: ECCurveType,
    pub params_content: ECParametersContent<'a>,
}

/// ECDH parameters
/// defined in [RFC4492](https://tools.ietf.org/html/rfc4492) section 5.4
#[derive(Debug, PartialEq)]
pub struct ServerECDHParams<'a> {
    pub curve_params: ECParameters<'a>,
    pub public: ECPoint<'a>,
}

/// Parse the entire input as a list of named groups (curves)
pub fn parse_named_groups(i: &[u8]) -> IResult<&[u8], Vec<NamedGroup>> {
    let len = i.len();
    if len == 0 {
        return Ok((i, Vec::new()));
    }
    if len % 2 == 1 || len > i.len() {
        return Err(Err::Error(error_position!(i, ErrorKind::LengthValue)));
    }
    let v = (&i[..len])
        .chunks(2)
        .map(|chunk| NamedGroup((chunk[0] as u16) << 8 | chunk[1] as u16))
        .collect();
    Ok((&i[len..], v))
}

named!(
    parse_ec_point<ECPoint>,
    map!(length_data!(be_u8), |d| { ECPoint { point: d } })
);

named! {parse_ec_curve<ECCurve>,
    do_parse!(
        a: length_data!(be_u8) >>
        b: length_data!(be_u8) >>
        ( ECCurve{a:a,b:b} )
    )
}

named! {parse_ec_explicit_prime_content<ECParametersContent>,
    do_parse!(
        p:        length_data!(be_u8) >>
        curve:    parse_ec_curve >>
        base:     parse_ec_point >>
        order:    length_data!(be_u8) >>
        cofactor: length_data!(be_u8) >>
        (
            ECParametersContent::ExplicitPrime(
                ExplicitPrimeContent{
                    prime_p:  p,
                    curve:    curve,
                    base:     base,
                    order:    order,
                    cofactor: cofactor,
                }
            )
        )
    )
}

named!(
    parse_ec_named_curve_content<ECParametersContent>,
    map!(be_u16, |c| {
        ECParametersContent::NamedGroup(NamedGroup(c))
    })
);

named! {pub parse_ec_parameters<ECParameters>,
    do_parse!(
        curve_type: be_u8  >>
        d: switch!(value!(curve_type),
            1 => call!(parse_ec_explicit_prime_content) |
            3 => call!(parse_ec_named_curve_content)
        ) >>
        (
            ECParameters{
                curve_type: ECCurveType(curve_type),
                params_content: d,
            }
        )
    )
}

named! {pub parse_ecdh_params<ServerECDHParams>,
    do_parse!(
        c: parse_ec_parameters >>
        p: parse_ec_point >>
        ( ServerECDHParams{curve_params:c,public:p} )
    )
}
<commit_msg>Pass NamedGroup by copy (size is only 2 bytes)<commit_after>use nom::error::ErrorKind;
use nom::number::streaming::{be_u16, be_u8};
use nom::{Err, IResult};

/// Named curves, as defined in [RFC4492](https://tools.ietf.org/html/rfc4492), [RFC7027](https://tools.ietf.org/html/rfc7027), [RFC7919](https://tools.ietf.org/html/rfc7919) and
/// [IANA Supported Groups
/// Registry](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8)
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct NamedGroup(pub u16);

newtype_enum! {
impl debug NamedGroup {
    Sect163k1 = 1,
    Sect163r1 = 2,
    Sect163r2 = 3,
    Sect193r1 = 4,
    Sect193r2 = 5,
    Sect233k1 = 6,
    Sect233r1 = 7,
    Sect239k1 = 8,
    Sect283k1 = 9,
    Sect283r1 = 10,
    Sect409k1 = 11,
    Sect409r1 = 12,
    Sect571k1 = 13,
    Sect571r1 = 14,
    Secp160k1 = 15,
    Secp160r1 = 16,
    Secp160r2 = 17,
    Secp192k1 = 18,
    Secp192r1 = 19,
    Secp224k1 = 20,
    Secp224r1 = 21,
    Secp256k1 = 22,
    Secp256r1 = 23,
    Secp384r1 = 24,
    Secp521r1 = 25,
    BrainpoolP256r1 = 26,
    BrainpoolP384r1 = 27,
    BrainpoolP512r1 = 28,
    EcdhX25519 = 29,
    EcdhX448 = 30,
    Sm2 = 41,
    Ffdhe2048 = 0x100,
    Ffdhe3072 = 0x101,
    Ffdhe4096 = 0x102,
    Ffdhe6144 = 0x103,
    Ffdhe8192 = 0x104,
    ArbitraryExplicitPrimeCurves = 0xFF01,
    ArbitraryExplicitChar2Curves = 0xFF02,
}
}

impl NamedGroup {
    /// Return key size of curve in bits, or None if unknown
    pub fn key_bits(self: NamedGroup) -> Option<u16> {
        match self {
            NamedGroup::Sect163k1 => Some(163),
            NamedGroup::Sect163r1 => Some(163),
            NamedGroup::Sect163r2 => Some(163),
            NamedGroup::Sect193r1 => Some(193),
            NamedGroup::Sect193r2 => Some(193),
            NamedGroup::Sect233k1 => Some(233),
            NamedGroup::Sect233r1 => Some(233),
            NamedGroup::Sect239k1 => Some(239),
            NamedGroup::Sect283k1 => Some(283),
            NamedGroup::Sect283r1 => Some(283),
            NamedGroup::Sect409k1 => Some(409),
            NamedGroup::Sect409r1 => Some(409),
            NamedGroup::Sect571k1 => Some(571),
            NamedGroup::Sect571r1 => Some(571),
            NamedGroup::Secp160k1 => Some(160),
            NamedGroup::Secp160r1 => Some(160),
            NamedGroup::Secp160r2 => Some(160),
            NamedGroup::Secp192k1 => Some(192),
            NamedGroup::Secp192r1 => Some(192),
            NamedGroup::Secp224k1 => Some(224),
            NamedGroup::Secp224r1 => Some(224),
            NamedGroup::Secp256k1 => Some(256),
            NamedGroup::Secp256r1 => Some(256),
            NamedGroup::Secp384r1 => Some(384),
            NamedGroup::Secp521r1 => Some(521),
            NamedGroup::BrainpoolP256r1 => Some(256),
            NamedGroup::BrainpoolP384r1 => Some(384),
            NamedGroup::BrainpoolP512r1 => Some(521),
            NamedGroup::EcdhX25519 => Some(253),
            _ => None,
        }
    }
}

/// Elliptic curve
///
/// a and b specify the coefficients of the curve
#[derive(Debug, PartialEq)]
pub struct ECCurve<'a> {
    pub a: &'a [u8],
    pub b: &'a [u8],
}

/// Elliptic curve types, as defined in the
/// [IANA EC Curve Type Registry
/// Registry](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-10)
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct ECCurveType(pub u8);

newtype_enum! {
impl display ECCurveType {
    ExplicitPrime = 1,
    ExplicitChar2 = 2,
    NamedGroup = 3,
}
}

/// EC Point
#[derive(Clone, Debug, PartialEq)]
pub struct ECPoint<'a> {
    pub point: &'a [u8],
}

/// Elliptic curve parameters, conveyed verbosely as a prime field, as
/// defined in [RFC4492](https://tools.ietf.org/html/rfc4492) section 5.4
#[derive(Debug, PartialEq)]
pub struct ExplicitPrimeContent<'a> {
    pub prime_p: &'a [u8],
    pub curve: ECCurve<'a>,
    pub base: ECPoint<'a>,
    pub order: &'a [u8],
    pub cofactor: &'a [u8],
}

/// Elliptic curve parameters content (depending on EC type)
#[derive(PartialEq)]
pub enum ECParametersContent<'a> {
    ExplicitPrime(ExplicitPrimeContent<'a>),
    // TODO ExplicitChar2 is defined in [RFC4492] section 5.4
    ExplicitChar2(&'a [u8]),
    NamedGroup(NamedGroup),
}

/// Elliptic curve parameters,
/// defined in [RFC4492](https://tools.ietf.org/html/rfc4492) section 5.4
#[derive(PartialEq)]
pub struct ECParameters<'a> {
    /// Should match a [ECCurveType](enum.ECCurveType.html) value
    pub curve_type: ECCurveType,
    pub params_content: ECParametersContent<'a>,
}

/// ECDH parameters
/// defined in [RFC4492](https://tools.ietf.org/html/rfc4492) section 5.4
#[derive(Debug, PartialEq)]
pub struct ServerECDHParams<'a> {
    pub curve_params: ECParameters<'a>,
    pub public: ECPoint<'a>,
}

/// Parse the entire input as a list of named groups (curves)
pub fn parse_named_groups(i: &[u8]) -> IResult<&[u8], Vec<NamedGroup>> {
    let len = i.len();
    if len == 0 {
        return Ok((i, Vec::new()));
    }
    if len % 2 == 1 || len > i.len() {
        return Err(Err::Error(error_position!(i, ErrorKind::LengthValue)));
    }
    let v = (&i[..len])
        .chunks(2)
        .map(|chunk| NamedGroup((chunk[0] as u16) << 8 | chunk[1] as u16))
        .collect();
    Ok((&i[len..], v))
}

named!(
    parse_ec_point<ECPoint>,
    map!(length_data!(be_u8), |d| { ECPoint { point: d } })
);

named! {parse_ec_curve<ECCurve>,
    do_parse!(
        a: length_data!(be_u8) >>
        b: length_data!(be_u8) >>
        ( ECCurve{a:a,b:b} )
    )
}

named! {parse_ec_explicit_prime_content<ECParametersContent>,
    do_parse!(
        p:        length_data!(be_u8) >>
        curve:    parse_ec_curve >>
        base:     parse_ec_point >>
        order:    length_data!(be_u8) >>
        cofactor: length_data!(be_u8) >>
        (
            ECParametersContent::ExplicitPrime(
                ExplicitPrimeContent{
                    prime_p:  p,
                    curve:    curve,
                    base:     base,
                    order:    order,
                    cofactor: cofactor,
                }
            )
        )
    )
}

named!(
    parse_ec_named_curve_content<ECParametersContent>,
    map!(be_u16, |c| {
        ECParametersContent::NamedGroup(NamedGroup(c))
    })
);

named! {pub parse_ec_parameters<ECParameters>,
    do_parse!(
        curve_type: be_u8  >>
        d: switch!(value!(curve_type),
            1 => call!(parse_ec_explicit_prime_content) |
            3 => call!(parse_ec_named_curve_content)
        ) >>
        (
            ECParameters{
                curve_type: ECCurveType(curve_type),
                params_content: d,
            }
        )
    )
}

named! {pub parse_ecdh_params<ServerECDHParams>,
    do_parse!(
        c: parse_ec_parameters >>
        p: parse_ec_point >>
        ( ServerECDHParams{curve_params:c,public:p} )
    )
}
<|endoftext|>