<commit_before>
use super::{
    Context,
    ContextUser,
    ContextBuilder,
    NoticeError
};

use serde_json::{self, Value};

use log::debug;
use std::error::Error;
use std::collections::HashMap;
use std::string::ToString;
use hyper::body::Body;
use crate::AirbrakeClient;

pub struct NoticeBuilder<'a> {
    pub client: Option<&'a AirbrakeClient>,
    pub errors: Vec<NoticeError>,
    pub context: Option<ContextBuilder>,
    pub environment: Option<HashMap<String, String>>,
    pub session: Option<HashMap<String, String>>,
    pub params: Option<HashMap<String, String>>
}

impl<'a> NoticeBuilder<'a> {
    /// Set the environment on the NoticeBuilder
    pub fn new() -> NoticeBuilder<'a> {
        NoticeBuilder {
            client: None,
            errors: vec![],
            context: None,
            environment: None,
            session: None,
            params: None
        }
    }

    pub fn set_client(mut self, client: &'a AirbrakeClient) -> NoticeBuilder<'a> {
        self.client = Some(client);
        self
    }

    /// Add multiple NoticeErrors from an iterator
    pub fn add_notices<T: Iterator<Item = NoticeError>>(mut self, notice_errors: T) -> NoticeBuilder<'a> {
        self.errors.extend(notice_errors);
        self
    }

    /// Add a single NoticeError
    pub fn add_notice(mut self, notice_error: NoticeError) -> NoticeBuilder<'a> {
        self.errors.push(notice_error);
        self
    }

    /// Add multiple Errors from an iterator
    pub fn add_errors<T: Iterator<Item = E>, E: Error>(self, errors: T) -> NoticeBuilder<'a> {
        let notice_errors = errors
            .into_iter()
            .map(|x| x.into());
        self.add_notices(notice_errors)
    }

    /// Add a single Error
    pub fn add_error<E: Error>(self, error: E) -> NoticeBuilder<'a> {
        let notice_error = NoticeError::from(error);
        self.add_notice(notice_error.into())
    }

    /// Set the context on the NoticeBuilder
    pub fn context(mut self, context: ContextBuilder) -> NoticeBuilder<'a> {
        self.context = Some(context);
        self
    }

    /// Set the operating_system on the configurations context
    pub fn operating_system(mut self, os: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.operating_system(os);
                Some(c)
            });
        self
    }

    /// Set the hostname on the configurations context
    pub fn hostname(mut self, hostname: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.hostname(hostname);
                Some(c)
            });
        self
    }

    /// Set the language on the configurations context
    pub fn language(mut self, language: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.language(language);
                Some(c)
            });
        self
    }

    /// Set the environment on the configurations context
    pub fn context_environment(mut self, environment: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.environment(environment);
                Some(c)
            });
        self
    }

    /// Set the severity on the configurations context
    pub fn severity(mut self, severity: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.severity(severity);
                Some(c)
            });
        self
    }

    /// Set the version on the configurations context
    pub fn version(mut self, version: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.version(version);
                Some(c)
            });
        self
    }

    /// Set the url on the configurations context
    pub fn url(mut self, url: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.url(url);
                Some(c)
            });
        self
    }

    /// Set the root_directory on the configurations context
    pub fn root_directory(mut self, root_directory: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.root_directory(root_directory);
                Some(c)
            });
        self
    }

    /// Set the user on the configurations context
    pub fn user(mut self, user: ContextUser) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.user(user);
                Some(c)
            });
        self
    }

    /// Set the route on the configurations context
    pub fn route(mut self, route: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.route(route);
                Some(c)
            });
        self
    }

    /// Set the http_method on the configurations context
    pub fn http_method(mut self, http_method: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.http_method(http_method);
                Some(c)
            });
        self
    }

    /// Set the environment on the NoticeBuilder
    pub fn environment(mut self, environment: HashMap<String, String>) -> NoticeBuilder<'a> {
        self.environment = Some(environment);
        self
    }

    /// Add environment to the NoticeBuilder
    /// ```
    /// use airbrake::Notice;
    /// let notice = Notice::builder()
    ///     .add_environment("PORT".to_owned(), "443".to_owned())
    ///     .add_environment("CODE_NAME".to_owned(), "gorilla".to_owned())
    ///     .build();
    /// ```
    pub fn add_environment(mut self, key: String, value: String) -> NoticeBuilder<'a> {
        self.environment = self.environment
            .or_else(|| Some(HashMap::new()))
            .and_then(|mut h| {
                h.insert(key, value);
                Some(h)
            });
        self
    }

    /// Set the environment on the NoticeBuilder
    pub fn session(mut self, session: HashMap<String, String>) -> NoticeBuilder<'a> {
        self.session = Some(session);
        self
    }

    /// Add session to the NoticeBuilder
    /// ```
    /// use airbrake::Notice;
    /// let notice = Notice::builder()
    ///     .add_session("basketId".to_owned(), "123".to_owned())
    ///     .add_session("userId".to_owned(), "456".to_owned())
    ///     .build();
    /// ```
    pub fn add_session(mut self, key: String, value: String) -> NoticeBuilder<'a> {
        self.session = self.session
            .or_else(|| Some(HashMap::new()))
            .and_then(|mut h| {
                h.insert(key, value);
                Some(h)
            });
        self
    }

    /// Set the environment on the NoticeBuilder
    pub fn params(mut self, params: HashMap<String, String>) -> NoticeBuilder<'a> {
        self.params = Some(params);
        self
    }

    /// Add param to the NoticeBuilder
    /// ```
    /// use airbrake::Notice;
    /// let notice = Notice::builder()
    ///     .add_param("page".to_owned(), "3".to_owned())
    ///     .add_param("sort".to_owned(), "name".to_owned())
    ///     .add_param("direction".to_owned(), "asc".to_owned())
    ///     .build();
    /// ```
    pub fn add_param(mut self, key: String, value: String) -> NoticeBuilder<'a> {
        self.params = self.params
            .or_else(|| Some(HashMap::new()))
            .and_then(|mut h| {
                h.insert(key, value);
                Some(h)
            });
        self
    }

    /// Executes the command as a child process, which is returned.
    pub fn build(self) -> Notice<'a> {
        let context = self.context.clone().and_then(|c| Some(c.build()));
        Notice {
            client: self.client,
            errors: self.errors,
            context: context,
            environment: self.environment,
            session: self.session,
            params: self.params
        }
    }
}

/// NoticeBuilder can be produced from a Context
///
/// The context specified in a Notice won't change often, and will typically
/// already exist while creating a new Notice so it only makes sense to
/// begin the Notice construction based on the context.
/// ```
/// use airbrake::{Context, NoticeBuilder};
///
/// let context = Context::builder();
/// let notice_builder = NoticeBuilder::from(&context);
/// ```
impl<'a, 'b> From<&ContextBuilder> for NoticeBuilder<'b> {
    fn from(context: &ContextBuilder) -> NoticeBuilder<'b> {
        NoticeBuilder::new().context(context.clone())
    }
}

impl<'a, 'b, E: Error> From<E> for NoticeBuilder<'b> {
    fn from(error: E) -> NoticeBuilder<'b> {
        NoticeBuilder::new().add_error(error)
    }
}

#[derive(Debug, Serialize)]
pub struct Notice<'a> {
    #[serde(skip)]
    pub client: Option<&'a AirbrakeClient>,

    pub errors: Vec<NoticeError>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub context: Option<Context>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub environment: Option<HashMap<String, String>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub session: Option<HashMap<String, String>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub params: Option<HashMap<String, String>>
}

impl<'a> Notice<'a> {
    /// Makes it easy to construct a new Notice
    ///
    /// ```
    /// use airbrake::{Context, Notice};
    ///
    /// let context = Context::builder();
    /// let notice = Notice::builder()
    ///     .context(context)
    ///     .build();
    /// ```
    pub fn builder() -> NoticeBuilder<'a> {
        NoticeBuilder::new()
    }

    pub fn send(self) {
        self.client.and_then(|c| {
            debug!("Sending via notice client");
            c.notify(self);
            Some(c)
        });
    }
}

impl<'a> From<Notice<'a>> for Value {
    fn from(notice: Notice<'a>) -> Value {
        serde_json::json!(notice)
    }
}

impl<'a> Into<Body> for Notice<'a> {
    fn into(self) -> Body {
        Body::from(Value::from(self).to_string())
    }
}

#[cfg(test)]
mod tests {
    use std::str::FromStr;
    use std::collections::HashMap;
    use serde_json::{self, Value};
    use hyper::body::Body;
    use super::{Notice, Context};

    #[test]
    fn notice_default() {
        let notice = Notice::builder().build();
        let expected_json = r#"
        {
            "errors": []
        }
        "#;
        assert_eq!(
            Value::from_str(expected_json).unwrap(),
            Value::from(notice)
        );
    }

    #[test]
    fn notice_with_add_environment() {
        let notice = Notice::builder()
            .add_environment("foo".to_owned(), "bar".to_owned())
            .build();
        let expected_json = r#"
        {
            "errors": [],
            "environment": {
                "foo": "bar"
            }
        }
        "#;
        assert_eq!(
            Value::from_str(expected_json).unwrap(),
            Value::from(notice)
        );
    }

    #[test]
    fn notice_with_set_environment() {
        let mut hashmap = HashMap::new();
        hashmap.insert("foo".to_owned(), "bar".to_owned());
        let notice = Notice::builder()
            .environment(hashmap)
            .build();
        let expected_json = r#"
        {
            "errors": [],
            "environment": {
                "foo": "bar"
            }
        }
        "#;
        assert_eq!(
            Value::from_str(expected_json).unwrap(),
            Value::from(notice)
        );
    }

    #[test]
    fn notice_with_add_session() {
        let notice = Notice::builder()
            .add_session("foo".to_owned(), "bar".to_owned())
            .build();
        let expected_json = r#"
        {
            "errors": [],
            "session": {
                "foo": "bar"
            }
        }
        "#;
        assert_eq!(
            Value::from_str(expected_json).unwrap(),
            Value::from(notice)
        );
    }

    #[test]
    fn notice_with_set_session() {
        let mut hashmap = HashMap::new();
        hashmap.insert("foo".to_owned(), "bar".to_owned());
        let notice = Notice::builder()
            .session(hashmap)
            .build();
        let expected_json = r#"
        {
            "errors": [],
            "session": {
                "foo": "bar"
            }
        }
        "#;
        assert_eq!(
            Value::from_str(expected_json).unwrap(),
            Value::from(notice)
        );
    }

    #[test]
    fn notice_with_add_param() {
        let notice = Notice::builder()
            .add_param("foo".to_owned(), "bar".to_owned())
            .build();
        let expected_json = r#"
        {
            "errors": [],
            "params": {
                "foo": "bar"
            }
        }
        "#;
        assert_eq!(
            Value::from_str(expected_json).unwrap(),
            Value::from(notice)
        );
    }

