<commit_before>use crate::request::ToParams;
use crate::errors::*;

use std::str::FromStr;

#[derive(Debug, Clone, PartialEq)]
pub struct AppId(String);
#[derive(Debug, Clone, PartialEq)]
pub struct AppKey(String);
#[derive(Debug, Clone, PartialEq)]
pub struct UserKey(String);
#[derive(Debug, Clone, PartialEq)]
pub struct OAuthToken(String);

// These trait impls provide a way to reference our types as &str
impl AsRef<str> for AppId {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

impl AsRef<str> for AppKey {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

impl AsRef<str> for UserKey {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

impl AsRef<str> for OAuthToken {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

// These trait impls provide a way to &str#parse() our Application type
impl FromStr for AppId {
    type Err = Error;

    fn from_str(s: &str) -> Result<AppId> {
        Ok(AppId(s.into()))
    }
}

impl FromStr for AppKey {
    type Err = Error;

    fn from_str(s: &str) -> Result<AppKey> {
        Ok(AppKey(s.into()))
    }
}

impl FromStr for UserKey {
    type Err = Error;

    fn from_str(s: &str) -> Result<UserKey> {
        Ok(UserKey(s.into()))
    }
}

impl FromStr for OAuthToken {
    type Err = Error;

    fn from_str(s: &str) -> Result<OAuthToken> {
        Ok(OAuthToken(s.into()))
    }
}

// These trait impls are similar to FromStr (but are infallible)
impl<'a> From<&'a str> for AppId where Self: FromStr {
    fn from(s: &'a str) -> AppId {
        s.parse().unwrap()
    }
}

impl<'a> From<&'a str> for AppKey where Self: FromStr {
    fn from(s: &'a str) -> AppKey {
        s.parse().unwrap()
    }
}

impl<'a> From<&'a str> for UserKey where Self: FromStr {
    fn from(s: &'a str) -> UserKey {
        s.parse().unwrap()
    }
}

impl<'a> From<&'a str> for OAuthToken where Self: FromStr {
    fn from(s: &'a str) -> OAuthToken {
        s.parse().unwrap()
    }
}

// These trait impls take ownership of a given String and also provide Into<AppId> for String
impl From<String> for AppId {
    fn from(s: String) -> AppId {
        AppId(s)
    }
}

impl From<String> for AppKey {
    fn from(s: String) -> AppKey {
        AppKey(s)
    }
}

impl From<String> for UserKey {
    fn from(s: String) -> UserKey {
        UserKey(s)
    }
}

impl From<String> for OAuthToken {
    fn from(s: String) -> OAuthToken {
        OAuthToken(s)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Application {
    AppId(AppId, Option<AppKey>),
    UserKey(UserKey),
    OAuthToken(OAuthToken)
}

// These trait impls build an Application variant out of its required types
impl Into<Application> for AppId {
    fn into(self) -> Application {
        Application::AppId(self, None)
    }
}

impl Into<Application> for (AppId, AppKey) {
    fn into(self) -> Application {
        Application::AppId(self.0, Some(self.1))
    }
}

impl Into<Application> for UserKey {
    fn into(self) -> Application {
        Application::UserKey(self)
    }
}

impl Into<Application> for OAuthToken {
    fn into(self) -> Application {
        Application::OAuthToken(self)
    }
}

impl Application {
    /// Creates a new `Application` from an `AppId`.
    ///
    /// # Examples
    ///
    /// ```
    /// use threescalers::application::*;
    ///
    /// let app = Application::from_app_id("my_app_id");
    /// ```
    pub fn from_app_id<T: Into<AppId>>(app_id: T) -> Self {
        Application::AppId(app_id.into(), None)
    }

    /// Creates a new `Application` from an `AppId` and an `AppKey`.
    ///
    /// # Examples
    ///
    /// ```
    /// use threescalers::application::*;
    ///
    /// let app = Application::from_app_id_and_key("my_app_id", "my_app_key");
    /// ```
    pub fn from_app_id_and_key<T: Into<AppId>, U: Into<AppKey>>(app_id: T, app_key: U) -> Self {
        Application::AppId(app_id.into(), Some(app_key.into()))
    }

    /// Creates a new `Application` from a `UserKey`.
    ///
    /// # Examples
    ///
    /// ```
    /// use threescalers::application::*;
    ///
    /// let app = Application::from_user_key("my_user_key");
    /// ```
    pub fn from_user_key<T: Into<UserKey>>(user_key: T) -> Self {
        Application::UserKey(user_key.into())
    }

    /// Creates a new `Application` from an `OAuthToken`.
    ///
    /// # Examples
    ///
    /// ```
    /// use threescalers::application::*;
    ///
    /// let app = Application::from_oauth_token("my_token");
    /// ```
    pub fn from_oauth_token<T: Into<OAuthToken>>(token: T) -> Self {
        Application::OAuthToken(token.into())
    }
}

impl ToParams for Application {
    fn to_params(&self) -> Vec<(&str, &str)>{
        use self::Application::*;

        let mut v = Vec::<(&str, &str)>::with_capacity(2);
        match self {
            AppId(app_id, None) => {
                v.push(("app_id", app_id.as_ref()));
            },
            AppId(app_id, Some(app_key)) => {
                v.push(("app_id", app_id.as_ref()));
                v.push(("app_key", app_key.as_ref()));
            },
            UserKey(user_key) => v.push(("user_key", user_key.as_ref())),
            OAuthToken(token) => v.push(("access_token", token.as_ref())),
        };

        v
    }
}

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

    #[test]
    fn transforms_app_id_into_params() {
        let app_id = "my_app_id";
        let app = Application::from_app_id(app_id);

        let result = app.to_params();

        let expected = vec![("app_id", app_id)];
        assert_eq!(expected, result);
    }

    #[test]
    fn transforms_app_id_and_key_into_params() {
        let app_id = "my_app_id";
        let key = "my_key";
        let app = Application::from_app_id_and_key(app_id, key);

        let result = app.to_params();

        let expected = vec![("app_id", app_id), ("app_key", key)];
        assert_eq!(expected, result);
    }

    #[test]
    fn transforms_user_key_into_params() {
        let user_key = "my_user_key";
        let app = Application::from_user_key(user_key);

        let result = app.to_params();

        let expected = vec![("user_key", user_key)];
        assert_eq!(expected, result);
    }

    #[test]
    fn transforms_oauth_token_into_params() {
        let oauth_token = "my_token";
        let app = Application::from_oauth_token(oauth_token);

        let result = app.to_params();

        let expected = vec![("access_token", oauth_token)];
        assert_eq!(expected, result);
    }
}
<commit_msg>application: use From trait instead of Into<commit_after>use crate::request::ToParams;
use crate::errors::*;

use std::str::FromStr;

#[derive(Debug, Clone, PartialEq)]
pub struct AppId(String);
#[derive(Debug, Clone, PartialEq)]
pub struct AppKey(String);
#[derive(Debug, Clone, PartialEq)]
pub struct UserKey(String);
#[derive(Debug, Clone, PartialEq)]
pub struct OAuthToken(String);

// These trait impls provide a way to reference our types as &str
impl AsRef<str> for AppId {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

impl AsRef<str> for AppKey {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

impl AsRef<str> for UserKey {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

impl AsRef<str> for OAuthToken {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

// These trait impls provide a way to &str#parse() our Application type
impl FromStr for AppId {
    type Err = Error;

    fn from_str(s: &str) -> Result<AppId> {
        Ok(AppId(s.into()))
    }
}

impl FromStr for AppKey {
    type Err = Error;

    fn from_str(s: &str) -> Result<AppKey> {
        Ok(AppKey(s.into()))
    }
}

impl FromStr for UserKey {
    type Err = Error;

    fn from_str(s: &str) -> Result<UserKey> {
        Ok(UserKey(s.into()))
    }
}

impl FromStr for OAuthToken {
    type Err = Error;

    fn from_str(s: &str) -> Result<OAuthToken> {
        Ok(OAuthToken(s.into()))
    }
}

// These trait impls are similar to FromStr (but are infallible)
impl<'a> From<&'a str> for AppId where Self: FromStr {
    fn from(s: &'a str) -> AppId {
        s.parse().unwrap()
    }
}

impl<'a> From<&'a str> for AppKey where Self: FromStr {
    fn from(s: &'a str) -> AppKey {
        s.parse().unwrap()
    }
}

impl<'a> From<&'a str> for UserKey where Self: FromStr {
    fn from(s: &'a str) -> UserKey {
        s.parse().unwrap()
    }
}

impl<'a> From<&'a str> for OAuthToken where Self: FromStr {
    fn from(s: &'a str) -> OAuthToken {
        s.parse().unwrap()
    }
}

// These trait impls take ownership of a given String and also provide Into<AppId> for String
impl From<String> for AppId {
    fn from(s: String) -> AppId {
        AppId(s)
    }
}

impl From<String> for AppKey {
    fn from(s: String) -> AppKey {
        AppKey(s)
    }
}

impl From<String> for UserKey {
    fn from(s: String) -> UserKey {
        UserKey(s)
    }
}

impl From<String> for OAuthToken {
    fn from(s: String) -> OAuthToken {
        OAuthToken(s)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Application {
    AppId(AppId, Option<AppKey>),
    UserKey(UserKey),
    OAuthToken(OAuthToken)
}

// These trait impls build an Application variant out of its required types
impl From<AppId> for Application {
    fn from(a: AppId) -> Self {
        Application::AppId(a, None)
    }
}

impl From<(AppId, AppKey)> for Application {
    fn from(a: (AppId, AppKey)) -> Self {
        Application::AppId(a.0, Some(a.1))
    }
}

impl From<UserKey> for Application {
    fn from(u: UserKey) -> Self {
        Application::UserKey(u)
    }
}

impl From<OAuthToken> for Application {
    fn from(o: OAuthToken) -> Self {
        Application::OAuthToken(o)
    }
}

impl Application {
    /// Creates a new `Application` from an `AppId`.
    ///
    /// # Examples
    ///
    /// ```
    /// use threescalers::application::*;
    ///
    /// let app = Application::from_app_id("my_app_id");
    /// ```
    pub fn from_app_id<T: Into<AppId>>(app_id: T) -> Self {
        Application::AppId(app_id.into(), None)
    }

    /// Creates a new `Application` from an `AppId` and an `AppKey`.
    ///
    /// # Examples
    ///
    /// ```
    /// use threescalers::application::*;
    ///
    /// let app = Application::from_app_id_and_key("my_app_id", "my_app_key");
    /// ```
    pub fn from_app_id_and_key<T: Into<AppId>, U: Into<AppKey>>(app_id: T, app_key: U) -> Self {
        Application::AppId(app_id.into(), Some(app_key.into()))
    }

    /// Creates a new `Application` from a `UserKey`.
    ///
    /// # Examples
    ///
    /// ```
    /// use threescalers::application::*;
    ///
    /// let app = Application::from_user_key("my_user_key");
    /// ```
    pub fn from_user_key<T: Into<UserKey>>(user_key: T) -> Self {
        Application::UserKey(user_key.into())
    }

    /// Creates a new `Application` from an `OAuthToken`.
    ///
    /// # Examples
    ///
    /// ```
    /// use threescalers::application::*;
    ///
    /// let app = Application::from_oauth_token("my_token");
    /// ```
    pub fn from_oauth_token<T: Into<OAuthToken>>(token: T) -> Self {
        Application::OAuthToken(token.into())
    }
}

impl ToParams for Application {
    fn to_params(&self) -> Vec<(&str, &str)>{
        use self::Application::*;

        let mut v = Vec::<(&str, &str)>::with_capacity(2);
        match self {
            AppId(app_id, None) => {
                v.push(("app_id", app_id.as_ref()));
            },
            AppId(app_id, Some(app_key)) => {
                v.push(("app_id", app_id.as_ref()));
                v.push(("app_key", app_key.as_ref()));
            },
            UserKey(user_key) => v.push(("user_key", user_key.as_ref())),
            OAuthToken(token) => v.push(("access_token", token.as_ref())),
        };

        v
    }
}

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

    #[test]
    fn transforms_app_id_into_params() {
        let app_id = "my_app_id";
        let app = Application::from_app_id(app_id);

        let result = app.to_params();

        let expected = vec![("app_id", app_id)];
        assert_eq!(expected, result);
    }

    #[test]
    fn transforms_app_id_and_key_into_params() {
        let app_id = "my_app_id";
        let key = "my_key";
        let app = Application::from_app_id_and_key(app_id, key);

        let result = app.to_params();

        let expected = vec![("app_id", app_id), ("app_key", key)];
        assert_eq!(expected, result);
    }

    #[test]
    fn transforms_user_key_into_params() {
        let user_key = "my_user_key";
        let app = Application::from_user_key(user_key);

        let result = app.to_params();

        let expected = vec![("user_key", user_key)];
        assert_eq!(expected, result);
    }

    #[test]
    fn transforms_oauth_token_into_params() {
        let oauth_token = "my_token";
        let app = Application::from_oauth_token(oauth_token);

        let result = app.to_params();

        let expected = vec![("access_token", oauth_token)];
        assert_eq!(expected, result);
    }
}
<|endoftext|>


<commit_before>// The following is a hexdump of a zip file containing the following
// ZipCrypto encrypted file:
// test.txt: 35 bytes, contents: `abcdefghijklmnopqrstuvwxyz123456789`, password: `test`
//
// 00000000  50 4b 03 04 14 00 01 00  00 00 54 bd b5 50 2f 20  |PK........T..P/ |
// 00000010  79 55 2f 00 00 00 23 00  00 00 08 00 00 00 74 65  |yU/...#.......te|
// 00000020  73 74 2e 74 78 74 ca 2d  1d 27 19 19 63 43 77 9a  |st.txt.-.'..cCw.|
// 00000030  71 76 c9 ec d1 6f d9 f5  22 67 b3 8f 52 b5 41 bc  |qv...o.."g..R.A.|
// 00000040  5c 36 f2 1d 84 c3 c0 28  3b fd e1 70 c2 cc 0c 11  |\6.....(;..p....|
// 00000050  0c c5 95 2f a4 50 4b 01  02 3f 00 14 00 01 00 00  |.../.PK..?......|
// 00000060  00 54 bd b5 50 2f 20 79  55 2f 00 00 00 23 00 00  |.T..P/ yU/...#..|
// 00000070  00 08 00 24 00 00 00 00  00 00 00 20 00 00 00 00  |...$....... ....|
// 00000080  00 00 00 74 65 73 74 2e  74 78 74 0a 00 20 00 00  |...test.txt.. ..|
// 00000090  00 00 00 01 00 18 00 31  b2 3b bf b8 2f d6 01 31  |.......1.;../..1|
// 000000a0  b2 3b bf b8 2f d6 01 a8  c4 45 bd b8 2f d6 01 50  |.;../....E../..P|
// 000000b0  4b 05 06 00 00 00 00 01  00 01 00 5a 00 00 00 55  |K..........Z...U|
// 000000c0  00 00 00 00 00                                    |.....|
// 000000c5

use std::io::Cursor;
use std::io::Read;

#[test]
fn encrypted_file() {
    let zip_file_bytes = &mut Cursor::new(vec![
        0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x54, 0xbd, 0xb5, 0x50, 0x2f,
        0x20, 0x79, 0x55, 0x2f, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
        0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 0x78, 0x74, 0xca, 0x2d, 0x1d, 0x27, 0x19, 0x19, 0x63,
        0x43, 0x77, 0x9a, 0x71, 0x76, 0xc9, 0xec, 0xd1, 0x6f, 0xd9, 0xf5, 0x22, 0x67, 0xb3, 0x8f,
        0x52, 0xb5, 0x41, 0xbc, 0x5c, 0x36, 0xf2, 0x1d, 0x84, 0xc3, 0xc0, 0x28, 0x3b, 0xfd, 0xe1,
        0x70, 0xc2, 0xcc, 0x0c, 0x11, 0x0c, 0xc5, 0x95, 0x2f, 0xa4, 0x50, 0x4b, 0x01, 0x02, 0x3f,
        0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x54, 0xbd, 0xb5, 0x50, 0x2f, 0x20, 0x79, 0x55,
        0x2f, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x08, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74,
        0x2e, 0x74, 0x78, 0x74, 0x0a, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x18,
        0x00, 0x31, 0xb2, 0x3b, 0xbf, 0xb8, 0x2f, 0xd6, 0x01, 0x31, 0xb2, 0x3b, 0xbf, 0xb8, 0x2f,
        0xd6, 0x01, 0xa8, 0xc4, 0x45, 0xbd, 0xb8, 0x2f, 0xd6, 0x01, 0x50, 0x4b, 0x05, 0x06, 0x00,
        0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,
        0x00, 0x00,
    ]);

    let mut archive = zip::ZipArchive::new(zip_file_bytes).unwrap();

    assert_eq!(archive.len(), 1); //Only one file inside archive: `test.txt`

    {
        // No password
        let file = archive.by_index(0);
        assert!(file.is_err());
        if let Err(error) = file {
            match error {
                zip::result::ZipError::PasswordRequired => (),
                _ => panic!(),
            }
        } else {
            panic!();
        }
    }

    {
        // Wrong password
        let file = archive.by_index_decrypt(0, b"wrong password");
        assert!(file.is_err());
        if let Err(error) = file {
            match error {
                zip::result::ZipError::InvalidPassword => (),
                _ => panic!(),
            }
        } else {
            panic!();
        }
    }

    {
        // Correct password, read contents
        let mut file = archive.by_index_decrypt(0, "test".as_bytes()).unwrap();
        let file_name = file.sanitized_name();
        assert_eq!(file_name, std::path::PathBuf::from("test.txt"));

        let mut data = Vec::new();
        file.read_to_end(&mut data).unwrap();
        assert_eq!(data, "abcdefghijklmnopqrstuvwxyz123456789".as_bytes());
    }
}
<commit_msg>Create meaningful panic messages in ZipCrypto test<commit_after>// The following is a hexdump of a zip file containing the following
// ZipCrypto encrypted file:
// test.txt: 35 bytes, contents: `abcdefghijklmnopqrstuvwxyz123456789`, password: `test`
//
// 00000000  50 4b 03 04 14 00 01 00  00 00 54 bd b5 50 2f 20  |PK........T..P/ |
// 00000010  79 55 2f 00 00 00 23 00  00 00 08 00 00 00 74 65  |yU/...#.......te|
// 00000020  73 74 2e 74 78 74 ca 2d  1d 27 19 19 63 43 77 9a  |st.txt.-.'..cCw.|
// 00000030  71 76 c9 ec d1 6f d9 f5  22 67 b3 8f 52 b5 41 bc  |qv...o.."g..R.A.|
// 00000040  5c 36 f2 1d 84 c3 c0 28  3b fd e1 70 c2 cc 0c 11  |\6.....(;..p....|
// 00000050  0c c5 95 2f a4 50 4b 01  02 3f 00 14 00 01 00 00  |.../.PK..?......|
// 00000060  00 54 bd b5 50 2f 20 79  55 2f 00 00 00 23 00 00  |.T..P/ yU/...#..|
// 00000070  00 08 00 24 00 00 00 00  00 00 00 20 00 00 00 00  |...$....... ....|
// 00000080  00 00 00 74 65 73 74 2e  74 78 74 0a 00 20 00 00  |...test.txt.. ..|
// 00000090  00 00 00 01 00 18 00 31  b2 3b bf b8 2f d6 01 31  |.......1.;../..1|
// 000000a0  b2 3b bf b8 2f d6 01 a8  c4 45 bd b8 2f d6 01 50  |.;../....E../..P|
// 000000b0  4b 05 06 00 00 00 00 01  00 01 00 5a 00 00 00 55  |K..........Z...U|
// 000000c0  00 00 00 00 00                                    |.....|
// 000000c5

use std::io::Cursor;
use std::io::Read;

#[test]
fn encrypted_file() {
    let zip_file_bytes = &mut Cursor::new(vec![
        0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x54, 0xbd, 0xb5, 0x50, 0x2f,
        0x20, 0x79, 0x55, 0x2f, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
        0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 0x78, 0x74, 0xca, 0x2d, 0x1d, 0x27, 0x19, 0x19, 0x63,
        0x43, 0x77, 0x9a, 0x71, 0x76, 0xc9, 0xec, 0xd1, 0x6f, 0xd9, 0xf5, 0x22, 0x67, 0xb3, 0x8f,
        0x52, 0xb5, 0x41, 0xbc, 0x5c, 0x36, 0xf2, 0x1d, 0x84, 0xc3, 0xc0, 0x28, 0x3b, 0xfd, 0xe1,
        0x70, 0xc2, 0xcc, 0x0c, 0x11, 0x0c, 0xc5, 0x95, 0x2f, 0xa4, 0x50, 0x4b, 0x01, 0x02, 0x3f,
        0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x54, 0xbd, 0xb5, 0x50, 0x2f, 0x20, 0x79, 0x55,
        0x2f, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x08, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74,
        0x2e, 0x74, 0x78, 0x74, 0x0a, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x18,
        0x00, 0x31, 0xb2, 0x3b, 0xbf, 0xb8, 0x2f, 0xd6, 0x01, 0x31, 0xb2, 0x3b, 0xbf, 0xb8, 0x2f,
        0xd6, 0x01, 0xa8, 0xc4, 0x45, 0xbd, 0xb8, 0x2f, 0xd6, 0x01, 0x50, 0x4b, 0x05, 0x06, 0x00,
        0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,
        0x00, 0x00,
    ]);

    let mut archive = zip::ZipArchive::new(zip_file_bytes).unwrap();

    assert_eq!(archive.len(), 1); //Only one file inside archive: `test.txt`

    {
        // No password
        let file = archive.by_index(0);
        assert!(file.is_err());
        if let Err(error) = file {
            match error {
                zip::result::ZipError::PasswordRequired => (),
                _ => panic!(
                    "Expected PasswordRequired error when opening encrypted file without password"
                ),
            }
        } else {
            panic!("Error: Successfully opened encrypted file without password?!");
        }
    }

    {
        // Wrong password
        let file = archive.by_index_decrypt(0, b"wrong password");
        assert!(file.is_err());
        if let Err(error) = file {
            match error {
                zip::result::ZipError::InvalidPassword => (),
                _ => panic!("Expected InvalidPassword error when opening encrypted file with wrong password"),
            }
        } else {
            panic!("Error: Successfully opened encrypted file with wrong password?!");
        }
    }

    {
        // Correct password, read contents
        let mut file = archive.by_index_decrypt(0, "test".as_bytes()).unwrap();
        let file_name = file.sanitized_name();
        assert_eq!(file_name, std::path::PathBuf::from("test.txt"));

        let mut data = Vec::new();
        file.read_to_end(&mut data).unwrap();
        assert_eq!(data, "abcdefghijklmnopqrstuvwxyz123456789".as_bytes());
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]
extern crate futures;
extern crate hyper;
extern crate pretty_env_logger;
extern crate url;

use futures::{future, Future, Stream};

use hyper::{Body, Method, Request, Response, Server, StatusCode};
use hyper::service::service_fn;

use std::collections::HashMap;
use url::form_urlencoded;

static INDEX: &[u8] = b"<form action=\"post\" method=\"post\">Name: <input type=\"text\" name=\"name\">
Number: <input type=\"text\" name=\"number\">
<input type=\"submit\">";
static MISSING: &[u8] = b"Missing field";
static NOTNUMERIC: &[u8] = b"Number field is not numeric";

// Using service_fn, we can turn this function into a `Service`.
fn param_example(req: Request) -> Box<dyn Future<Item=Response, Error=hyper::Error> + Send> {
    match (req.method(), req.uri().path()) {
        (&Method::GET, "/") | (&Method::GET, "/post") => {
            Box::new(future::ok(Response::new(INDEX.into())))
        },
        (&Method::POST, "/post") => {
            Box::new(req.into_body().concat2().map(|b| {
                // Parse the request body. form_urlencoded::parse
                // always succeeds, but in general parsing may
                // fail (for example, an invalid post of json), so
                // returning early with BadRequest may be
                // necessary.
                //
                // Warning: this is a simplified use case. In
                // principle names can appear multiple times in a
                // form, and the values should be rolled up into a
                // HashMap<String, Vec<String>>. However in this
                // example the simpler approach is sufficient.
                let params = form_urlencoded::parse(b.as_ref()).into_owned().collect::<HashMap<String, String>>();

                // Validate the request parameters, returning
                // early if an invalid input is detected.
                let name = if let Some(n) = params.get("name") {
                    n
                } else {
                    return Response::builder()
                        .status(StatusCode::UNPROCESSABLE_ENTITY)
                        .body(MISSING.into())
                        .unwrap();
                };
                let number = if let Some(n) = params.get("number") {
                    if let Ok(v) = n.parse::<f64>() {
                        v
                    } else {
                        return Response::builder()
                            .status(StatusCode::UNPROCESSABLE_ENTITY)
                            .body(NOTNUMERIC.into())
                            .unwrap();
                    }
                } else {
                    return Response::builder()
                        .status(StatusCode::UNPROCESSABLE_ENTITY)
                        .body(MISSING.into())
                        .unwrap();
                };

                // Render the response. This will often involve
                // calls to a database or web service, which will
                // require creating a new stream for the response
                // body. Since those may fail, other error
                // responses such as InternalServiceError may be
                // needed here, too.
                let body = format!("Hello {}, your number is {}", name, number);
                Response::new(body.into())
            }))
        },
        _ => {
            Box::new(future::ok(Response::builder()
                                .status(StatusCode::NOT_FOUND)
                                .body(Body::empty())
                                .unwrap()))
        }
    }

}

fn main() {
    pretty_env_logger::init();

    let addr = ([127, 0, 0, 1], 1337).into();

    let server = Server::bind(&addr)
        .serve(|| service_fn(param_example))
        .map_err(|e| eprintln!("server error: {}", e));

    hyper::rt::run(server);
}
<commit_msg>docs(examples): Update params example to use async await<commit_after>#![feature(async_await)]
// #![deny(warnings)]  // FIXME: https://github.com/rust-lang/rust/issues/62411
extern crate hyper;
extern crate pretty_env_logger;
extern crate url;

use hyper::{Body, Method, Request, Response, Server, StatusCode};
use hyper::service::{service_fn, make_service_fn};

use std::collections::HashMap;
use url::form_urlencoded;
use futures_util::TryStreamExt;

static INDEX: &[u8] = b"<form action=\"post\" method=\"post\">Name: <input type=\"text\" name=\"name\">
Number: <input type=\"text\" name=\"number\">
<input type=\"submit\">";
static MISSING: &[u8] = b"Missing field";
static NOTNUMERIC: &[u8] = b"Number field is not numeric";

// Using service_fn, we can turn this function into a `Service`.
async fn param_example(req: Request) -> Result<Response, hyper::Error> {
    match (req.method(), req.uri().path()) {
        (&Method::GET, "/") | (&Method::GET, "/post") => {
            Ok(Response::new(INDEX.into()))
        },
        (&Method::POST, "/post") => {
            let b = req.into_body().try_concat().await?;
            // Parse the request body. form_urlencoded::parse
            // always succeeds, but in general parsing may
            // fail (for example, an invalid post of json), so
            // returning early with BadRequest may be
            // necessary.
            //
            // Warning: this is a simplified use case. In
            // principle names can appear multiple times in a
            // form, and the values should be rolled up into a
            // HashMap<String, Vec<String>>. However in this
            // example the simpler approach is sufficient.
            let params = form_urlencoded::parse(b.as_ref()).into_owned().collect::<HashMap<String, String>>();

            // Validate the request parameters, returning
            // early if an invalid input is detected.
            let name = if let Some(n) = params.get("name") {
                n
            } else {
                return Ok(Response::builder()
                    .status(StatusCode::UNPROCESSABLE_ENTITY)
                    .body(MISSING.into())
                    .unwrap());
            };
            let number = if let Some(n) = params.get("number") {
                if let Ok(v) = n.parse::<f64>() {
                    v
                } else {
                    return Ok(Response::builder()
                        .status(StatusCode::UNPROCESSABLE_ENTITY)
                        .body(NOTNUMERIC.into())
                        .unwrap());
                }
            } else {
                return Ok(Response::builder()
                    .status(StatusCode::UNPROCESSABLE_ENTITY)
                    .body(MISSING.into())
                    .unwrap());
            };

            // Render the response. This will often involve
            // calls to a database or web service, which will
            // require creating a new stream for the response
            // body. Since those may fail, other error
            // responses such as InternalServiceError may be
            // needed here, too.
            let body = format!("Hello {}, your number is {}", name, number);
            Ok(Response::new(body.into()))
        },
        _ => {
            Ok(Response::builder()
                        .status(StatusCode::NOT_FOUND)
                        .body(Body::empty())
                        .unwrap())
        }
    }
}

#[hyper::rt::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    pretty_env_logger::init();

    let addr = ([127, 0, 0, 1], 1337).into();

    let server = Server::bind(&addr)
        .serve(make_service_fn(|_| {
            async {
                Ok::<_, hyper::Error>(service_fn(param_example))
            }
        }));

    println!("Listening on http://{}", addr);

    server.await?;

    Ok(())
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate router;

// To build, $ cargo test
// To use, go to http://127.0.0.1:3000/test

use iron::{Iron, Request, Response, IronResult};
use iron::status;
use router::{Router};

fn main() {
    let mut router = Router::new();
    router.get("/", handler);
    router.get("/:query", handler);

    Iron::new(handler).http("localhost:3000").unwrap();

    fn handler(req: &mut Request) -> IronResult<Response> {
        let ref query = req.extensions.get::<Router>()
            .unwrap().find("query").unwrap_or("/");
        Ok(Response::with((status::Ok, *query)))
    }
}
<commit_msg>(fix) Revert an unintentional change.<commit_after>extern crate iron;
extern crate router;

// To build, $ cargo test
// To use, go to http://127.0.0.1:3000/test

use iron::{Iron, Request, Response, IronResult};
use iron::status;
use router::{Router};

fn main() {
    let mut router = Router::new();
    router.get("/", handler);
    router.get("/:query", handler);

    Iron::new(router).http("localhost:3000").unwrap();

    fn handler(req: &mut Request) -> IronResult<Response> {
        let ref query = req.extensions.get::<Router>()
            .unwrap().find("query").unwrap_or("/");
        Ok(Response::with((status::Ok, *query)))
    }
}
<|endoftext|>


<commit_before>extern crate schedule_gen;

use schedule_gen::{ Date, GameWeekday, IdAndName, GameTime, Time };

fn main() {
    println!("Hello world!");

    let thing = schedule_gen::LeagueSpec {
        teams: vec![],
        locations: vec![
            IdAndName { id: "1", name: "name1" },
            IdAndName { id: "2", name: "name2" },
            IdAndName { id: "3", name: "name3" }
        ],
        start_date: Date {
            day: 16,
            month: 9,
            year: 2014
        },
        end_date: Date {
            day: 24,
            month: 9,
            year: 2014
        },
        game_weekdays: vec![
            GameWeekday {
                day: schedule_gen::Tuesday,
                game_times: vec![
                    GameTime {
                        time: Time {
                            hour: 16,
                            min: 0
                        },
                        location_ids: vec![ "1", "2" ]
                    },
                    GameTime {
                        time: Time {
                            hour: 17,
                            min: 0
                        },
                        location_ids: vec![ "1", "3" ]
                    },
                    GameTime {
                        time: Time {
                            hour: 18,
                            min: 0
                        },
                        location_ids: vec![ "2", "3" ]
                    }
                ]
            },
            GameWeekday {
                day: schedule_gen::Thursday,
                game_times: vec![
                    GameTime {
                        time: Time {
                            hour: 16,
                            min: 0
                        },
                        location_ids: vec![ "1", "2" ]
                    },
                    GameTime {
                        time: Time {
                            hour: 17,
                            min: 0
                        },
                        location_ids: vec![ "1", "3" ]
                    },
                    GameTime {
                        time: Time {
                            hour: 18,
                            min: 0
                        },
                        location_ids: vec![ "2", "3" ]
                    }
                ]
            }
        ]
    };

    println!("errors:\n{}", schedule_gen::validate(thing));
}
<commit_msg>fixed a date which wasn't valid for the input<commit_after>extern crate schedule_gen;

use schedule_gen::{ Date, GameWeekday, IdAndName, GameTime, Time };

fn main() {
    println!("Hello world!");

    let thing = schedule_gen::LeagueSpec {
        teams: vec![],
        locations: vec![
            IdAndName { id: "1", name: "name1" },
            IdAndName { id: "2", name: "name2" },
            IdAndName { id: "3", name: "name3" }
        ],
        start_date: Date {
            day: 16,
            month: 9,
            year: 2014
        },
        end_date: Date {
            day: 25,
            month: 9,
            year: 2014
        },
        game_weekdays: vec![
            GameWeekday {
                day: schedule_gen::Tuesday,
                game_times: vec![
                    GameTime {
                        time: Time {
                            hour: 16,
                            min: 0
                        },
                        location_ids: vec![ "1", "2" ]
                    },
                    GameTime {
                        time: Time {
                            hour: 17,
                            min: 0
                        },
                        location_ids: vec![ "1", "3" ]
                    },
                    GameTime {
                        time: Time {
                            hour: 18,
                            min: 0
                        },
                        location_ids: vec![ "2", "3" ]
                    }
                ]
            },
            GameWeekday {
                day: schedule_gen::Thursday,
                game_times: vec![
                    GameTime {
                        time: Time {
                            hour: 16,
                            min: 0
                        },
                        location_ids: vec![ "1", "2" ]
                    },
                    GameTime {
                        time: Time {
                            hour: 17,
                            min: 0
                        },
                        location_ids: vec![ "1", "3" ]
                    },
                    GameTime {
                        time: Time {
                            hour: 18,
                            min: 0
                        },
                        location_ids: vec![ "2", "3" ]
                    }
                ]
            }
        ]
    };

    println!("errors:\n{}", schedule_gen::validate(thing));
}
<|endoftext|>


<commit_before>use core::mem;

use redox::*;

use super::nvpair::{DataType, NV_VERSION, NvList, NvValue};
use super::xdr;

// nvlist pack encoding
const NV_ENCODE_NATIVE: u8 = 0;
const NV_ENCODE_XDR:    u8 = 1;

// nvlist pack endian
const NV_BIG_ENDIAN:    u8 = 0;
const NV_LITTLE_ENDIAN: u8 = 1;

// nvlist persistent unique name flags, stored in nvl_nvflags
const NV_UNIQUE_NAME:      u32 = 0x1;
const NV_UNIQUE_NAME_TYPE: u32 = 0x2;

// nvlist lookup pairs related flags
const NV_FLAG_NOENTOK: isize = 0x1;

// NvList XDR format:
// - header (encoding and endian): 4 bytes
// - nvl version: 4 bytes
// - nv flags: 4 bytes
// - nv pairs:
//   - encoded size: 4 bytes
//   - decoded size: 4 bytes
//   - name: xdr string | len: 4 bytes, data: len+(4 - len%4) bytes
//   - data type: 4 bytes
//   - num elements: 4 bytes
//   - data
// - 2 terminating zeros: 4 bytes
//
// NOTE: XDR aligns all of the smaller integer types to be 4 bytes, so `encode_u8` is actually
// writing 4 bytes
//
// I don't know why the ZFS developers decided to use i32's everywhere. Even for clearly
// unsigned things like array lengths.

/// Name value stream header
pub struct NvsHeader {
    encoding: u8,  // nvs encoding method
    endian: u8,    // nvs endian
    reserved1: u8, // reserved for future use
    reserved2: u8, // reserved for future use
}

/// Encodes a NvList in XDR format
pub fn encode_nv_list(xdr: &mut xdr::Xdr, nv_list: &NvList) -> xdr::XdrResult<()> {
    try!(encode_nv_list_header(xdr));

    // Encode version and nvflag
    try!(xdr.encode_i32(nv_list.version));
    try!(xdr.encode_u32(nv_list.nvflag));

    // Encode the pairs
    for &(ref name, ref value) in &nv_list.pairs {
        // Encode encoded/decoded size
        let encoded_size = 0;
        let decoded_size = 0;

        // Encode name
        try!(xdr.encode_string(name));

        // TODO

        // Encode data type
        try!(xdr.encode_u8(value.data_type().to_u8()));

        // Encode the number of elements
        try!(xdr.encode_i32(value.num_elements() as i32));

        // Encode the value
    }

    // Encode 2 terminating zeros
    try!(xdr.encode_i32(0));
    try!(xdr.encode_i32(0));
    Ok(())
}

fn encode_nv_list_header(xdr: &mut xdr::Xdr) -> xdr::XdrResult<()> {
    let header =
        NvsHeader {
            encoding: NV_ENCODE_XDR,
            endian: NV_LITTLE_ENDIAN,
            reserved1: 0,
            reserved2: 0,
        };
    let header_bytes: [u8; 4] = unsafe { mem::transmute(header) };
    try!(xdr.encode_opaque(&header_bytes));
    Ok(())
}

/// Decodes a NvList in XDR format
pub fn decode_nv_list(xdr: &mut xdr::Xdr) -> xdr::XdrResult<NvList> {
    try!(decode_nv_list_header(xdr));

    decode_nv_list_embedded(xdr)
}

pub fn decode_nv_list_embedded(xdr: &mut xdr::Xdr) -> xdr::XdrResult<NvList> {
    // Decode version and nvflag
    let version = try!(xdr.decode_i32());
    let nvflag = try!(xdr.decode_u32());

    // TODO: Give an actual error
    if version != NV_VERSION {
        return Err(xdr::XdrError);
    }

    let mut nv_list = NvList::new(nvflag);

    // Decode the pairs
    loop {
        // Decode decoded/decoded size
        let encoded_size = try!(xdr.decode_u32());
        let decoded_size = try!(xdr.decode_u32());

        // Check for 2 terminating zeros
        if (encoded_size == 0 && decoded_size == 0) {
            break;
        }

        // Decode name
        let name = try!(xdr.decode_string());

        // Decode data type
        let data_type =
            match DataType::from_u8(try!(xdr.decode_u8())) {
                Some(dt) => dt,
                None => { return Err(xdr::XdrError); },
            };

        // Decode the number of elements
        let num_elements = try!(xdr.decode_i32()) as usize;

        // Decode the value
        let value = try!(decode_nv_value(xdr, data_type, num_elements));

        // Add the value to the list
        nv_list.pairs.push((name, value));
    }

    Ok(nv_list)
}

fn decode_nv_list_header(xdr: &mut xdr::Xdr) -> xdr::XdrResult<()> {
    let mut bytes = [0; 4];
    try!(xdr.decode_opaque(&mut bytes));
    let header: &NvsHeader = unsafe { mem::transmute(&bytes[0]) };

    if header.encoding != NV_ENCODE_XDR {
        return Err(xdr::XdrError);
    }
    Ok(())
}

fn decode_nv_value(xdr: &mut xdr::Xdr, data_type: DataType, num_elements: usize) -> xdr::XdrResult<NvValue> {
    match data_type {
        DataType::Unknown => { Ok(NvValue::Unknown) },
        DataType::Boolean => { Ok(NvValue::Boolean) },
        DataType::Byte => {
            Ok(NvValue::Byte(try!(xdr.decode_u8())))
        },
        DataType::Int16 => {
            Ok(NvValue::Int16(try!(xdr.decode_i16())))
        },
        DataType::Uint16 => {
            Ok(NvValue::Uint16(try!(xdr.decode_u16())))
        },
        DataType::Int32 => {
            Ok(NvValue::Int32(try!(xdr.decode_i32())))
        },
        DataType::Uint32 => {
            Ok(NvValue::Uint32(try!(xdr.decode_u32())))
        },
        DataType::Int64 => {
            Ok(NvValue::Int64(try!(xdr.decode_i64())))
        },
        DataType::Uint64 => {
            Ok(NvValue::Uint64(try!(xdr.decode_u64())))
        },
        DataType::String => {
            Ok(NvValue::String(try!(xdr.decode_string())))
        },
        DataType::ByteArray => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_u8());
            }
            Ok(NvValue::ByteArray(v))
        },
        DataType::Int16Array => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_i16());
            }
            Ok(NvValue::Int16Array(v))
        },
        DataType::Uint16Array => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_u16());
            }
            Ok(NvValue::Uint16Array(v))
        },
        DataType::Int32Array => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_i32());
            }
            Ok(NvValue::Int32Array(v))
        },
        DataType::Uint32Array => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_u32());
            }
            Ok(NvValue::Uint32Array(v))
        },
        DataType::Int64Array => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_i64());
            }
            Ok(NvValue::Int64Array(v))
        },
        DataType::Uint64Array => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_u64());
            }
            Ok(NvValue::Uint64Array(v))
        },
        DataType::StringArray => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_u64());
            }
            Ok(NvValue::Uint64Array(v))
        },
        DataType::HrTime => {
            Ok(NvValue::HrTime)
        },
        DataType::NvList => {
            let nv_list = Box::new(try!(decode_nv_list_embedded(xdr)));
            Ok(NvValue::NvList(nv_list))
        },
        DataType::NvListArray => {
            let mut v = Vec::with_capacity(num_elements);
            for _ in 0..num_elements {
                v.push(Box::new(try!(decode_nv_list_embedded(xdr))));
            }
            Ok(NvValue::NvListArray(v))
        },
        DataType::BooleanValue => {
            Ok(NvValue::BooleanValue(try!(xdr.decode_bool())))
        },
        DataType::Int8 => {
            Ok(NvValue::Int8(try!(xdr.decode_i8())))
        },
        DataType::Uint8 => {
            Ok(NvValue::Uint8(try!(xdr.decode_u8())))
        },
        DataType::BooleanArray => {
            let mut v = vec![false; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_bool());
            }
            Ok(NvValue::BooleanArray(v))
        },
        DataType::Int8Array => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_i8());
            }
            Ok(NvValue::Int8Array(v))
        },
        DataType::Uint8Array => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_u8());
            }
            Ok(NvValue::Uint8Array(v))
        },
    }
}
<commit_msg>Successfully loaded a null nvlist<commit_after>use core::mem;