    #[test]
    fn notice_with_set_params() {
        let mut hashmap = HashMap::new();
        hashmap.insert("foo".to_owned(), "bar".to_owned());
        let notice = Notice::builder()
            .params(hashmap)
            .build();
        let expected_json = r#"
        {
            "errors": [],
            "params": {
                "foo": "bar"
            }
        }
        "#;
        assert_eq!(
            Value::from_str(expected_json).unwrap(),
            Value::from(notice)
        );
    }

    #[test]
    fn notice_context_default() {
        let context = Context::builder();
        let notice = Notice::builder()
            .context(context)
            .build();
        let expected_json = r#"
        {
            "errors": [],
            "context": {
                "notifier": {
                    "name": "airbrake-rust",
                    "version": "0.2.0",
                    "url": "https://github.com/airbrake/airbrake-rust"
                }
            }
        }
        "#;
        assert_eq!(
            Value::from_str(expected_json).unwrap(),
            Value::from(notice)
        );
    }
}<commit_msg>removed unused lifetime from trait implementations<commit_after>
use super::{
    Context,
    ContextUser,
    ContextBuilder,
    NoticeError
};

use serde_json::{self, Value};

use log::debug;
use std::error::Error;
use std::collections::HashMap;
use std::string::ToString;
use hyper::body::Body;
use crate::AirbrakeClient;

pub struct NoticeBuilder<'a> {
    pub client: Option<&'a AirbrakeClient>,
    pub errors: Vec<NoticeError>,
    pub context: Option<ContextBuilder>,
    pub environment: Option<HashMap<String, String>>,
    pub session: Option<HashMap<String, String>>,
    pub params: Option<HashMap<String, String>>
}

impl<'a> NoticeBuilder<'a> {
    /// Set the environment on the NoticeBuilder
    pub fn new() -> NoticeBuilder<'a> {
        NoticeBuilder {
            client: None,
            errors: vec![],
            context: None,
            environment: None,
            session: None,
            params: None
        }
    }

    pub fn set_client(mut self, client: &'a AirbrakeClient) -> NoticeBuilder<'a> {
        self.client = Some(client);
        self
    }

    /// Add multiple NoticeErrors from an iterator
    pub fn add_notices<T: Iterator<Item = NoticeError>>(mut self, notice_errors: T) -> NoticeBuilder<'a> {
        self.errors.extend(notice_errors);
        self
    }

    /// Add a single NoticeError
    pub fn add_notice(mut self, notice_error: NoticeError) -> NoticeBuilder<'a> {
        self.errors.push(notice_error);
        self
    }

    /// Add multiple Errors from an iterator
    pub fn add_errors<T: Iterator<Item = E>, E: Error>(self, errors: T) -> NoticeBuilder<'a> {
        let notice_errors = errors
            .into_iter()
            .map(|x| x.into());
        self.add_notices(notice_errors)
    }

    /// Add a single Error
    pub fn add_error<E: Error>(self, error: E) -> NoticeBuilder<'a> {
        let notice_error = NoticeError::from(error);
        self.add_notice(notice_error.into())
    }

    /// Set the context on the NoticeBuilder
    pub fn context(mut self, context: ContextBuilder) -> NoticeBuilder<'a> {
        self.context = Some(context);
        self
    }

    /// Set the operating_system on the configurations context
    pub fn operating_system(mut self, os: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.operating_system(os);
                Some(c)
            });
        self
    }

    /// Set the hostname on the configurations context
    pub fn hostname(mut self, hostname: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.hostname(hostname);
                Some(c)
            });
        self
    }

    /// Set the language on the configurations context
    pub fn language(mut self, language: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.language(language);
                Some(c)
            });
        self
    }

    /// Set the environment on the configurations context
    pub fn context_environment(mut self, environment: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.environment(environment);
                Some(c)
            });
        self
    }

    /// Set the severity on the configurations context
    pub fn severity(mut self, severity: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.severity(severity);
                Some(c)
            });
        self
    }

    /// Set the version on the configurations context
    pub fn version(mut self, version: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.version(version);
                Some(c)
            });
        self
    }

    /// Set the url on the configurations context
    pub fn url(mut self, url: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.url(url);
                Some(c)
            });
        self
    }

    /// Set the root_directory on the configurations context
    pub fn root_directory(mut self, root_directory: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.root_directory(root_directory);
                Some(c)
            });
        self
    }

    /// Set the user on the configurations context
    pub fn user(mut self, user: ContextUser) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.user(user);
                Some(c)
            });
        self
    }

    /// Set the route on the configurations context
    pub fn route(mut self, route: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.route(route);
                Some(c)
            });
        self
    }

    /// Set the http_method on the configurations context
    pub fn http_method(mut self, http_method: String) -> NoticeBuilder<'a> {
        self.context = self.context
            .clone()
            .or_else(|| Some(Context::builder()))
            .and_then(|mut c| {
                c.http_method(http_method);
                Some(c)
            });
        self
    }

    /// Set the environment on the NoticeBuilder
    pub fn environment(mut self, environment: HashMap<String, String>) -> NoticeBuilder<'a> {
        self.environment = Some(environment);
        self
    }

    /// Add environment to the NoticeBuilder
    /// ```
    /// use airbrake::Notice;
    /// let notice = Notice::builder()
    ///     .add_environment("PORT".to_owned(), "443".to_owned())
    ///     .add_environment("CODE_NAME".to_owned(), "gorilla".to_owned())
    ///     .build();
    /// ```
    pub fn add_environment(mut self, key: String, value: String) -> NoticeBuilder<'a> {
        self.environment = self.environment
            .or_else(|| Some(HashMap::new()))
            .and_then(|mut h| {
                h.insert(key, value);
                Some(h)
            });
        self
    }

    /// Set the environment on the NoticeBuilder
    pub fn session(mut self, session: HashMap<String, String>) -> NoticeBuilder<'a> {
        self.session = Some(session);
        self
    }

    /// Add session to the NoticeBuilder
    /// ```
    /// use airbrake::Notice;
    /// let notice = Notice::builder()
    ///     .add_session("basketId".to_owned(), "123".to_owned())
    ///     .add_session("userId".to_owned(), "456".to_owned())
    ///     .build();
    /// ```
    pub fn add_session(mut self, key: String, value: String) -> NoticeBuilder<'a> {
        self.session = self.session
            .or_else(|| Some(HashMap::new()))
            .and_then(|mut h| {
                h.insert(key, value);
                Some(h)
            });
        self
    }

    /// Set the environment on the NoticeBuilder
    pub fn params(mut self, params: HashMap<String, String>) -> NoticeBuilder<'a> {
        self.params = Some(params);
        self
    }

    /// Add param to the NoticeBuilder
    /// ```
    /// use airbrake::Notice;
    /// let notice = Notice::builder()
    ///     .add_param("page".to_owned(), "3".to_owned())
    ///     .add_param("sort".to_owned(), "name".to_owned())
    ///     .add_param("direction".to_owned(), "asc".to_owned())
    ///     .build();
    /// ```
    pub fn add_param(mut self, key: String, value: String) -> NoticeBuilder<'a> {
        self.params = self.params
            .or_else(|| Some(HashMap::new()))
            .and_then(|mut h| {
                h.insert(key, value);
                Some(h)
            });
        self
    }

    /// Executes the command as a child process, which is returned.
    pub fn build(self) -> Notice<'a> {
        let context = self.context.clone().and_then(|c| Some(c.build()));
        Notice {
            client: self.client,
            errors: self.errors,
            context: context,
            environment: self.environment,
            session: self.session,
            params: self.params
        }
    }
}

/// NoticeBuilder can be produced from a Context
///
/// The context specified in a Notice won't change often, and will typically
/// already exist while creating a new Notice so it only makes sense to
/// begin the Notice construction based on the context.
/// ```
/// use airbrake::{Context, NoticeBuilder};
///
/// let context = Context::builder();
/// let notice_builder = NoticeBuilder::from(&context);
/// ```
impl<'a> From<&ContextBuilder> for NoticeBuilder<'a> {
    fn from(context: &ContextBuilder) -> NoticeBuilder<'a> {
        NoticeBuilder::new().context(context.clone())
    }
}

impl<'a, E: Error> From<E> for NoticeBuilder<'a> {
    fn from(error: E) -> NoticeBuilder<'a> {
        NoticeBuilder::new().add_error(error)
    }
}

#[derive(Debug, Serialize)]
pub struct Notice<'a> {
    #[serde(skip)]
    pub client: Option<&'a AirbrakeClient>,

    pub errors: Vec<NoticeError>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub context: Option<Context>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub environment: Option<HashMap<String, String>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub session: Option<HashMap<String, String>>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub params: Option<HashMap<String, String>>
}

impl<'a> Notice<'a> {
    /// Makes it easy to construct a new Notice
    ///
    /// ```
    /// use airbrake::{Context, Notice};
    ///
    /// let context = Context::builder();
    /// let notice = Notice::builder()
    ///     .context(context)
    ///     .build();
    /// ```
    pub fn builder() -> NoticeBuilder<'a> {
        NoticeBuilder::new()
    }

    pub fn send(self) {
        self.client.and_then(|c| {
            debug!("Sending via notice client");
            c.notify(self);
            Some(c)
        });
    }
}

impl<'a> From<Notice<'a>> for Value {
    fn from(notice: Notice<'a>) -> Value {
        serde_json::json!(notice)
    }
}

impl<'a> Into<Body> for Notice<'a> {
    fn into(self) -> Body {
        Body::from(Value::from(self).to_string())
    }
}

#[cfg(test)]
mod tests {
    use std::str::FromStr;
    use std::collections::HashMap;
    use serde_json::{self, Value};
    use hyper::body::Body;
    use super::{Notice, Context};

    #[test]
    fn notice_default() {
        let notice = Notice::builder().build();
        let expected_json = r#"
        {
            "errors": []
        }
        "#;
        assert_eq!(
            Value::from_str(expected_json).unwrap(),
            Value::from(notice)
        );
    }

    #[test]
    fn notice_with_add_environment() {
        let notice = Notice::builder()
            .add_environment("foo".to_owned(), "bar".to_owned())
            .build();
        let expected_json = r#"
        {
            "errors": [],
            "environment": {
                "foo": "bar"
            }
        }
        "#;
        assert_eq!(
            Value::from_str(expected_json).unwrap(),
            Value::from(notice)
        );
    }

    #[test]
    fn notice_with_set_environment() {
        let mut hashmap = HashMap::new();
        hashmap.insert("foo".to_owned(), "bar".to_owned());
        let notice = Notice::builder()
            .environment(hashmap)
            .build();
        let expected_json = r#"
        {
            "errors": [],
            "environment": {
                "foo": "bar"
            }
        }
        "#;
        assert_eq!(
            Value::from_str(expected_json).unwrap(),
            Value::from(notice)
        );
    }

    #[test]
    fn notice_with_add_session() {
        let notice = Notice::builder()
            .add_session("foo".to_owned(), "bar".to_owned())
            .build();
        let expected_json = r#"
        {
            "errors": [],
            "session": {
                "foo": "bar"
            }
        }
        "#;
        assert_eq!(
            Value::from_str(expected_json).unwrap(),
            Value::from(notice)
        );
    }