use redox::*;

use super::nvpair::{DataType, NV_VERSION, NvList, NvValue};
use super::xdr;

// nvlist pack encoding
const NV_ENCODE_NATIVE: u8 = 0;
const NV_ENCODE_XDR:    u8 = 1;

// nvlist pack endian
const NV_BIG_ENDIAN:    u8 = 0;
const NV_LITTLE_ENDIAN: u8 = 1;

// nvlist persistent unique name flags, stored in nvl_nvflags
const NV_UNIQUE_NAME:      u32 = 0x1;
const NV_UNIQUE_NAME_TYPE: u32 = 0x2;

// nvlist lookup pairs related flags
const NV_FLAG_NOENTOK: isize = 0x1;

// NvList XDR format:
// - header (encoding and endian): 4 bytes
// - nvl version: 4 bytes
// - nv flags: 4 bytes
// - nv pairs:
//   - encoded size: 4 bytes
//   - decoded size: 4 bytes
//   - name: xdr string | len: 4 bytes, data: len+(4 - len%4) bytes
//   - data type: 4 bytes
//   - num elements: 4 bytes
//   - data
// - 2 terminating zeros: 4 bytes
//
// NOTE: XDR aligns all of the smaller integer types to be 4 bytes, so `encode_u8` is actually
// writing 4 bytes
//
// I don't know why the ZFS developers decided to use i32's everywhere. Even for clearly
// unsigned things like array lengths.