    #[test]
    fn notice_with_set_session() {
        let mut hashmap = HashMap::new();
        hashmap.insert("foo".to_owned(), "bar".to_owned());
        let notice = Notice::builder()
            .session(hashmap)
            .build();
        let expected_json = r#"
        {
            "errors": [],
            "session": {
                "foo": "bar"
            }
        }
        "#;
        assert_eq!(
            Value::from_str(expected_json).unwrap(),
            Value::from(notice)
        );
    }

    #[test]
    fn notice_with_add_param() {
        let notice = Notice::builder()
            .add_param("foo".to_owned(), "bar".to_owned())
            .build();
        let expected_json = r#"
        {
            "errors": [],
            "params": {
                "foo": "bar"
            }
        }
        "#;
        assert_eq!(
            Value::from_str(expected_json).unwrap(),
            Value::from(notice)
        );
    }

    #[test]
    fn notice_with_set_params() {
        let mut hashmap = HashMap::new();
        hashmap.insert("foo".to_owned(), "bar".to_owned());
        let notice = Notice::builder()
            .params(hashmap)
            .build();
        let expected_json = r#"
        {
            "errors": [],
            "params": {
                "foo": "bar"
            }
        }
        "#;
        assert_eq!(
            Value::from_str(expected_json).unwrap(),
            Value::from(notice)
        );
    }

    #[test]
    fn notice_context_default() {
        let context = Context::builder();
        let notice = Notice::builder()
            .context(context)
            .build();
        let expected_json = r#"
        {
            "errors": [],
            "context": {
                "notifier": {
                    "name": "airbrake-rust",
                    "version": "0.2.0",
                    "url": "https://github.com/airbrake/airbrake-rust"
                }
            }
        }
        "#;
        assert_eq!(
            Value::from_str(expected_json).unwrap(),
            Value::from(notice)
        );
    }
}<|endoftext|>


<commit_before>use glutin::Window;
use nalgebra::{Isometry3, Perspective3};

use math::{FMatrix4, FPoint2, FPoint3, FScalar, FVector3, IntoSpace, UPoint2, UScalar};

lazy_static! {
    static ref UP: FVector3 = FVector3::z();
}

pub trait AspectRatio {
    fn dimensions(&self) -> (UScalar, UScalar);

    fn aspect_ratio(&self) -> FScalar {
        let (width, height) = self.dimensions();
        width as FScalar / height as FScalar
    }
}

impl AspectRatio for Window {
    fn dimensions(&self) -> (UScalar, UScalar) {
        self.get_inner_size_pixels().unwrap_or((1, 1))
    }
}

pub struct Projection {
    pub fov: FScalar,
    pub near: FScalar,
    pub far: FScalar,
}

impl Projection {
    pub fn new(fov: FScalar, near: FScalar, far: FScalar) -> Self {
        Projection {
            fov: fov,
            near: near,
            far: far,
        }
    }
}

impl Default for Projection {
    fn default() -> Self {
        Projection::new(1.0, -1.0, 1.0)
    }
}

pub struct Camera {
    projection: Perspective3<FScalar>,
    view: Isometry3<FScalar>,
}

impl Camera {
    pub fn new<W>(window: &W, projection: &Projection) -> Self
        where W: AspectRatio
    {
        Camera {
            projection: Perspective3::new(window.aspect_ratio(),
                                          projection.fov,
                                          projection.near,
                                          projection.far),
            view: Isometry3::look_at_rh(&FPoint3::origin(), &FPoint3::new(0.0, 0.0, 1.0), &UP),
        }
    }

    pub fn look_at(&mut self, position: &FPoint3, point: &FPoint3) {
        self.view = Isometry3::look_at_rh(position, point, &UP);
    }

    pub fn cast_ray<W>(&self, window: &W, point: &UPoint2) -> (FPoint3, FVector3)
        where W: AspectRatio
    {
        let point: FPoint2 = (*point).into_space();
        let (width, height) = window.dimensions();
        let inverse = self.view.inverse();
        let near = self.projection.unproject_point(&FPoint3::new(point.x / width as FScalar,
                                                                 point.y / height as FScalar,
                                                                 -1.0));
        let far = self.projection.unproject_point(&FPoint3::new(point.x / width as FScalar,
                                                                point.y / height as FScalar,
                                                                1.0));
        (inverse * near, (inverse * (far - near)).normalize())
    }

    pub fn transform(&self) -> FMatrix4 {
        self.projection() * self.view()
    }

    fn projection(&self) -> &FMatrix4 {
        self.projection.as_matrix()
    }

    fn view(&self) -> FMatrix4 {
        self.view.to_homogeneous()
    }
}
<commit_msg>Implement conversion from `Perspective3` into `Projection`.<commit_after>use glutin::Window;
use nalgebra::{Isometry3, Perspective3};

use math::{FMatrix4, FPoint2, FPoint3, FScalar, FVector3, IntoSpace, UPoint2, UScalar};

lazy_static! {
    static ref UP: FVector3 = FVector3::z();
}

pub trait AspectRatio {
    fn dimensions(&self) -> (UScalar, UScalar);

    fn aspect_ratio(&self) -> FScalar {
        let (width, height) = self.dimensions();
        width as FScalar / height as FScalar
    }
}

impl AspectRatio for Window {
    fn dimensions(&self) -> (UScalar, UScalar) {
        self.get_inner_size_pixels().unwrap_or((1, 1))
    }
}

pub struct Projection {
    pub fov: FScalar,
    pub near: FScalar,
    pub far: FScalar,
}

impl Projection {
    pub fn new(fov: FScalar, near: FScalar, far: FScalar) -> Self {
        Projection {
            fov: fov,
            near: near,
            far: far,
        }
    }
}

impl Default for Projection {
    fn default() -> Self {
        Projection::new(1.0, -1.0, 1.0)
    }
}

impl From<Perspective3<FScalar>> for Projection {
    fn from(perspective: Perspective3<FScalar>) -> Self {
        Projection::new(perspective.fovy(), perspective.znear(), perspective.zfar())
    }
}

pub struct Camera {
    projection: Perspective3<FScalar>,
    view: Isometry3<FScalar>,
}

impl Camera {
    pub fn new<W>(window: &W, projection: &Projection) -> Self
        where W: AspectRatio
    {
        Camera {
            projection: Perspective3::new(window.aspect_ratio(),
                                          projection.fov,
                                          projection.near,
                                          projection.far),
            view: Isometry3::look_at_rh(&FPoint3::origin(), &FPoint3::new(0.0, 0.0, 1.0), &UP),
        }
    }

    pub fn look_at(&mut self, position: &FPoint3, point: &FPoint3) {
        self.view = Isometry3::look_at_rh(position, point, &UP);
    }

    pub fn cast_ray<W>(&self, window: &W, point: &UPoint2) -> (FPoint3, FVector3)
        where W: AspectRatio
    {
        let point: FPoint2 = (*point).into_space();
        let (width, height) = window.dimensions();
        let inverse = self.view.inverse();
        let near = self.projection.unproject_point(&FPoint3::new(point.x / width as FScalar,
                                                                 point.y / height as FScalar,
                                                                 -1.0));
        let far = self.projection.unproject_point(&FPoint3::new(point.x / width as FScalar,
                                                                point.y / height as FScalar,
                                                                1.0));
        (inverse * near, (inverse * (far - near)).normalize())
    }

    pub fn transform(&self) -> FMatrix4 {
        self.projection() * self.view()
    }

    fn projection(&self) -> &FMatrix4 {
        self.projection.as_matrix()
    }

    fn view(&self) -> FMatrix4 {
        self.view.to_homogeneous()
    }
}
<|endoftext|>


<commit_before>use regex::Regex;
use std::collections::hashmap::HashMap;

pub struct Params {
    captures: HashMap<String, String>
}

impl Params {
    pub fn new<I: Iterator<String>>(uri: &str, matcher: Regex, params: I) -> Params {
        let captures = matcher.captures(uri).unwrap();
        Params {
            captures: params.map(|p| (p.clone(), captures.name(p.as_slice()).to_string())).collect()
        }
    }

    pub fn get<'a>(&'a self, param: &'static str) -> Option<String> {
        self.captures.find(&param.to_string()).and_then(|p| Some(p.clone()))
    }
}

#[cfg(test)]
mod test {
    use test::{Bencher, black_box};
    use super::*;
    use super::super::glob::deglob;

    #[test]
    fn test_new() {
        let params = Params::new("/users/7324", deglob("/users/:userid".to_string()), vec!["userid".to_string()].move_iter());
        assert_eq!(params.get("userid").unwrap(), "7324".to_string());
    }

    #[bench]
    fn bench_get(b: &mut Bencher) {
        let params = Params::new("/users/7324", deglob("/users/:userid".to_string()), vec!["userid".to_string()].move_iter());
        b.iter(|| {
            black_box(params.get("userid").unwrap())
        })
    }
}

<commit_msg>(test) Tested two parameters in a single url.<commit_after>use regex::Regex;
use std::collections::hashmap::HashMap;

pub struct Params {
    captures: HashMap<String, String>
}

impl Params {
    pub fn new<I: Iterator<String>>(uri: &str, matcher: Regex, params: I) -> Params {
        let captures = matcher.captures(uri).unwrap();
        Params {
            captures: params.map(|p| (p.clone(), captures.name(p.as_slice()).to_string())).collect()
        }
    }

    pub fn get<'a>(&'a self, param: &'static str) -> Option<String> {
        self.captures.find(&param.to_string()).and_then(|p| Some(p.clone()))
    }
}

#[cfg(test)]
mod test {
    use test::{Bencher, black_box};
    use super::*;
    use super::super::glob::deglob;

    #[test]
    fn test_new() {
        let params = Params::new(
            "/users/7324/235",
            deglob("/users/:userid/:groupid".to_string()),
            vec!["userid".to_string(), "groupid".to_string()].move_iter());
        assert_eq!(params.get("userid").unwrap(), "7324".to_string());
        assert_eq!(params.get("groupid").unwrap(), "235".to_string());
    }

    #[bench]
    fn bench_get(b: &mut Bencher) {
        let params = Params::new("/users/7324", deglob("/users/:userid".to_string()), vec!["userid".to_string()].move_iter());
        b.iter(|| {
            black_box(params.get("userid").unwrap())
        })
    }
}

<|endoftext|>


<commit_before>//! Basic types to build the parsers

use self::IResult::*;
use util::ErrorKind;

#[cfg(feature = "core")]
use std::prelude::v1::*;
use std::boxed::Box;

/// Contains the error that a parser can return
///
/// It can represent a linked list of errors, indicating the path taken in the parsing tree, with corresponding position in the input data.
/// It depends on P, the input position (for a &[u8] parser, it would be a &[u8]), and E, the custom error type (by default, u32)
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Err<P,E=u32>{
  /// An error code, represented by an ErrorKind, which can contain a custom error code represented by E
  Code(ErrorKind<E>),
  /// An error code, and the next error
  Node(ErrorKind<E>, Box<Err<P,E>>),
  /// An error code, and the input position
  Position(ErrorKind<E>, P),
  /// An error code, the input position and the next error
  NodePosition(ErrorKind<E>, P, Box<Err<P,E>>)
}

/// Contains information on needed data if a parser returned `Incomplete`
#[derive(Debug,PartialEq,Eq,Clone,Copy)]
pub enum Needed {
  /// needs more data, but we do not know how much
  Unknown,
  /// contains the required data size
  Size(usize)
}

/// Holds the result of parsing functions
///
/// It depends on I, the input type, O, the output type, and E, the error type (by default u32)
///
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum IResult<I,O,E=u32> {
   /// indicates a correct parsing, the first field containing the rest of the unparsed data, the second field contains the parsed data
  Done(I,O),
  /// contains a Err, an enum that can indicate an error code, a position in the input, and a pointer to another error, making a list of errors in the parsing tree
  Error(Err<I,E>),
  /// Incomplete contains a Needed, an enum than can represent a known quantity of input data, or unknown
  Incomplete(Needed)
}

impl<I,O,E> IResult<I,O,E> {
  pub fn is_done(&self) -> bool {
    match *self {
      Done(_,_) => true,
      _         => false
    }
  }

  pub fn is_err(&self) -> bool {
    match *self {
      Error(_) => true,
      _        => false
    }
  }

  pub fn is_incomplete(&self) -> bool {
    match *self {
      Incomplete(_) => true,
      _             => false
    }
  }
}

pub trait GetInput<I> {
  fn remaining_input(&self) -> Option<I>;
}

pub trait GetOutput<O> {
  fn output(&self) -> Option<O>;
}

impl<'a,I,O,E> GetInput<&'a[I]> for IResult<&'a[I],O,E> {
  fn remaining_input(&self) -> Option<&'a[I]> {
    match *self {
      Done(ref i,_) => Some(*i),
      _             => None
    }
  }
}

impl<O,E> GetInput<()> for IResult<(),O,E> {
  fn remaining_input(&self) -> Option<()> {
    match *self {
      Done((),_) => Some(()),
      _          => None
    }
  }
}

impl<'a,O,E> GetInput<&'a str> for IResult<&'a str,O,E> {
  fn remaining_input(&self) -> Option<&'a str> {
    match *self {
      Done(ref i,_) => Some(*i),
      _          => None
    }
  }
}

impl<'a,I,O,E> GetOutput<&'a[O]> for IResult<I,&'a[O],E> {
  fn output(&self) -> Option<&'a[O]> {
    match *self {
      Done(_, ref o) => Some(*o),
      _              => None
    }
  }
}

impl<I,E> GetOutput<()> for IResult<I,(),E> {
  fn output(&self) -> Option<()> {
    match *self {
      Done(_,()) => Some(()),
      _          => None
    }
  }
}

impl<'a,I,E> GetOutput<&'a str> for IResult<I,&'a str,E> {
  fn output(&self) -> Option<&'a str> {
    match *self {
      Done(_,ref o) => Some(*o),
      _          => None
    }
  }
}
<commit_msg>Add `IResult::map` for output manipulation<commit_after>//! Basic types to build the parsers

use self::IResult::*;
use util::ErrorKind;

#[cfg(feature = "core")]
use std::prelude::v1::*;
use std::boxed::Box;

/// Contains the error that a parser can return
///
/// It can represent a linked list of errors, indicating the path taken in the parsing tree, with corresponding position in the input data.
/// It depends on P, the input position (for a &[u8] parser, it would be a &[u8]), and E, the custom error type (by default, u32)
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Err<P,E=u32>{
  /// An error code, represented by an ErrorKind, which can contain a custom error code represented by E
  Code(ErrorKind<E>),
  /// An error code, and the next error
  Node(ErrorKind<E>, Box<Err<P,E>>),
  /// An error code, and the input position
  Position(ErrorKind<E>, P),
  /// An error code, the input position and the next error
  NodePosition(ErrorKind<E>, P, Box<Err<P,E>>)
}

/// Contains information on needed data if a parser returned `Incomplete`
#[derive(Debug,PartialEq,Eq,Clone,Copy)]
pub enum Needed {
  /// needs more data, but we do not know how much
  Unknown,
  /// contains the required data size
  Size(usize)
}

/// Holds the result of parsing functions
///
/// It depends on I, the input type, O, the output type, and E, the error type (by default u32)
///
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum IResult<I,O,E=u32> {
   /// indicates a correct parsing, the first field containing the rest of the unparsed data, the second field contains the parsed data
  Done(I,O),
  /// contains a Err, an enum that can indicate an error code, a position in the input, and a pointer to another error, making a list of errors in the parsing tree
  Error(Err<I,E>),
  /// Incomplete contains a Needed, an enum than can represent a known quantity of input data, or unknown
  Incomplete(Needed)
}

impl<I,O,E> IResult<I,O,E> {
  pub fn is_done(&self) -> bool {
    match *self {
      Done(_,_) => true,
      _         => false
    }
  }

  pub fn is_err(&self) -> bool {
    match *self {
      Error(_) => true,
      _        => false
    }
  }

  pub fn is_incomplete(&self) -> bool {
    match *self {
      Incomplete(_) => true,
      _             => false
    }
  }

  #[inline]
  pub fn map<N, F: FnOnce(O) -> N>(self, f: F) -> IResult<I, N, E> {
    match self {
      Done(i, o)    => Done(i, f(o)),
      Error(e)      => Error(e),
      Incomplete(n) => Incomplete(n),
    }
  }
}

pub trait GetInput<I> {
  fn remaining_input(&self) -> Option<I>;
}

pub trait GetOutput<O> {
  fn output(&self) -> Option<O>;
}

impl<'a,I,O,E> GetInput<&'a[I]> for IResult<&'a[I],O,E> {
  fn remaining_input(&self) -> Option<&'a[I]> {
    match *self {
      Done(ref i,_) => Some(*i),
      _             => None
    }
  }
}

impl<O,E> GetInput<()> for IResult<(),O,E> {
  fn remaining_input(&self) -> Option<()> {
    match *self {
      Done((),_) => Some(()),
      _          => None
    }
  }
}

impl<'a,O,E> GetInput<&'a str> for IResult<&'a str,O,E> {
  fn remaining_input(&self) -> Option<&'a str> {
    match *self {
      Done(ref i,_) => Some(*i),
      _          => None
    }
  }
}

impl<'a,I,O,E> GetOutput<&'a[O]> for IResult<I,&'a[O],E> {
  fn output(&self) -> Option<&'a[O]> {
    match *self {
      Done(_, ref o) => Some(*o),
      _              => None
    }
  }
}

impl<I,E> GetOutput<()> for IResult<I,(),E> {
  fn output(&self) -> Option<()> {
    match *self {
      Done(_,()) => Some(()),
      _          => None
    }
  }
}

impl<'a,I,E> GetOutput<&'a str> for IResult<I,&'a str,E> {
  fn output(&self) -> Option<&'a str> {
    match *self {
      Done(_,ref o) => Some(*o),
      _          => None
    }
  }
}
<|endoftext|>


<commit_before>//! Keyboard utility functions; allow querying state of keyboard keys and modifiers.
//!
//! Example:
//!
//! ```rust, no-run
//! use ggez::event::{EventHandler, KeyCode, KeyMods};
//! use ggez::{graphics, keyboard, nalgebra as na, timer};
//! use ggez::{Context, GameResult};
//!
//! struct MainState {
//!     position_x: f32,
//! }
//!
//! impl EventHandler for MainState {
//!     fn update(&mut self, ctx: &mut Context) -> GameResult {
//!         // Increase or decrease `position_x` by 0.5, or by 5.0 if Shift is held.
//!         if keyboard::is_key_pressed(ctx, KeyCode::Right) {
//!             if keyboard::is_mod_active(ctx, KeyMods::SHIFT) {
//!                 self.position_x += 4.5;
//!             }
//!             self.position_x += 0.5;
//!         } else if keyboard::is_key_pressed(ctx, KeyCode::Left) {
//!             if keyboard::is_mod_active(ctx, KeyMods::SHIFT) {
//!                 self.position_x -= 4.5;
//!             }
//!             self.position_x -= 0.5;
//!         }
//!         Ok(())
//!     }
//!
//!     fn draw(&mut self, ctx: &mut Context) -> GameResult {
//!         graphics::clear(ctx, [0.1, 0.2, 0.3, 1.0].into());
//!         // Draw a circle at `position_x`.
//!         graphics::circle(
//!             ctx,
//!             graphics::WHITE,
//!             graphics::DrawMode::Fill,
//!             na::Point2::new(self.position_x, 380.0),
//!             100.0,
//!             2.0,
//!         )?;
//!         graphics::present(ctx)?;
//!         timer::yield_now();
//!         Ok(())
//!     }
//!
//!     fn key_down_event(&mut self, ctx: &mut Context, key: KeyCode, mods: KeyMods, _: bool) {
//!         match key {
//!             // Quit if Shift+Ctrl+Q is pressed.
//!             KeyCode::Q => {
//!                 if mods.contains(KeyMods::SHIFT | KeyMods::CTRL) {
//!                     println!("Terminating!");
//!                     ctx.quit();
//!                 } else if mods.contains(KeyMods::SHIFT) || mods.contains(KeyMods::CTRL) {
//!                     println!("You need to hold both Shift and Control to quit.");
//!                 } else {
//!                     println!("Now you're not even trying!");
//!                 }
//!             }
//!             _ => (),
//!         }
//!     }
//! }
//! ```

use context::Context;

/// A key code.
pub use winit::VirtualKeyCode as KeyCode;
use winit::ModifiersState;

bitflags! {
    /// Bitflags describing state of keyboard modifiers, such as Control or Shift.
    #[derive(Default)]
    pub struct KeyMods: u8 {
        /// No modifiers; equivalent to `KeyMods::default()` and `KeyMods::empty()`.
        const NONE  = 0b00000000;
        /// Left or right Shift key.
        const SHIFT = 0b00000001;
        /// Left or right Control key.
        const CTRL  = 0b00000010;
        /// Left or right Alt key.
        const ALT   = 0b00000100;
        /// Left or right Win/Cmd/equivalent key.
        const LOGO  = 0b00001000;
    }
}

impl From<ModifiersState> for KeyMods {
    fn from(state: ModifiersState) -> Self {
        let mut keymod = KeyMods::empty();
        if state.shift {
            keymod |= Self::SHIFT;
        }
        if state.ctrl {
            keymod |= Self::CTRL;
        }
        if state.alt {
            keymod |= Self::ALT;
        }
        if state.logo {
            keymod |= Self::LOGO;
        }
        keymod
    }
}

/// Tracks held down keyboard keys, active keyboard modifiers,
/// and figures out if the system is sending repeat keystrokes.
#[derive(Clone, Debug)]
pub struct KeyboardContext {
    active_modifiers: KeyMods,
    /// A simple mapping of which key code has been pressed.
    /// KeyCode's are a c-like enum, and so can be converted to/from
    /// simple integers.
    /// As of winit 0.16 this is Big Enough For Anyone; assertions
    /// will check if that assumption gets violated
    pressed_keys: Vec<bool>,
    last_pressed: Option<KeyCode>,
}