/// Name value stream header
#[derive(Debug)]
pub struct NvsHeader {
    encoding: u8,  // nvs encoding method
    endian: u8,    // nvs endian
    reserved1: u8, // reserved for future use
    reserved2: u8, // reserved for future use
}

/// Encodes a NvList in XDR format
pub fn encode_nv_list(xdr: &mut xdr::Xdr, nv_list: &NvList) -> xdr::XdrResult<()> {
    try!(encode_nv_list_header(xdr));

    // Encode version and nvflag
    try!(xdr.encode_i32(nv_list.version));
    try!(xdr.encode_u32(nv_list.nvflag));

    // Encode the pairs
    for &(ref name, ref value) in &nv_list.pairs {
        // Encode encoded/decoded size
        let encoded_size = 0;
        let decoded_size = 0;

        // Encode name
        try!(xdr.encode_string(name));

        // TODO

        // Encode data type
        try!(xdr.encode_u8(value.data_type().to_u8()));

        // Encode the number of elements
        try!(xdr.encode_i32(value.num_elements() as i32));

        // Encode the value
    }

    // Encode 2 terminating zeros
    try!(xdr.encode_i32(0));
    try!(xdr.encode_i32(0));
    Ok(())
}

fn encode_nv_list_header(xdr: &mut xdr::Xdr) -> xdr::XdrResult<()> {
    let header =
        NvsHeader {
            encoding: NV_ENCODE_XDR,
            endian: NV_LITTLE_ENDIAN,
            reserved1: 0,
            reserved2: 0,
        };
    let header_bytes: [u8; 4] = unsafe { mem::transmute(header) };
    try!(xdr.encode_opaque(&header_bytes));
    Ok(())
}