impl KeyboardContext {
    pub(crate) fn new() -> Self {
        // We reserve a fixed-size vec because we never want to have
        // to bother resizing it, but it is not easy to ask
        // Rust what an enum's max member is and a Sufficiently Big
        // fixed-size array `[bool; MAX_KEY_IDX]` doesn't implement
        // nice things like Debug.  :|
        const MAX_KEY_IDX: usize = 256;
        let mut key_vec =  Vec::with_capacity(MAX_KEY_IDX);
        key_vec.resize(MAX_KEY_IDX, false);
        Self {
            active_modifiers: KeyMods::empty(),
            pressed_keys: key_vec,
            last_pressed: None,
        }
    }

    // TODO: Set modifiers correctly
    // and in general cmake sure this is hooked up correctly
    // from Context::process_event().
    // Looks like it is, but, not 100% sure.
    pub(crate) fn set_key(&mut self, key: KeyCode, pressed: bool) {
        let key_idx = key as usize;
        assert!(key_idx < self.pressed_keys.len());
        self.pressed_keys[key_idx] = pressed;
        if pressed {
            self.last_pressed = Some(key);
        } else {
            // Double check that this edge handling is necessary;
            // winit sounds like it should do this for us,
            // see https://docs.rs/winit/0.16.1/winit/struct.KeyboardInput.html#structfield.modifiers
            match key {
                KeyCode::LShift | KeyCode::RShift => self.active_modifiers -= KeyMods::SHIFT,
                KeyCode::LControl | KeyCode::RControl => self.active_modifiers -= KeyMods::CTRL,
                KeyCode::LAlt | KeyCode::RAlt => self.active_modifiers -= KeyMods::ALT,
                KeyCode::LWin | KeyCode::RWin => self.active_modifiers -= KeyMods::LOGO,
                _ => (),
            }
        }
    }

    // TODO: Merge into set_key?
    pub(crate) fn set_modifiers(&mut self, keymods: KeyMods) {
        self.active_modifiers = keymods;
    }

    pub(crate) fn is_key_pressed(&self, key: KeyCode) -> bool {
        let key_idx = key as usize;
        assert!(key_idx < self.pressed_keys.len());
        self.pressed_keys[key_idx]
    }

    pub(crate) fn is_key_repeated(&self) -> bool {
        if let Some(key) = self.last_pressed {
            self.is_key_pressed(key)
        } else {
            false
        }
    }

    pub(crate) fn get_pressed_keys(&self) -> Vec<KeyCode> {
        self.pressed_keys.iter()
            .enumerate()
            .filter_map(|(key_idx, b)| {
                if *b {
                    // Sigh
                    // Horrible unsafe pointer cast to turn a number
                    // into the matching KeyCode, because Rust's support
                    // for C-like numeric enums is UTTER GARBAGE.
                    // TODO: Can we protect this with an assertion somehow?
                    let keycode: &KeyCode = unsafe {
                        &*(&key_idx as *const usize as *const KeyCode)
                    };
                    Some(*keycode)
                } else {
                    None
                }
            })
            .collect()
    }

    pub(crate) fn get_active_mods(&self) -> KeyMods {
        self.active_modifiers
    }
}

impl Default for KeyboardContext {
    fn default() -> Self {
        Self::new()
    }
}

/// Checks if a key is currently pressed down.
pub fn is_key_pressed(ctx: &Context, key: KeyCode) -> bool {
    ctx.keyboard_context.is_key_pressed(key)
}

/// Checks if the last keystroke sent by the system is repeated,
/// like when a key is held down for a period of time.
pub fn is_key_repeated(ctx: &Context) -> bool {
    ctx.keyboard_context.is_key_repeated()
}

/// Returns a slice with currently pressed down keys.
pub fn get_pressed_keys(ctx: &Context) -> Vec<KeyCode> {
    ctx.keyboard_context.get_pressed_keys()
}

/// Checks if keyboard modifier (or several) is active.
pub fn is_mod_active(ctx: &Context, keymods: KeyMods) -> bool {
    ctx.keyboard_context.get_active_mods().contains(keymods)
}

/// Returns currently active keyboard modifiers.
pub fn get_active_mods(ctx: &Context) -> KeyMods {
    ctx.keyboard_context.get_active_mods()
}

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

    #[test]
    fn key_mod_conversions() {
        assert_eq!(
            KeyMods::empty(),
            KeyMods::from(ModifiersState {
                shift: false,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT | KeyMods::ALT,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: false,
                alt: true,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT | KeyMods::ALT | KeyMods::CTRL,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: true,
                alt: true,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT - KeyMods::ALT,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
        assert_eq!(
            (KeyMods::SHIFT | KeyMods::ALT) - KeyMods::ALT,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT - (KeyMods::ALT | KeyMods::SHIFT),
            KeyMods::from(ModifiersState {
                shift: false,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
    }

    #[test]
    fn pressed_keys_tracking() {
        let mut keyboard = KeyboardContext::new();
        assert_eq!(keyboard.get_pressed_keys(), &[]);
        assert!(!keyboard.is_key_pressed(KeyCode::A));
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.get_pressed_keys(), &[KeyCode::A]);
        assert!(keyboard.is_key_pressed(KeyCode::A));
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.get_pressed_keys(), &[]);
        assert!(!keyboard.is_key_pressed(KeyCode::A));
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.get_pressed_keys(), &[KeyCode::A]);
        assert!(keyboard.is_key_pressed(KeyCode::A));
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.get_pressed_keys(), &[KeyCode::A]);
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.get_pressed_keys(), &[KeyCode::A, KeyCode::B]);
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.get_pressed_keys(), &[KeyCode::A, KeyCode::B]);
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.get_pressed_keys(), &[KeyCode::B]);
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.get_pressed_keys(), &[KeyCode::B]);
        keyboard.set_key(KeyCode::B, false);
        assert_eq!(keyboard.get_pressed_keys(), &[]);
    }

    #[test]
    fn repeated_keys_tracking() {
        let mut keyboard = KeyboardContext::new();
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), true);
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), true);
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.is_key_repeated(), true);
    }
}
<commit_msg>Update keyboard module docs a bit.<commit_after>//! Keyboard utility functions; allow querying state of keyboard keys and modifiers.
//!
//! Example:
//!
//! ```rust, no-run
//! use ggez::event::{EventHandler, KeyCode, KeyMods};
//! use ggez::{graphics, keyboard, nalgebra as na, timer};
//! use ggez::{Context, GameResult};
//!
//! struct MainState {
//!     position_x: f32,
//! }
//!
//! impl EventHandler for MainState {
//!     fn update(&mut self, ctx: &mut Context) -> GameResult {
//!         // Increase or decrease `position_x` by 0.5, or by 5.0 if Shift is held.
//!         if keyboard::is_key_pressed(ctx, KeyCode::Right) {
//!             if keyboard::is_mod_active(ctx, KeyMods::SHIFT) {
//!                 self.position_x += 4.5;
//!             }
//!             self.position_x += 0.5;
//!         } else if keyboard::is_key_pressed(ctx, KeyCode::Left) {
//!             if keyboard::is_mod_active(ctx, KeyMods::SHIFT) {
//!                 self.position_x -= 4.5;
//!             }
//!             self.position_x -= 0.5;
//!         }
//!         Ok(())
//!     }
//!
//!     fn draw(&mut self, ctx: &mut Context) -> GameResult {
//!         graphics::clear(ctx, [0.1, 0.2, 0.3, 1.0].into());
//!         // Draw a circle at `position_x`.
//!         graphics::circle(
//!             ctx,
//!             graphics::WHITE,
//!             graphics::DrawMode::Fill,
//!             na::Point2::new(self.position_x, 380.0),
//!             100.0,
//!             2.0,
//!         )?;
//!         graphics::present(ctx)?;
//!         timer::yield_now();
//!         Ok(())
//!     }
//!
//!     fn key_down_event(&mut self, ctx: &mut Context, key: KeyCode, mods: KeyMods, _: bool) {
//!         match key {
//!             // Quit if Shift+Ctrl+Q is pressed.
//!             KeyCode::Q => {
//!                 if mods.contains(KeyMods::SHIFT | KeyMods::CTRL) {
//!                     println!("Terminating!");
//!                     ctx.quit();
//!                 } else if mods.contains(KeyMods::SHIFT) || mods.contains(KeyMods::CTRL) {
//!                     println!("You need to hold both Shift and Control to quit.");
//!                 } else {
//!                     println!("Now you're not even trying!");
//!                 }
//!             }
//!             _ => (),
//!         }
//!     }
//! }
//! ```

use context::Context;

/// A key code.
pub use winit::VirtualKeyCode as KeyCode;
use winit::ModifiersState;

bitflags! {
    /// Bitflags describing state of keyboard modifiers, such as Control or Shift.
    #[derive(Default)]
    pub struct KeyMods: u8 {
        /// No modifiers; equivalent to `KeyMods::default()` and `KeyMods::empty()`.
        const NONE  = 0b00000000;
        /// Left or right Shift key.
        const SHIFT = 0b00000001;
        /// Left or right Control key.
        const CTRL  = 0b00000010;
        /// Left or right Alt key.
        const ALT   = 0b00000100;
        /// Left or right Win/Cmd/equivalent key.
        const LOGO  = 0b00001000;
    }
}

impl From<ModifiersState> for KeyMods {
    fn from(state: ModifiersState) -> Self {
        let mut keymod = KeyMods::empty();
        if state.shift {
            keymod |= Self::SHIFT;
        }
        if state.ctrl {
            keymod |= Self::CTRL;
        }
        if state.alt {
            keymod |= Self::ALT;
        }
        if state.logo {
            keymod |= Self::LOGO;
        }
        keymod
    }
}

/// Tracks held down keyboard keys, active keyboard modifiers,
/// and figures out if the system is sending repeat keystrokes.
#[derive(Clone, Debug)]
pub struct KeyboardContext {
    active_modifiers: KeyMods,
    /// A simple mapping of which key code has been pressed.
    /// KeyCode's are a c-like enum, and so can be converted to/from
    /// simple integers.
    /// As of winit 0.16 this is Big Enough For Anyone; assertions
    /// will check if that assumption gets violated
    pressed_keys: Vec<bool>,
    last_pressed: Option<KeyCode>,
}

impl KeyboardContext {
    pub(crate) fn new() -> Self {
        // We reserve a fixed-size vec because we never want to have
        // to bother resizing it, but it is not easy to ask
        // Rust what an enum's max member is and a Sufficiently Big
        // fixed-size array `[bool; MAX_KEY_IDX]` doesn't implement
        // nice things like Debug.  :|
        // We have an assert everywhere pressed_keys is accessed so
        // we know if this assumption is broken.
        const MAX_KEY_IDX: usize = 256;
        let mut key_vec =  Vec::with_capacity(MAX_KEY_IDX);
        key_vec.resize(MAX_KEY_IDX, false);
        Self {
            active_modifiers: KeyMods::empty(),
            pressed_keys: key_vec,
            last_pressed: None,
        }
    }