/// Decodes a NvList in XDR format
pub fn decode_nv_list(xdr: &mut xdr::Xdr) -> xdr::XdrResult<NvList> {
    println!("Decoding NvList...");

    try!(decode_nv_list_header(xdr));

    println!("Decoded header");

    decode_nv_list_embedded(xdr)
}

pub fn decode_nv_list_embedded(xdr: &mut xdr::Xdr) -> xdr::XdrResult<NvList> {
    // Decode version and nvflag
    let version = try!(xdr.decode_i32());
    let nvflag = try!(xdr.decode_u32());

    println!("Decoded version and nvflag: {}\t{}", version, nvflag);

    // TODO: Give an actual error
    if version != NV_VERSION {
        return Err(xdr::XdrError);
    }

    let mut nv_list = NvList::new(nvflag);

    // Decode the pairs
    loop {
        // Decode decoded/decoded size
        let encoded_size = try!(xdr.decode_u32());
        let decoded_size = try!(xdr.decode_u32());

        println!("Decoded sizes: {}\t{}", encoded_size, decoded_size);

        // Check for 2 terminating zeros
        if (encoded_size == 0 && decoded_size == 0) {
            break;
        }

        // Decode name
        let name = try!(xdr.decode_string());

        println!("Decoded name: {}", name);

        // Decode data type
        let data_type =
            match DataType::from_u8(try!(xdr.decode_u8())) {
                Some(dt) => dt,
                None => { return Err(xdr::XdrError); },
            };

        // Decode the number of elements
        let num_elements = try!(xdr.decode_i32()) as usize;

        // Decode the value
        let value = try!(decode_nv_value(xdr, data_type, num_elements));

        // Add the value to the list
        nv_list.pairs.push((name, value));
    }

    Ok(nv_list)
}

fn decode_nv_list_header(xdr: &mut xdr::Xdr) -> xdr::XdrResult<()> {
    println!("Decoding header...");

    let mut bytes = [0; 4];
    try!(xdr.decode_opaque(&mut bytes));
    let header: &NvsHeader = unsafe { mem::transmute(&bytes[0]) };

    println!("header: {:?}", header);

    /*if header.encoding != NV_ENCODE_XDR {
        return Err(xdr::XdrError);
    }*/
    Ok(())
}

fn decode_nv_value(xdr: &mut xdr::Xdr, data_type: DataType, num_elements: usize) -> xdr::XdrResult<NvValue> {
    match data_type {
        DataType::Unknown => { Ok(NvValue::Unknown) },
        DataType::Boolean => { Ok(NvValue::Boolean) },
        DataType::Byte => {
            Ok(NvValue::Byte(try!(xdr.decode_u8())))
        },
        DataType::Int16 => {
            Ok(NvValue::Int16(try!(xdr.decode_i16())))
        },
        DataType::Uint16 => {
            Ok(NvValue::Uint16(try!(xdr.decode_u16())))
        },
        DataType::Int32 => {
            Ok(NvValue::Int32(try!(xdr.decode_i32())))
        },
        DataType::Uint32 => {
            Ok(NvValue::Uint32(try!(xdr.decode_u32())))
        },
        DataType::Int64 => {
            Ok(NvValue::Int64(try!(xdr.decode_i64())))
        },
        DataType::Uint64 => {
            Ok(NvValue::Uint64(try!(xdr.decode_u64())))
        },
        DataType::String => {
            Ok(NvValue::String(try!(xdr.decode_string())))
        },
        DataType::ByteArray => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_u8());
            }
            Ok(NvValue::ByteArray(v))
        },
        DataType::Int16Array => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_i16());
            }
            Ok(NvValue::Int16Array(v))
        },
        DataType::Uint16Array => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_u16());
            }
            Ok(NvValue::Uint16Array(v))
        },
        DataType::Int32Array => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_i32());
            }
            Ok(NvValue::Int32Array(v))
        },
        DataType::Uint32Array => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_u32());
            }
            Ok(NvValue::Uint32Array(v))
        },
        DataType::Int64Array => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_i64());
            }
            Ok(NvValue::Int64Array(v))
        },
        DataType::Uint64Array => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_u64());
            }
            Ok(NvValue::Uint64Array(v))
        },
        DataType::StringArray => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_u64());
            }
            Ok(NvValue::Uint64Array(v))
        },
        DataType::HrTime => {
            Ok(NvValue::HrTime)
        },
        DataType::NvList => {
            let nv_list = Box::new(try!(decode_nv_list_embedded(xdr)));
            Ok(NvValue::NvList(nv_list))
        },
        DataType::NvListArray => {
            let mut v = Vec::with_capacity(num_elements);
            for _ in 0..num_elements {
                v.push(Box::new(try!(decode_nv_list_embedded(xdr))));
            }
            Ok(NvValue::NvListArray(v))
        },
        DataType::BooleanValue => {
            Ok(NvValue::BooleanValue(try!(xdr.decode_bool())))
        },
        DataType::Int8 => {
            Ok(NvValue::Int8(try!(xdr.decode_i8())))
        },
        DataType::Uint8 => {
            Ok(NvValue::Uint8(try!(xdr.decode_u8())))
        },
        DataType::BooleanArray => {
            let mut v = vec![false; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_bool());
            }
            Ok(NvValue::BooleanArray(v))
        },
        DataType::Int8Array => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_i8());
            }
            Ok(NvValue::Int8Array(v))
        },
        DataType::Uint8Array => {
            let mut v = vec![0; num_elements];
            for v in &mut v {
                *v = try!(xdr.decode_u8());
            }
            Ok(NvValue::Uint8Array(v))
        },
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

extern crate walkdir;
extern crate syntax;

use std::env;
use std::path::Path;
use std::process::Command;
use std::u32;

use self::walkdir::DirEntry;