    // TODO: Set modifiers correctly
    // and in general cmake sure this is hooked up correctly
    // from Context::process_event().
    // Looks like it is, but, not 100% sure.
    pub(crate) fn set_key(&mut self, key: KeyCode, pressed: bool) {
        let key_idx = key as usize;
        assert!(key_idx < self.pressed_keys.len(), "Impossible KeyCode detected!");
        self.pressed_keys[key_idx] = pressed;
        if pressed {
            self.last_pressed = Some(key);
        } else {
            // Double check that this edge handling is necessary;
            // winit sounds like it should do this for us,
            // see https://docs.rs/winit/0.16.1/winit/struct.KeyboardInput.html#structfield.modifiers
            match key {
                KeyCode::LShift | KeyCode::RShift => self.active_modifiers -= KeyMods::SHIFT,
                KeyCode::LControl | KeyCode::RControl => self.active_modifiers -= KeyMods::CTRL,
                KeyCode::LAlt | KeyCode::RAlt => self.active_modifiers -= KeyMods::ALT,
                KeyCode::LWin | KeyCode::RWin => self.active_modifiers -= KeyMods::LOGO,
                _ => (),
            }
        }
    }

    // TODO: Merge into set_key?
    pub(crate) fn set_modifiers(&mut self, keymods: KeyMods) {
        self.active_modifiers = keymods;
    }

    pub(crate) fn is_key_pressed(&self, key: KeyCode) -> bool {
        let key_idx = key as usize;
        assert!(key_idx < self.pressed_keys.len(), "Impossible KeyCode detected!");
        self.pressed_keys[key_idx]
    }

    pub(crate) fn is_key_repeated(&self) -> bool {
        if let Some(key) = self.last_pressed {
            self.is_key_pressed(key)
        } else {
            false
        }
    }

    pub(crate) fn get_pressed_keys(&self) -> Vec<KeyCode> {
        self.pressed_keys.iter()
            .enumerate()
            .filter_map(|(key_idx, b)| {
                if *b {
                    // Sigh
                    // Horrible unsafe pointer cast to turn a number
                    // into the matching KeyCode, because Rust's support
                    // for C-like numeric enums is UTTER GARBAGE.
                    // TODO: Can we protect this with an assertion somehow?
                    let keycode: &KeyCode = unsafe {
                        &*(&key_idx as *const usize as *const KeyCode)
                    };
                    Some(*keycode)
                } else {
                    None
                }
            })
            .collect()
    }

    pub(crate) fn get_active_mods(&self) -> KeyMods {
        self.active_modifiers
    }
}

impl Default for KeyboardContext {
    fn default() -> Self {
        Self::new()
    }
}

/// Checks if a key is currently pressed down.
pub fn is_key_pressed(ctx: &Context, key: KeyCode) -> bool {
    ctx.keyboard_context.is_key_pressed(key)
}

/// Checks if the last keystroke sent by the system is repeated,
/// like when a key is held down for a period of time.
pub fn is_key_repeated(ctx: &Context) -> bool {
    ctx.keyboard_context.is_key_repeated()
}

/// Returns a Vec with currently pressed keys.
pub fn get_pressed_keys(ctx: &Context) -> Vec<KeyCode> {
    ctx.keyboard_context.get_pressed_keys()
}

/// Checks if keyboard modifier (or several) is active.
pub fn is_mod_active(ctx: &Context, keymods: KeyMods) -> bool {
    ctx.keyboard_context.get_active_mods().contains(keymods)
}

/// Returns currently active keyboard modifiers.
pub fn get_active_mods(ctx: &Context) -> KeyMods {
    ctx.keyboard_context.get_active_mods()
}

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

    #[test]
    fn key_mod_conversions() {
        assert_eq!(
            KeyMods::empty(),
            KeyMods::from(ModifiersState {
                shift: false,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT | KeyMods::ALT,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: false,
                alt: true,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT | KeyMods::ALT | KeyMods::CTRL,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: true,
                alt: true,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT - KeyMods::ALT,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
        assert_eq!(
            (KeyMods::SHIFT | KeyMods::ALT) - KeyMods::ALT,
            KeyMods::from(ModifiersState {
                shift: true,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
        assert_eq!(
            KeyMods::SHIFT - (KeyMods::ALT | KeyMods::SHIFT),
            KeyMods::from(ModifiersState {
                shift: false,
                ctrl: false,
                alt: false,
                logo: false,
            })
        );
    }

    #[test]
    fn pressed_keys_tracking() {
        let mut keyboard = KeyboardContext::new();
        assert_eq!(keyboard.get_pressed_keys(), &[]);
        assert!(!keyboard.is_key_pressed(KeyCode::A));
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.get_pressed_keys(), &[KeyCode::A]);
        assert!(keyboard.is_key_pressed(KeyCode::A));
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.get_pressed_keys(), &[]);
        assert!(!keyboard.is_key_pressed(KeyCode::A));
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.get_pressed_keys(), &[KeyCode::A]);
        assert!(keyboard.is_key_pressed(KeyCode::A));
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.get_pressed_keys(), &[KeyCode::A]);
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.get_pressed_keys(), &[KeyCode::A, KeyCode::B]);
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.get_pressed_keys(), &[KeyCode::A, KeyCode::B]);
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.get_pressed_keys(), &[KeyCode::B]);
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.get_pressed_keys(), &[KeyCode::B]);
        keyboard.set_key(KeyCode::B, false);
        assert_eq!(keyboard.get_pressed_keys(), &[]);
    }

    #[test]
    fn repeated_keys_tracking() {
        let mut keyboard = KeyboardContext::new();
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), true);
        keyboard.set_key(KeyCode::A, false);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::A, true);
        assert_eq!(keyboard.is_key_repeated(), true);
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.is_key_repeated(), false);
        keyboard.set_key(KeyCode::B, true);
        assert_eq!(keyboard.is_key_repeated(), true);
    }
}
<|endoftext|>


<commit_before>import rustrt.sbuf;

import std._vec.rustrt.vbuf;

native "rust" mod rustrt {
    type sbuf;
    fn str_buf(str s) -> sbuf;
    fn str_byte_len(str s) -> uint;
    fn str_alloc(uint n_bytes) -> str;
    fn str_from_vec(vec[u8] b) -> str;
    fn refcount[T](str s) -> uint;
}

fn eq(&str a, &str b) -> bool {
    let uint i = byte_len(a);
    if (byte_len(b) != i) {
        ret false;
    }
    while (i > 0u) {
        i -= 1u;
        auto cha = a.(i);
        auto chb = b.(i);
        if (cha != chb) {
            ret false;
        }
    }
    ret true;
}

fn lteq(&str a, &str b) -> bool {
    let uint i = byte_len(a);
    let uint j = byte_len(b);
    let uint n = i;
    if (j < n) {
        n = j;
    }

    let uint x = 0u;
    while (x < n) {
        auto cha = a.(x);
        auto chb = b.(x);
        if (cha <= chb) {
            ret true;
        }
        else if (cha > chb) {
            ret false;
        }
        x += 1u;
    }

    ret i <= j;
}

fn hash(&str s) -> uint {
    // djb hash.
    // FIXME: replace with murmur.
    let uint u = 5381u;
    for (u8 c in s) {
        u *= 33u;
        u += (c as uint);
    }
    ret u;
}

fn is_utf8(vec[u8] v) -> bool {
    fail; // FIXME
}

fn is_ascii(str s) -> bool {
    let uint i = byte_len(s);
    while (i > 0u) {
        i -= 1u;
        if ((s.(i) & 0x80u8) != 0u8) {
            ret false;
        }
    }
    ret true;
}

fn alloc(uint n_bytes) -> str {
    ret rustrt.str_alloc(n_bytes);
}

// Returns the number of bytes (a.k.a. UTF-8 code units) in s.
// Contrast with a function that would return the number of code
// points (char's), combining character sequences, words, etc.  See
// http://icu-project.org/apiref/icu4c/classBreakIterator.html for a
// way to implement those.
fn byte_len(str s) -> uint {
    ret rustrt.str_byte_len(s);
}

fn buf(str s) -> sbuf {
    ret rustrt.str_buf(s);
}

fn bytes(str s) -> vec[u8] {
    /* FIXME (issue #58):
     * Should be...
     *
     *  fn ith(str s, uint i) -> u8 {
     *      ret s.(i);
     *  }
     *  ret _vec.init_fn[u8](bind ith(s, _), byte_len(s));
     *
     * but we do not correctly decrement refcount of s when
     * the binding dies, so we have to do this manually.
     */
    let uint n = _str.byte_len(s);
    let vec[u8] v = _vec.alloc[u8](n);
    let uint i = 0u;
    while (i < n) {
        v += vec(s.(i));
        i += 1u;
    }
    ret v;
}

fn from_bytes(vec[u8] v) : is_utf8(v) -> str {
    ret rustrt.str_from_vec(v);
}

fn refcount(str s) -> uint {
    auto r = rustrt.refcount[u8](s);
    if (r == dbg.const_refcount) {
        ret r;
    } else {
        // -1 because calling this function incremented the refcount.
        ret  r - 1u;
    }
}

// Standard bits from the world of string libraries.

fn index(str s, u8 c) -> int {
    let int i = 0;
    for (u8 k in s) {
        if (k == c) {
            ret i;
        }
        i += 1;
    }
    ret -1;
}

fn rindex(str s, u8 c) -> int {
    let int n = _str.byte_len(s) as int;
    while (n >= 0) {
        if (s.(n) == c) {
            ret n;
        }
        n -= 1;
    }
    ret n;
}

fn find(str haystack, str needle) -> int {

    let int haystack_len = byte_len(haystack) as int;
    let int needle_len = byte_len(needle) as int;

    if (needle_len == 0) {
        ret 0;
    }

    fn match_at(&str haystack,
                &str needle,
                int i) -> bool {
        let int j = i;
        for (u8 c in needle) {
            if (haystack.(j) != c) {
                ret false;
            }
            j += 1;
        }
        ret true;
    }

    let int i = 0;
    while (i <= haystack_len - needle_len) {
        if (match_at(haystack, needle, i)) {
            ret i;
        }
        i += 1;
    }
    ret  -1;
}

fn substr(str s, uint begin, uint len) -> str {
    let str accum = "";
    let uint i = begin;
    while (i < begin+len) {
        accum += s.(i);
        i += 1u;
    }
    ret accum;
}

fn split(str s, u8 sep) -> vec[str] {
    let vec[str] v = vec();
    let str accum = "";
    let bool ends_with_sep = false;
    for (u8 c in s) {
        if (c == sep) {
            v += accum;
            accum = "";
            ends_with_sep = true;
        } else {
            accum += c;
            ends_with_sep = false;
        }
    }
    if (_str.byte_len(accum) != 0u ||
        ends_with_sep) {
        v += accum;
    }
    ret v;
}