macro_rules! errorf {
    ($($tt:tt)*) => {
        {
            use ::std::io::Write;
            write!(::std::io::stderr(), $($tt)*).unwrap();
        }
    };
}

pub mod parse;
pub mod respan;

pub fn check_min_stack() {
    let min_stack_value = env::var("RUST_MIN_STACK")
        .expect("RUST_MIN_STACK env var should be set since some tests require it.");
    let min_stack_value: usize = min_stack_value.parse()
        .expect("RUST_MIN_STACK env var should be set since some tests require it.");
    assert!(min_stack_value >= 16000000);
}

/// Read the `ABORT_AFTER_FAILURE` environment variable, and parse it.
pub fn abort_after() -> u32 {
    if let Ok(s) = env::var("ABORT_AFTER_FAILURE") {
        if let Ok(n) = s.parse::<u32>() {
            return n;
        }
    }
    u32::MAX
}

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }
    let path_string = path.to_string_lossy();
    let path_string = if cfg!(windows) {
        path_string.replace('\\', "/").into()
    } else {
        path_string
    };
    // TODO assert that parsing fails on the parse-fail cases
    if path_string.starts_with("tests/rust/src/test/parse-fail") ||
       path_string.starts_with("tests/rust/src/test/compile-fail") {
        return false;
    }

    if path_string.starts_with("tests/rust/src/test/ui") {
        let stderr_path = path.with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    // TODO: support `macro` definitions
    if path_string.starts_with("tests/rust/src/test/run-pass/hygiene") {
        return false;
    }

    match path_string.as_ref() {
        // TODO better support for attributes
        //
        //      let a = A { #[a] b: c };
        "tests/rust/src/librustc_data_structures/blake2b.rs" |
        // TODO better support for attributes
        //
        //      enum A { B = #[a] 2 }
        "tests/rust/src/test/incremental/hashes/enum_defs.rs" |
        // TODO better support for attributes
        //
        //      { #![foo] }
        "tests/rust/src/test/pretty/stmt_expr_attributes.rs" |
        // TODO better support for attributes
        "tests/rust/src/test/run-pass/cfg_stmt_expr.rs" |
        // TODO weird glob import
        //
        //      use ::*;
        "tests/rust/src/test/run-pass/import-glob-crate.rs" |
        // TODO better support for attributes
        //
        //      impl Foo { #![a] }
        "tests/rust/src/test/run-pass/inner-attrs-on-impl.rs" |
        // TODO better support for attributes
        "tests/rust/src/test/run-pass/item-attributes.rs" |
        // TODO support lifetimes before traits
        //
        //      Box<'foo + Bar>
        "tests/rust/src/test/run-pass/trait-object-lifetime-first.rs" |
        // not actually a test case
        "tests/rust/src/test/run-pass/auxiliary/macro-include-items-expr.rs" => false,
        _ => true,
    }
}

pub fn clone_rust() {
    if Path::new("tests/rust").is_dir() {
        return
    }

    println!("cloning rust-lang/rust");
    let result = Command::new("git")
                    .arg("clone")
                    .arg("https://github.com/rust-lang/rust")
                    .arg("tests/rust")
                    .status()
                    .unwrap();
    println!("result: {}", result);
    assert!(result.success());

    println!("reset to known-good rev");
    let result = Command::new("git")
                    .arg("reset")
                    .arg("--hard")
                    .arg("eb8f2586ebd842dec49d3d7f50e49a985ab31493")
                    .current_dir("tests/rust")
                    .status()
                    .unwrap();
    println!("result: {}", result);
    assert!(result.success());
}
<commit_msg>Log output when tests/rust already exists<commit_after>#![allow(dead_code)]

extern crate walkdir;
extern crate syntax;

use std::env;
use std::path::Path;
use std::process::Command;
use std::u32;

use self::walkdir::DirEntry;

macro_rules! errorf {
    ($($tt:tt)*) => {
        {
            use ::std::io::Write;
            write!(::std::io::stderr(), $($tt)*).unwrap();
        }
    };
}

pub mod parse;
pub mod respan;

pub fn check_min_stack() {
    let min_stack_value = env::var("RUST_MIN_STACK")
        .expect("RUST_MIN_STACK env var should be set since some tests require it.");
    let min_stack_value: usize = min_stack_value.parse()
        .expect("RUST_MIN_STACK env var should be set since some tests require it.");
    assert!(min_stack_value >= 16000000);
}

/// Read the `ABORT_AFTER_FAILURE` environment variable, and parse it.
pub fn abort_after() -> u32 {
    if let Ok(s) = env::var("ABORT_AFTER_FAILURE") {
        if let Ok(n) = s.parse::<u32>() {
            return n;
        }
    }
    u32::MAX
}

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }
    let path_string = path.to_string_lossy();
    let path_string = if cfg!(windows) {
        path_string.replace('\\', "/").into()
    } else {
        path_string
    };
    // TODO assert that parsing fails on the parse-fail cases
    if path_string.starts_with("tests/rust/src/test/parse-fail") ||
       path_string.starts_with("tests/rust/src/test/compile-fail") {
        return false;
    }

    if path_string.starts_with("tests/rust/src/test/ui") {
        let stderr_path = path.with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    // TODO: support `macro` definitions
    if path_string.starts_with("tests/rust/src/test/run-pass/hygiene") {
        return false;
    }

    match path_string.as_ref() {
        // TODO better support for attributes
        //
        //      let a = A { #[a] b: c };
        "tests/rust/src/librustc_data_structures/blake2b.rs" |
        // TODO better support for attributes
        //
        //      enum A { B = #[a] 2 }
        "tests/rust/src/test/incremental/hashes/enum_defs.rs" |
        // TODO better support for attributes
        //
        //      { #![foo] }
        "tests/rust/src/test/pretty/stmt_expr_attributes.rs" |
        // TODO better support for attributes
        "tests/rust/src/test/run-pass/cfg_stmt_expr.rs" |
        // TODO weird glob import
        //
        //      use ::*;
        "tests/rust/src/test/run-pass/import-glob-crate.rs" |
        // TODO better support for attributes
        //
        //      impl Foo { #![a] }
        "tests/rust/src/test/run-pass/inner-attrs-on-impl.rs" |
        // TODO better support for attributes
        "tests/rust/src/test/run-pass/item-attributes.rs" |
        // TODO support lifetimes before traits
        //
        //      Box<'foo + Bar>
        "tests/rust/src/test/run-pass/trait-object-lifetime-first.rs" |
        // not actually a test case
        "tests/rust/src/test/run-pass/auxiliary/macro-include-items-expr.rs" => false,
        _ => true,
    }
}

pub fn clone_rust() {
    if Path::new("tests/rust").is_dir() {
        println!("found rust repo in tests/rust");
        return;
    }

    println!("cloning rust-lang/rust");
    let result = Command::new("git")
                    .arg("clone")
                    .arg("https://github.com/rust-lang/rust")
                    .arg("tests/rust")
                    .status()
                    .unwrap();
    println!("result: {}", result);
    assert!(result.success());

    println!("reset to known-good rev");
    let result = Command::new("git")
                    .arg("reset")
                    .arg("--hard")
                    .arg("eb8f2586ebd842dec49d3d7f50e49a985ab31493")
                    .current_dir("tests/rust")
                    .status()
                    .unwrap();
    println!("result: {}", result);
    assert!(result.success());
}
<|endoftext|>


<commit_before>//! Provides different helper functions.

use crate::comparison::best_segments;
use crate::settings::SemanticColor;
use crate::{Run, Segment, TimeSpan, Timer, TimerPhase, TimingMethod};

/// Gets the last non-live delta in the run starting from `segment_index`.
///
/// - `run`: The current run.
/// - `segment_index`: The split number to start checking deltas from.
/// - `comparison`: The comparison that you are comparing with.
/// - `method`: The timing method that you are using.
///
/// Returns the last non-live delta or None if there have been no deltas yet.
pub fn last_delta(
    run: &Run,
    segment_index: usize,
    comparison: &str,
    method: TimingMethod,
) -> Option<TimeSpan> {
    find_previous_non_empty_split_and_comparison_time(
        &run.segments()[..=segment_index],
        comparison,
        method,
    )
    .map(|(split_time, comparison_time)| split_time - comparison_time)
}

fn find_previous_non_empty_segment<F, T>(segments: &[Segment], check_segment: F) -> Option<T>
where
    F: FnMut(&Segment) -> Option<T>,
{
    segments.iter().rev().find_map(check_segment)
}

fn find_previous_non_empty_split_time(
    segments: &[Segment],
    method: TimingMethod,
) -> Option<TimeSpan> {
    find_previous_non_empty_segment(segments, |s| s.split_time()[method])
}

fn find_previous_non_empty_comparison_time(
    segments: &[Segment],
    comparison: &str,
    method: TimingMethod,
) -> Option<TimeSpan> {
    find_previous_non_empty_segment(segments, |s| s.comparison(comparison)[method])
}

fn find_previous_non_empty_split_and_comparison_time(
    segments: &[Segment],
    comparison: &str,
    method: TimingMethod,
) -> Option<(TimeSpan, TimeSpan)> {
    find_previous_non_empty_segment(segments, |s| {
        catch! {
            (s.split_time()[method]?, s.comparison(comparison)[method]?)
        }
    })
}

/// Calculates the comparison's segment time of the segment with the timing
/// method specified. This is not calculating the current attempt's segment
/// times.
pub fn comparison_segment_time(
    run: &Run,
    segment_index: usize,
    comparison: &str,
    method: TimingMethod,
) -> Option<TimeSpan> {
    let current_comparison_time = run.segment(segment_index).comparison(comparison)[method]?;

    let previous_comparison_time = find_previous_non_empty_comparison_time(
        &run.segments()[..segment_index],
        comparison,
        method,
    )
    .unwrap_or_default();

    Some(current_comparison_time - previous_comparison_time)
}

fn segment_delta(
    run: &Run,
    segment_index: usize,
    current_time: TimeSpan,
    comparison: &str,
    method: TimingMethod,
) -> Option<TimeSpan> {
    let segment_index_comparison = run.segment(segment_index).comparison(comparison)[method]?;

    Some(
        find_previous_non_empty_split_and_comparison_time(
            &run.segments()[..segment_index],
            comparison,
            method,
        )
        .map(|(split_time, comparison_time)| {
            (current_time - segment_index_comparison) - (split_time - comparison_time)
        })
        .unwrap_or_else(|| current_time - segment_index_comparison),
    )
}