fn concat(vec[str] v) -> str {
    let str s = "";
    for (str ss in v) {
        s += ss;
    }
    ret s;
}

fn connect(vec[str] v, str sep) -> str {
    let str s = "";
    let bool first = true;
    for (str ss in v) {
        if (first) {
            first = false;
        } else {
            s += sep;
        }
        s += ss;
    }
    ret s;
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Add _str.starts_with and ends_with.<commit_after>import rustrt.sbuf;

import std._vec.rustrt.vbuf;

native "rust" mod rustrt {
    type sbuf;
    fn str_buf(str s) -> sbuf;
    fn str_byte_len(str s) -> uint;
    fn str_alloc(uint n_bytes) -> str;
    fn str_from_vec(vec[u8] b) -> str;
    fn refcount[T](str s) -> uint;
}

fn eq(&str a, &str b) -> bool {
    let uint i = byte_len(a);
    if (byte_len(b) != i) {
        ret false;
    }
    while (i > 0u) {
        i -= 1u;
        auto cha = a.(i);
        auto chb = b.(i);
        if (cha != chb) {
            ret false;
        }
    }
    ret true;
}

fn lteq(&str a, &str b) -> bool {
    let uint i = byte_len(a);
    let uint j = byte_len(b);
    let uint n = i;
    if (j < n) {
        n = j;
    }

    let uint x = 0u;
    while (x < n) {
        auto cha = a.(x);
        auto chb = b.(x);
        if (cha <= chb) {
            ret true;
        }
        else if (cha > chb) {
            ret false;
        }
        x += 1u;
    }

    ret i <= j;
}

fn hash(&str s) -> uint {
    // djb hash.
    // FIXME: replace with murmur.
    let uint u = 5381u;
    for (u8 c in s) {
        u *= 33u;
        u += (c as uint);
    }
    ret u;
}

fn is_utf8(vec[u8] v) -> bool {
    fail; // FIXME
}

fn is_ascii(str s) -> bool {
    let uint i = byte_len(s);
    while (i > 0u) {
        i -= 1u;
        if ((s.(i) & 0x80u8) != 0u8) {
            ret false;
        }
    }
    ret true;
}

fn alloc(uint n_bytes) -> str {
    ret rustrt.str_alloc(n_bytes);
}

// Returns the number of bytes (a.k.a. UTF-8 code units) in s.
// Contrast with a function that would return the number of code
// points (char's), combining character sequences, words, etc.  See
// http://icu-project.org/apiref/icu4c/classBreakIterator.html for a
// way to implement those.
fn byte_len(str s) -> uint {
    ret rustrt.str_byte_len(s);
}

fn buf(str s) -> sbuf {
    ret rustrt.str_buf(s);
}

fn bytes(str s) -> vec[u8] {
    /* FIXME (issue #58):
     * Should be...
     *
     *  fn ith(str s, uint i) -> u8 {
     *      ret s.(i);
     *  }
     *  ret _vec.init_fn[u8](bind ith(s, _), byte_len(s));
     *
     * but we do not correctly decrement refcount of s when
     * the binding dies, so we have to do this manually.
     */
    let uint n = _str.byte_len(s);
    let vec[u8] v = _vec.alloc[u8](n);
    let uint i = 0u;
    while (i < n) {
        v += vec(s.(i));
        i += 1u;
    }
    ret v;
}

fn from_bytes(vec[u8] v) : is_utf8(v) -> str {
    ret rustrt.str_from_vec(v);
}

fn refcount(str s) -> uint {
    auto r = rustrt.refcount[u8](s);
    if (r == dbg.const_refcount) {
        ret r;
    } else {
        // -1 because calling this function incremented the refcount.
        ret  r - 1u;
    }
}

// Standard bits from the world of string libraries.

fn index(str s, u8 c) -> int {
    let int i = 0;
    for (u8 k in s) {
        if (k == c) {
            ret i;
        }
        i += 1;
    }
    ret -1;
}

fn rindex(str s, u8 c) -> int {
    let int n = _str.byte_len(s) as int;
    while (n >= 0) {
        if (s.(n) == c) {
            ret n;
        }
        n -= 1;
    }
    ret n;
}

fn find(str haystack, str needle) -> int {

    let int haystack_len = byte_len(haystack) as int;
    let int needle_len = byte_len(needle) as int;

    if (needle_len == 0) {
        ret 0;
    }

    fn match_at(&str haystack,
                &str needle,
                int i) -> bool {
        let int j = i;
        for (u8 c in needle) {
            if (haystack.(j) != c) {
                ret false;
            }
            j += 1;
        }
        ret true;
    }

    let int i = 0;
    while (i <= haystack_len - needle_len) {
        if (match_at(haystack, needle, i)) {
            ret i;
        }
        i += 1;
    }
    ret  -1;
}

fn starts_with(str haystack, str needle) -> bool {
    let uint haystack_len = byte_len(haystack);
    let uint needle_len = byte_len(needle);
    if (needle_len == 0u) {
        ret true;
    }
    if (needle_len > haystack_len) {
        ret false;
    }
    ret eq(substr(haystack, 0u, needle_len), needle);
}

fn ends_with(str haystack, str needle) -> bool {
    let uint haystack_len = byte_len(haystack);
    let uint needle_len = byte_len(needle);
    if (needle_len == 0u) {
        ret true;
    }
    if (needle_len > haystack_len) {
        ret false;
    }
    ret eq(substr(haystack,
                  haystack_len - needle_len,
                  needle_len),
           needle);
}

fn substr(str s, uint begin, uint len) -> str {
    let str accum = "";
    let uint i = begin;
    while (i < begin+len) {
        accum += s.(i);
        i += 1u;
    }
    ret accum;
}

fn split(str s, u8 sep) -> vec[str] {
    let vec[str] v = vec();
    let str accum = "";
    let bool ends_with_sep = false;
    for (u8 c in s) {
        if (c == sep) {
            v += accum;
            accum = "";
            ends_with_sep = true;
        } else {
            accum += c;
            ends_with_sep = false;
        }
    }
    if (_str.byte_len(accum) != 0u ||
        ends_with_sep) {
        v += accum;
    }
    ret v;
}

fn concat(vec[str] v) -> str {
    let str s = "";
    for (str ss in v) {
        s += ss;
    }
    ret s;
}

fn connect(vec[str] v, str sep) -> str {
    let str s = "";
    let bool first = true;
    for (str ss in v) {
        if (first) {
            first = false;
        } else {
            s += sep;
        }
        s += ss;
    }
    ret s;
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>use std::mem;

use crate::common::*;
use crate::dbi::Module;
use crate::msf::Stream;
use crate::symbol::SymbolIter;
use crate::FallibleIterator;

mod c13;
mod constants;

#[derive(Clone, Copy, Debug)]
enum LinesSize {
    C11(usize),
    C13(usize),
}

/// This struct contains data about a single module from its module info stream.
///
/// The module info stream is where private symbols and line info is stored.
pub struct ModuleInfo<'s> {
    stream: Stream<'s>,
    symbols_size: usize,
    lines_size: LinesSize,
}

impl<'s> ModuleInfo<'s> {
    /// Parses a `ModuleInfo` from it's Module info stream data.
    pub(crate) fn parse(stream: Stream<'s>, module: &Module<'_>) -> Result<Self> {
        let info = module.info();

        let mut buf = stream.parse_buffer();
        if buf.parse_u32()? != constants::CV_SIGNATURE_C13 {
            return Err(Error::UnimplementedFeature(
                "Unsupported module info format",
            ));
        }

        let lines_size = if info.lines_size > 0 {
            LinesSize::C11(info.lines_size as usize)
        } else {
            LinesSize::C13(info.c13_lines_size as usize)
        };

        let symbols_size = info.symbols_size as usize;
        Ok(ModuleInfo {
            stream,
            symbols_size,
            lines_size,
        })
    }

    /// Get an iterator over the all symbols in this module.
    pub fn symbols(&self) -> Result<SymbolIter<'_>> {
        let mut buf = self.stream.parse_buffer();
        buf.parse_u32()?;
        let symbols = buf.take(self.symbols_size - mem::size_of::<u32>())?;
        Ok(SymbolIter::new(symbols.into()))
    }

    /// Returns a line program that gives access to file and line information in this module.
    pub fn line_program(&self) -> Result<LineProgram<'_>> {
        let start = self.symbols_size as usize;
        let inner = match self.lines_size {
            LinesSize::C11(_size) => return Err(Error::UnimplementedFeature("C11 line programs")),
            LinesSize::C13(size) => {
                let data = &self.stream[start..start + size];
                LineProgramInner::C13(c13::C13LineProgram::parse(data)?)
            }
        };

        Ok(LineProgram { inner })
    }
}

/// Checksum of a source file's contents.
#[derive(Clone, Debug)]
pub enum FileChecksum<'a> {
    None,
    Md5(&'a [u8]),
    Sha1(&'a [u8]),
    Sha256(&'a [u8]),
}

impl PartialEq for FileChecksum<'_> {
    fn eq(&self, other: &Self) -> bool {
        // Manual implementation to allow for None != None.
        match (self, other) {
            (&FileChecksum::Md5(lhs), &FileChecksum::Md5(rhs)) => lhs == rhs,
            (&FileChecksum::Sha1(lhs), &FileChecksum::Sha1(rhs)) => lhs == rhs,
            (&FileChecksum::Sha256(lhs), &FileChecksum::Sha256(rhs)) => lhs == rhs,
            _ => false,
        }
    }
}

/// Information record on a source file.
#[derive(Clone, Debug, PartialEq)]
pub struct FileInfo<'a> {
    /// Reference to the file name in the [string table](struct.StringTable.html).
    pub name: StringRef,

    /// Checksum of the file contents.
    pub checksum: FileChecksum<'a>,
}

/// Index of a file entry in the module.
///
/// Use the [`LineProgram`] to resolve information on the file from this offset.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct FileIndex(pub u32);

/// The kind of source construct a line info is referring to.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LineInfoKind {
    /// A source code expression.
    Expression,
    /// A source code statement.
    Statement,
}

/// Mapping of a source code offset to a source file location.
///
/// A line entry is always valid up to the subsequent entry.
#[derive(Clone, Debug)]
pub struct LineInfo {
    /// Source code offset.
    pub offset: PdbInternalSectionOffset,
    /// Index of the source file in this module.
    pub file_index: FileIndex,
    /// Line number of the start of the covered range.
    pub line_start: u32,
    /// Line number of the end of the covered range.
    pub line_end: u32,
    /// Column number of the start of the covered range.
    ///
    /// This value is only present if column information is provided by the PDB. Even then, it is
    /// often zero.
    pub column_start: Option<u16>,
    /// Column number of the end of the covered range.
    ///
    /// This value is only present if column information is provided by the PDB. Even then, it is
    /// often zero.
    pub column_end: Option<u16>,
    /// Kind of this line information.
    pub kind: LineInfoKind,
}

enum LineProgramInner<'a> {
    C13(c13::C13LineProgram<'a>),
}