fn segment_time(
    run: &Run,
    segment_index: usize,
    current_time: TimeSpan,
    method: TimingMethod,
) -> TimeSpan {
    find_previous_non_empty_split_time(&run.segments()[..segment_index], method)
        .map(|split_time| current_time - split_time)
        .unwrap_or(current_time)
}

/// Gets the length of the last segment that leads up to a certain split.
///
/// - `timer`: The current timer.
/// - `segment_index`: The index of the split that represents the end of the
///   segment.
/// - `method`: The timing method that you are using.
///
/// Returns the length of the segment leading up to `segment_index`, returning
/// None if the split is not completed yet.
pub fn previous_segment_time(
    timer: &Timer,
    segment_index: usize,
    method: TimingMethod,
) -> Option<TimeSpan> {
    segment_time(
        timer.run(),
        segment_index,
        timer.run().segment(segment_index).split_time()[method]?,
        method,
    )
    .into()
}

/// Gets the length of the last segment that leads up to a certain split, using
/// the live segment time if the split is not completed yet.
///
/// - `timer`: The current timer.
/// - `segment_index`: The index of the split that represents the end of the
///   segment.
/// - `method`: The timing method that you are using.
///
/// Returns the length of the segment leading up to `segment_index`, returning
/// the live segment time if the split is not completed yet.
pub fn live_segment_time(
    timer: &Timer,
    segment_index: usize,
    method: TimingMethod,
) -> Option<TimeSpan> {
    segment_time(
        timer.run(),
        segment_index,
        timer.current_time()[method]?,
        method,
    )
    .into()
}

/// Gets the amount of time lost or gained on a certain split.
///
/// - `timer`: The current timer.
/// - `segment_index`: The index of the split for which the delta is calculated.
/// - `comparison`: The comparison that you are comparing with.
/// - `method`: The timing method that you are using.
///
/// Returns the segment delta for a certain split, returning None if the split
/// is not completed yet.
pub fn previous_segment_delta(
    timer: &Timer,
    segment_index: usize,
    comparison: &str,
    method: TimingMethod,
) -> Option<TimeSpan> {
    segment_delta(
        timer.run(),
        segment_index,
        timer.run().segment(segment_index).split_time()[method]?,
        comparison,
        method,
    )
}

/// Gets the amount of time lost or gained on a certain split, using the live
/// segment delta if the split is not completed yet.
///
/// - `timer`: The current timer.
/// - `segment_index`: The index of the split for which the delta is calculated.
/// - `comparison`: The comparison that you are comparing with.
/// - `method`: The timing method that you are using.
///
/// Returns the segment delta for a certain split, returning the live segment
/// delta if the split is not completed yet.
pub fn live_segment_delta(
    timer: &Timer,
    segment_index: usize,
    comparison: &str,
    method: TimingMethod,
) -> Option<TimeSpan> {
    segment_delta(
        timer.run(),
        segment_index,
        timer.current_time()[method]?,
        comparison,
        method,
    )
}

/// Checks whether the live segment should now be shown.
///
/// - `timer`: The current timer.
/// - `split_delta`: Specifies whether to return a split delta
///    rather than a segment delta and to start showing the live
///    segment once you are behind.
/// - `comparison`: The comparison that you are comparing with.
/// - `method`: The timing method that you are using.
///
/// Returns the current live delta.
pub fn check_live_delta(
    timer: &Timer,
    split_delta: bool,
    comparison: &str,
    method: TimingMethod,
) -> Option<TimeSpan> {
    if timer.current_phase() == TimerPhase::Running || timer.current_phase() == TimerPhase::Paused {
        let use_best_segment = true; // FIXME: Make this a parameter
        let current_split = timer
            .current_split()
            .unwrap()
            .comparison_timing_method(comparison, method);
        let current_time = timer.current_time()[method];
        let segment_index = timer.current_split_index().unwrap();
        let current_segment = live_segment_time(timer, segment_index, method);
        let best_segment = timer.run().segment(segment_index).best_segment_time()[method];
        let best_segment_delta =
            live_segment_delta(timer, segment_index, best_segments::NAME, method);
        let comparison_delta = live_segment_delta(timer, segment_index, comparison, method);

        if split_delta && current_time > current_split
            || use_best_segment
                && catch! { current_segment? > best_segment? }.unwrap_or(false)
                && best_segment_delta.map_or(false, |d| d > TimeSpan::zero())
            || comparison_delta.map_or(false, |d| d > TimeSpan::zero())
        {
            if split_delta {
                return catch! { current_time? - current_split? };
            } else {
                return comparison_delta;
            }
        }
    }
    None
}

/// Chooses a split color from the Layout Settings based on the current run.
///
/// - `timer`: The current timer.
/// - `time_difference`: The delta that you want to find a color for.
/// - `segment_index`: The split number that is associated with this delta.
/// - `show_segment_deltas`: Can show ahead gaining and behind losing colors if
///    true.
/// - `show_best_segments`: Can show the best segment color if true.
/// - `comparison`: The comparison that you are comparing this delta to.
/// - `method`: The timing method of this delta.
///
/// Returns the chosen color.
pub fn split_color(
    timer: &Timer,
    time_difference: Option<TimeSpan>,
    segment_index: usize,
    show_segment_deltas: bool,
    show_best_segments: bool,
    comparison: &str,
    method: TimingMethod,
) -> SemanticColor {
    let use_best_segment = true; // FIXME: Make this a parameter

    if show_best_segments && use_best_segment && check_best_segment(timer, segment_index, method) {
        SemanticColor::BestSegment
    } else if let Some(time_difference) = time_difference {
        let last_delta = segment_index
            .checked_sub(1)
            .and_then(|n| last_delta(timer.run(), n, comparison, method));
        if time_difference < TimeSpan::zero() {
            if show_segment_deltas && last_delta.map_or(false, |d| time_difference > d) {
                SemanticColor::AheadLosingTime
            } else {
                SemanticColor::AheadGainingTime
            }
        } else if show_segment_deltas && last_delta.map_or(false, |d| time_difference < d) {
            SemanticColor::BehindGainingTime
        } else {
            SemanticColor::BehindLosingTime
        }
    } else {
        SemanticColor::Default
    }
}

/// Calculates whether or not the Split Times for the indicated split qualify as
/// a Best Segment.
///
/// - `timer`: The current timer.
/// - `segment_index`: The split to check.
/// - `method`: The timing method to use.
///
/// Returns whether or not the indicated split is a Best Segment.
pub fn check_best_segment(timer: &Timer, segment_index: usize, method: TimingMethod) -> bool {
    if timer.run().segment(segment_index).split_time()[method].is_none() {
        return false;
    }

    let delta = previous_segment_delta(timer, segment_index, best_segments::NAME, method);
    let current_segment = previous_segment_time(timer, segment_index, method);
    let best_segment = timer.run().segment(segment_index).best_segment_time()[method];
    best_segment.map_or(true, |b| {
        current_segment.map_or(false, |c| c < b) || delta.map_or(false, |d| d < TimeSpan::zero())
    })
}
<commit_msg>Remove the ability to not use Best Segment Coloring<commit_after>//! Provides different helper functions.

use crate::comparison::best_segments;
use crate::settings::SemanticColor;
use crate::{Run, Segment, TimeSpan, Timer, TimerPhase, TimingMethod};

/// Gets the last non-live delta in the run starting from `segment_index`.
///
/// - `run`: The current run.
/// - `segment_index`: The split number to start checking deltas from.
/// - `comparison`: The comparison that you are comparing with.
/// - `method`: The timing method that you are using.
///
/// Returns the last non-live delta or None if there have been no deltas yet.
pub fn last_delta(
    run: &Run,
    segment_index: usize,
    comparison: &str,
    method: TimingMethod,
) -> Option<TimeSpan> {
    find_previous_non_empty_split_and_comparison_time(
        &run.segments()[..=segment_index],
        comparison,
        method,
    )
    .map(|(split_time, comparison_time)| split_time - comparison_time)
}

fn find_previous_non_empty_segment<F, T>(segments: &[Segment], check_segment: F) -> Option<T>
where
    F: FnMut(&Segment) -> Option<T>,
{
    segments.iter().rev().find_map(check_segment)
}

fn find_previous_non_empty_split_time(
    segments: &[Segment],
    method: TimingMethod,
) -> Option<TimeSpan> {
    find_previous_non_empty_segment(segments, |s| s.split_time()[method])
}

fn find_previous_non_empty_comparison_time(
    segments: &[Segment],
    comparison: &str,
    method: TimingMethod,
) -> Option<TimeSpan> {
    find_previous_non_empty_segment(segments, |s| s.comparison(comparison)[method])
}

fn find_previous_non_empty_split_and_comparison_time(
    segments: &[Segment],
    comparison: &str,
    method: TimingMethod,
) -> Option<(TimeSpan, TimeSpan)> {
    find_previous_non_empty_segment(segments, |s| {
        catch! {
            (s.split_time()[method]?, s.comparison(comparison)[method]?)
        }
    })
}

/// Calculates the comparison's segment time of the segment with the timing
/// method specified. This is not calculating the current attempt's segment
/// times.
pub fn comparison_segment_time(
    run: &Run,
    segment_index: usize,
    comparison: &str,
    method: TimingMethod,
) -> Option<TimeSpan> {
    let current_comparison_time = run.segment(segment_index).comparison(comparison)[method]?;

    let previous_comparison_time = find_previous_non_empty_comparison_time(
        &run.segments()[..segment_index],
        comparison,
        method,
    )
    .unwrap_or_default();

    Some(current_comparison_time - previous_comparison_time)
}

fn segment_delta(
    run: &Run,
    segment_index: usize,
    current_time: TimeSpan,
    comparison: &str,
    method: TimingMethod,
) -> Option<TimeSpan> {
    let segment_index_comparison = run.segment(segment_index).comparison(comparison)[method]?;

    Some(
        find_previous_non_empty_split_and_comparison_time(
            &run.segments()[..segment_index],
            comparison,
            method,
        )
        .map(|(split_time, comparison_time)| {
            (current_time - segment_index_comparison) - (split_time - comparison_time)
        })
        .unwrap_or_else(|| current_time - segment_index_comparison),
    )
}