/// The `LineProgram` provides access to source line information for a module and its procedures.
pub struct LineProgram<'a> {
    inner: LineProgramInner<'a>,
}

impl<'a> LineProgram<'a> {
    /// Returns an iterator over all line information records of this module.
    ///
    /// Note that line records are not guaranteed to be ordered by source code offset. If a
    /// monotonic order by `PdbInternalSectionOffset` or `Rva` is required, the lines have to be
    /// sorted manually.
    pub fn lines(&self) -> LineIterator {
        match self.inner {
            LineProgramInner::C13(ref inner) => LineIterator {
                inner: LineIteratorInner::C13(inner.lines()),
            },
        }
    }

    /// Returns an iterator over all file records of this module.
    pub fn files(&self) -> FileIterator {
        match self.inner {
            LineProgramInner::C13(ref inner) => FileIterator {
                inner: FileIteratorInner::C13(inner.files()),
            },
        }
    }

    /// Returns an iterator over line records for the given section offset.
    ///
    /// This does not work with any arbitrary section offset. The iterator only returns lines if the
    /// section offset is the start of a line block. This is true for procedure or symbol offsets
    /// that specify line information. For all other offsets, the iterator will be empty.
    ///
    /// Note that line records are not guaranteed to be ordered by source code offset. If a
    /// monotonic order by `PdbInternalSectionOffset` or `Rva` is required, the lines have to be
    /// sorted manually.
    pub fn lines_at_offset(&self, offset: PdbInternalSectionOffset) -> LineIterator {
        match self.inner {
            LineProgramInner::C13(ref inner) => LineIterator {
                inner: LineIteratorInner::C13(inner.lines_at_offset(offset)),
            },
        }
    }

    /// Looks up file information for the specified file.
    pub fn get_file_info(&self, offset: FileIndex) -> Result<FileInfo<'a>> {
        match self.inner {
            LineProgramInner::C13(ref inner) => inner.get_file_info(offset),
        }
    }
}

enum LineIteratorInner<'a> {
    C13(c13::C13LineIterator<'a>),
}

/// An iterator over line information records in a module.
pub struct LineIterator<'a> {
    inner: LineIteratorInner<'a>,
}

impl<'a> FallibleIterator for LineIterator<'a> {
    type Item = LineInfo;
    type Error = Error;

    fn next(&mut self) -> Result<Option<Self::Item>> {
        match self.inner {
            LineIteratorInner::C13(ref mut inner) => inner.next(),
        }
    }
}

enum FileIteratorInner<'a> {
    C13(c13::C13FileIterator<'a>),
}

/// An iterator over file records in a module.
pub struct FileIterator<'a> {
    inner: FileIteratorInner<'a>,
}

impl<'a> FallibleIterator for FileIterator<'a> {
    type Item = FileInfo<'a>;
    type Error = Error;

    fn next(&mut self) -> Result<Option<Self::Item>> {
        match self.inner {
            FileIteratorInner::C13(ref mut inner) => inner.next(),
        }
    }
}
<commit_msg>Implement empty Default iterators for lines and files<commit_after>use std::mem;

use crate::common::*;
use crate::dbi::Module;
use crate::msf::Stream;
use crate::symbol::SymbolIter;
use crate::FallibleIterator;

mod c13;
mod constants;

#[derive(Clone, Copy, Debug)]
enum LinesSize {
    C11(usize),
    C13(usize),
}

/// This struct contains data about a single module from its module info stream.
///
/// The module info stream is where private symbols and line info is stored.
pub struct ModuleInfo<'s> {
    stream: Stream<'s>,
    symbols_size: usize,
    lines_size: LinesSize,
}

impl<'s> ModuleInfo<'s> {
    /// Parses a `ModuleInfo` from it's Module info stream data.
    pub(crate) fn parse(stream: Stream<'s>, module: &Module<'_>) -> Result<Self> {
        let info = module.info();

        let mut buf = stream.parse_buffer();
        if buf.parse_u32()? != constants::CV_SIGNATURE_C13 {
            return Err(Error::UnimplementedFeature(
                "Unsupported module info format",
            ));
        }

        let lines_size = if info.lines_size > 0 {
            LinesSize::C11(info.lines_size as usize)
        } else {
            LinesSize::C13(info.c13_lines_size as usize)
        };

        let symbols_size = info.symbols_size as usize;
        Ok(ModuleInfo {
            stream,
            symbols_size,
            lines_size,
        })
    }

    /// Get an iterator over the all symbols in this module.
    pub fn symbols(&self) -> Result<SymbolIter<'_>> {
        let mut buf = self.stream.parse_buffer();
        buf.parse_u32()?;
        let symbols = buf.take(self.symbols_size - mem::size_of::<u32>())?;
        Ok(SymbolIter::new(symbols.into()))
    }

    /// Returns a line program that gives access to file and line information in this module.
    pub fn line_program(&self) -> Result<LineProgram<'_>> {
        let start = self.symbols_size as usize;
        let inner = match self.lines_size {
            LinesSize::C11(_size) => return Err(Error::UnimplementedFeature("C11 line programs")),
            LinesSize::C13(size) => {
                let data = &self.stream[start..start + size];
                LineProgramInner::C13(c13::C13LineProgram::parse(data)?)
            }
        };

        Ok(LineProgram { inner })
    }
}

/// Checksum of a source file's contents.
#[derive(Clone, Debug)]
pub enum FileChecksum<'a> {
    None,
    Md5(&'a [u8]),
    Sha1(&'a [u8]),
    Sha256(&'a [u8]),
}

impl PartialEq for FileChecksum<'_> {
    fn eq(&self, other: &Self) -> bool {
        // Manual implementation to allow for None != None.
        match (self, other) {
            (&FileChecksum::Md5(lhs), &FileChecksum::Md5(rhs)) => lhs == rhs,
            (&FileChecksum::Sha1(lhs), &FileChecksum::Sha1(rhs)) => lhs == rhs,
            (&FileChecksum::Sha256(lhs), &FileChecksum::Sha256(rhs)) => lhs == rhs,
            _ => false,
        }
    }
}

/// Information record on a source file.
#[derive(Clone, Debug, PartialEq)]
pub struct FileInfo<'a> {
    /// Reference to the file name in the [string table](struct.StringTable.html).
    pub name: StringRef,

    /// Checksum of the file contents.
    pub checksum: FileChecksum<'a>,
}

/// Index of a file entry in the module.
///
/// Use the [`LineProgram`] to resolve information on the file from this offset.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct FileIndex(pub u32);

/// The kind of source construct a line info is referring to.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LineInfoKind {
    /// A source code expression.
    Expression,
    /// A source code statement.
    Statement,
}

/// Mapping of a source code offset to a source file location.
///
/// A line entry is always valid up to the subsequent entry.
#[derive(Clone, Debug)]
pub struct LineInfo {
    /// Source code offset.
    pub offset: PdbInternalSectionOffset,
    /// Index of the source file in this module.
    pub file_index: FileIndex,
    /// Line number of the start of the covered range.
    pub line_start: u32,
    /// Line number of the end of the covered range.
    pub line_end: u32,
    /// Column number of the start of the covered range.
    ///
    /// This value is only present if column information is provided by the PDB. Even then, it is
    /// often zero.
    pub column_start: Option<u16>,
    /// Column number of the end of the covered range.
    ///
    /// This value is only present if column information is provided by the PDB. Even then, it is
    /// often zero.
    pub column_end: Option<u16>,
    /// Kind of this line information.
    pub kind: LineInfoKind,
}

enum LineProgramInner<'a> {
    C13(c13::C13LineProgram<'a>),
}

/// The `LineProgram` provides access to source line information for a module and its procedures.
pub struct LineProgram<'a> {
    inner: LineProgramInner<'a>,
}

impl<'a> LineProgram<'a> {
    /// Returns an iterator over all line information records of this module.
    ///
    /// Note that line records are not guaranteed to be ordered by source code offset. If a
    /// monotonic order by `PdbInternalSectionOffset` or `Rva` is required, the lines have to be
    /// sorted manually.
    pub fn lines(&self) -> LineIterator {
        match self.inner {
            LineProgramInner::C13(ref inner) => LineIterator {
                inner: LineIteratorInner::C13(inner.lines()),
            },
        }
    }

    /// Returns an iterator over all file records of this module.
    pub fn files(&self) -> FileIterator {
        match self.inner {
            LineProgramInner::C13(ref inner) => FileIterator {
                inner: FileIteratorInner::C13(inner.files()),
            },
        }
    }

    /// Returns an iterator over line records for the given section offset.
    ///
    /// This does not work with any arbitrary section offset. The iterator only returns lines if the
    /// section offset is the start of a line block. This is true for procedure or symbol offsets
    /// that specify line information. For all other offsets, the iterator will be empty.
    ///
    /// Note that line records are not guaranteed to be ordered by source code offset. If a
    /// monotonic order by `PdbInternalSectionOffset` or `Rva` is required, the lines have to be
    /// sorted manually.
    pub fn lines_at_offset(&self, offset: PdbInternalSectionOffset) -> LineIterator {
        match self.inner {
            LineProgramInner::C13(ref inner) => LineIterator {
                inner: LineIteratorInner::C13(inner.lines_at_offset(offset)),
            },
        }
    }

    /// Looks up file information for the specified file.
    pub fn get_file_info(&self, offset: FileIndex) -> Result<FileInfo<'a>> {
        match self.inner {
            LineProgramInner::C13(ref inner) => inner.get_file_info(offset),
        }
    }
}

#[derive(Clone, Debug)]
enum LineIteratorInner<'a> {
    C13(c13::C13LineIterator<'a>),
}

/// An iterator over line information records in a module.
#[derive(Clone, Debug)]
pub struct LineIterator<'a> {
    inner: LineIteratorInner<'a>,
}

impl Default for LineIterator<'_> {
    fn default() -> Self {
        LineIterator {
            inner: LineIteratorInner::C13(Default::default()),
        }
    }
}

impl<'a> FallibleIterator for LineIterator<'a> {
    type Item = LineInfo;
    type Error = Error;

    fn next(&mut self) -> Result<Option<Self::Item>> {
        match self.inner {
            LineIteratorInner::C13(ref mut inner) => inner.next(),
        }
    }
}

#[derive(Clone, Debug)]
enum FileIteratorInner<'a> {
    C13(c13::C13FileIterator<'a>),
}

/// An iterator over file records in a module.
#[derive(Clone, Debug)]
pub struct FileIterator<'a> {
    inner: FileIteratorInner<'a>,
}

impl Default for FileIterator<'_> {
    fn default() -> Self {
        FileIterator {
            inner: FileIteratorInner::C13(Default::default()),
        }
    }
}

impl<'a> FallibleIterator for FileIterator<'a> {
    type Item = FileInfo<'a>;
    type Error = Error;

    fn next(&mut self) -> Result<Option<Self::Item>> {
        match self.inner {
            FileIteratorInner::C13(ref mut inner) => inner.next(),
        }
    }
}
<|endoftext|>