fn segment_time(
    run: &Run,
    segment_index: usize,
    current_time: TimeSpan,
    method: TimingMethod,
) -> TimeSpan {
    find_previous_non_empty_split_time(&run.segments()[..segment_index], method)
        .map(|split_time| current_time - split_time)
        .unwrap_or(current_time)
}

/// Gets the length of the last segment that leads up to a certain split.
///
/// - `timer`: The current timer.
/// - `segment_index`: The index of the split that represents the end of the
///   segment.
/// - `method`: The timing method that you are using.
///
/// Returns the length of the segment leading up to `segment_index`, returning
/// None if the split is not completed yet.
pub fn previous_segment_time(
    timer: &Timer,
    segment_index: usize,
    method: TimingMethod,
) -> Option<TimeSpan> {
    segment_time(
        timer.run(),
        segment_index,
        timer.run().segment(segment_index).split_time()[method]?,
        method,
    )
    .into()
}

/// Gets the length of the last segment that leads up to a certain split, using
/// the live segment time if the split is not completed yet.
///
/// - `timer`: The current timer.
/// - `segment_index`: The index of the split that represents the end of the
///   segment.
/// - `method`: The timing method that you are using.
///
/// Returns the length of the segment leading up to `segment_index`, returning
/// the live segment time if the split is not completed yet.
pub fn live_segment_time(
    timer: &Timer,
    segment_index: usize,
    method: TimingMethod,
) -> Option<TimeSpan> {
    segment_time(
        timer.run(),
        segment_index,
        timer.current_time()[method]?,
        method,
    )
    .into()
}

/// Gets the amount of time lost or gained on a certain split.
///
/// - `timer`: The current timer.
/// - `segment_index`: The index of the split for which the delta is calculated.
/// - `comparison`: The comparison that you are comparing with.
/// - `method`: The timing method that you are using.
///
/// Returns the segment delta for a certain split, returning None if the split
/// is not completed yet.
pub fn previous_segment_delta(
    timer: &Timer,
    segment_index: usize,
    comparison: &str,
    method: TimingMethod,
) -> Option<TimeSpan> {
    segment_delta(
        timer.run(),
        segment_index,
        timer.run().segment(segment_index).split_time()[method]?,
        comparison,
        method,
    )
}

/// Gets the amount of time lost or gained on a certain split, using the live
/// segment delta if the split is not completed yet.
///
/// - `timer`: The current timer.
/// - `segment_index`: The index of the split for which the delta is calculated.
/// - `comparison`: The comparison that you are comparing with.
/// - `method`: The timing method that you are using.
///
/// Returns the segment delta for a certain split, returning the live segment
/// delta if the split is not completed yet.
pub fn live_segment_delta(
    timer: &Timer,
    segment_index: usize,
    comparison: &str,
    method: TimingMethod,
) -> Option<TimeSpan> {
    segment_delta(
        timer.run(),
        segment_index,
        timer.current_time()[method]?,
        comparison,
        method,
    )
}

/// Checks whether the live segment should now be shown.
///
/// - `timer`: The current timer.
/// - `split_delta`: Specifies whether to return a split delta
///    rather than a segment delta and to start showing the live
///    segment once you are behind.
/// - `comparison`: The comparison that you are comparing with.
/// - `method`: The timing method that you are using.
///
/// Returns the current live delta.
pub fn check_live_delta(
    timer: &Timer,
    split_delta: bool,
    comparison: &str,
    method: TimingMethod,
) -> Option<TimeSpan> {
    if timer.current_phase() == TimerPhase::Running || timer.current_phase() == TimerPhase::Paused {
        let current_split = timer
            .current_split()
            .unwrap()
            .comparison_timing_method(comparison, method);
        let current_time = timer.current_time()[method];
        let segment_index = timer.current_split_index().unwrap();
        let current_segment = live_segment_time(timer, segment_index, method);
        let best_segment = timer.run().segment(segment_index).best_segment_time()[method];
        let best_segment_delta =
            live_segment_delta(timer, segment_index, best_segments::NAME, method);
        let comparison_delta = live_segment_delta(timer, segment_index, comparison, method);

        if split_delta && current_time > current_split
            || catch! { current_segment? > best_segment? }.unwrap_or(false)
                && best_segment_delta.map_or(false, |d| d > TimeSpan::zero())
            || comparison_delta.map_or(false, |d| d > TimeSpan::zero())
        {
            if split_delta {
                return catch! { current_time? - current_split? };
            } else {
                return comparison_delta;
            }
        }
    }
    None
}

/// Chooses a split color from the Layout Settings based on the current run.
///
/// - `timer`: The current timer.
/// - `time_difference`: The delta that you want to find a color for.
/// - `segment_index`: The split number that is associated with this delta.
/// - `show_segment_deltas`: Can show ahead gaining and behind losing colors if
///    true.
/// - `show_best_segments`: Can show the best segment color if true.
/// - `comparison`: The comparison that you are comparing this delta to.
/// - `method`: The timing method of this delta.
///
/// Returns the chosen color.
pub fn split_color(
    timer: &Timer,
    time_difference: Option<TimeSpan>,
    segment_index: usize,
    show_segment_deltas: bool,
    show_best_segments: bool,
    comparison: &str,
    method: TimingMethod,
) -> SemanticColor {
    if show_best_segments && check_best_segment(timer, segment_index, method) {
        SemanticColor::BestSegment
    } else if let Some(time_difference) = time_difference {
        let last_delta = segment_index
            .checked_sub(1)
            .and_then(|n| last_delta(timer.run(), n, comparison, method));
        if time_difference < TimeSpan::zero() {
            if show_segment_deltas && last_delta.map_or(false, |d| time_difference > d) {
                SemanticColor::AheadLosingTime
            } else {
                SemanticColor::AheadGainingTime
            }
        } else if show_segment_deltas && last_delta.map_or(false, |d| time_difference < d) {
            SemanticColor::BehindGainingTime
        } else {
            SemanticColor::BehindLosingTime
        }
    } else {
        SemanticColor::Default
    }
}

/// Calculates whether or not the Split Times for the indicated split qualify as
/// a Best Segment.
///
/// - `timer`: The current timer.
/// - `segment_index`: The split to check.
/// - `method`: The timing method to use.
///
/// Returns whether or not the indicated split is a Best Segment.
pub fn check_best_segment(timer: &Timer, segment_index: usize, method: TimingMethod) -> bool {
    if timer.run().segment(segment_index).split_time()[method].is_none() {
        return false;
    }

    let delta = previous_segment_delta(timer, segment_index, best_segments::NAME, method);
    let current_segment = previous_segment_time(timer, segment_index, method);
    let best_segment = timer.run().segment(segment_index).best_segment_time()[method];
    best_segment.map_or(true, |b| {
        current_segment.map_or(false, |c| c < b) || delta.map_or(false, |d| d < TimeSpan::zero())
    })
}
<|endoftext|>


<commit_before>use std::io::{self, Write};
use term::{self, Attr, Result, Terminal};
use term::color::Color;

/// A `Terminal` that just ignores all attempts at formatting. Used
/// to report errors when no ANSI terminfo is available.
pub struct FakeTerminal<W: Write> {
    write: W
}

impl<W: Write> FakeTerminal<W> {
    pub fn new(write: W) -> FakeTerminal<W> {
        FakeTerminal { write: write }
    }
}

impl<W: Write> Write for FakeTerminal<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.write.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.write.flush()
    }
}

impl<W: Write> Terminal for FakeTerminal<W> {
    type Output = W;

    fn fg(&mut self, _color: Color) -> term::Result<()> {
        Ok(())
    }

    fn bg(&mut self, _color: Color) -> term::Result<()> {
        Ok(())
    }

    fn attr(&mut self, _attr: Attr) -> term::Result<()> {
        Ok(())
    }

    fn supports_attr(&self, _attr: Attr) -> bool {
        false
    }

    fn reset(&mut self) -> term::Result<()> {
        Ok(())
    }

    fn supports_reset(&self) -> bool {
        false
    }

    fn supports_color(&self) -> bool {
        false
    }

    fn cursor_up(&mut self) -> term::Result<()> {
        Ok(())
    }

    fn delete_line(&mut self) -> term::Result<()> {
        Ok(())
    }

    fn carriage_return(&mut self) -> term::Result<()> {
        Ok(())
    }

    fn get_ref(&self) -> &Self::Output {
        &self.write
    }

    fn get_mut(&mut self) -> &mut Self::Output {
        &mut self.write
    }

    fn into_inner(self) -> Self::Output where Self: Sized {
        self.write
    }
}
<commit_msg>Kill another unused import.<commit_after>use std::io::{self, Write};
use term::{self, Attr, Terminal};
use term::color::Color;

/// A `Terminal` that just ignores all attempts at formatting. Used
/// to report errors when no ANSI terminfo is available.
pub struct FakeTerminal<W: Write> {
    write: W
}

impl<W: Write> FakeTerminal<W> {
    pub fn new(write: W) -> FakeTerminal<W> {
        FakeTerminal { write: write }
    }
}

impl<W: Write> Write for FakeTerminal<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.write.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.write.flush()
    }
}

impl<W: Write> Terminal for FakeTerminal<W> {
    type Output = W;

    fn fg(&mut self, _color: Color) -> term::Result<()> {
        Ok(())
    }

    fn bg(&mut self, _color: Color) -> term::Result<()> {
        Ok(())
    }

    fn attr(&mut self, _attr: Attr) -> term::Result<()> {
        Ok(())
    }

    fn supports_attr(&self, _attr: Attr) -> bool {
        false
    }

    fn reset(&mut self) -> term::Result<()> {
        Ok(())
    }

    fn supports_reset(&self) -> bool {
        false
    }

    fn supports_color(&self) -> bool {
        false
    }

    fn cursor_up(&mut self) -> term::Result<()> {
        Ok(())
    }

    fn delete_line(&mut self) -> term::Result<()> {
        Ok(())
    }

    fn carriage_return(&mut self) -> term::Result<()> {
        Ok(())
    }

    fn get_ref(&self) -> &Self::Output {
        &self.write
    }

    fn get_mut(&mut self) -> &mut Self::Output {
        &mut self.write
    }

    fn into_inner(self) -> Self::Output where Self: Sized {
        self.write
    }
}
<|endoftext|>