<commit_before>//! Installs rust-analyzer language server and/or editor plugin.

use std::{env, path::PathBuf, str};

use anyhow::{bail, format_err, Context, Result};
use xshell::{cmd, pushd};

use crate::flags;

// Latest stable, feel free to send a PR if this lags behind.
const REQUIRED_RUST_VERSION: u32 = 50;

impl flags::Install {
    pub(crate) fn run(self) -> Result<()> {
        if cfg!(target_os = "macos") {
            fix_path_for_mac().context("Fix path for mac")?
        }
        if let Some(server) = self.server() {
            install_server(server).context("install server")?;
        }
        if let Some(client) = self.client() {
            install_client(client).context("install client")?;
        }
        Ok(())
    }
}

#[derive(Clone)]
pub(crate) struct ClientOpt {
    pub(crate) code_bin: Option<String>,
}

const VS_CODES: &[&str] = &["code", "code-exploration", "code-insiders", "codium", "code-oss"];

pub(crate) struct ServerOpt {
    pub(crate) malloc: Malloc,
}

pub(crate) enum Malloc {
    System,
    Mimalloc,
    Jemalloc,
}

fn fix_path_for_mac() -> Result<()> {
    let mut vscode_path: Vec<PathBuf> = {
        const COMMON_APP_PATH: &str =
            r"/Applications/Visual Studio Code.app/Contents/Resources/app/bin";
        const ROOT_DIR: &str = "";
        let home_dir = match env::var("HOME") {
            Ok(home) => home,
            Err(e) => bail!("Failed getting HOME from environment with error: {}.", e),
        };

        [ROOT_DIR, &home_dir]
            .iter()
            .map(|dir| String::from(*dir) + COMMON_APP_PATH)
            .map(PathBuf::from)
            .filter(|path| path.exists())
            .collect()
    };

    if !vscode_path.is_empty() {
        let vars = match env::var_os("PATH") {
            Some(path) => path,
            None => bail!("Could not get PATH variable from env."),
        };

        let mut paths = env::split_paths(&vars).collect::<Vec<_>>();
        paths.append(&mut vscode_path);
        let new_paths = env::join_paths(paths).context("build env PATH")?;
        env::set_var("PATH", &new_paths);
    }

    Ok(())
}

fn install_client(client_opt: ClientOpt) -> Result<()> {
    let _dir = pushd("./editors/code");

    // Package extension.
    if cfg!(unix) {
        cmd!("npm --version").run().context("`npm` is required to build the VS Code plugin")?;
        cmd!("npm ci").run()?;

        cmd!("npm run package --scripts-prepend-node-path").run()?;
    } else {
        cmd!("cmd.exe /c npm --version")
            .run()
            .context("`npm` is required to build the VS Code plugin")?;
        cmd!("cmd.exe /c npm ci").run()?;

        cmd!("cmd.exe /c npm run package").run()?;
    };

    // Find the appropriate VS Code binary.
    let lifetime_extender;
    let candidates: &[&str] = match client_opt.code_bin.as_deref() {
        Some(it) => {
            lifetime_extender = [it];
            &lifetime_extender[..]
        }
        None => VS_CODES,
    };
    let code = candidates
        .iter()
        .copied()
        .find(|&bin| {
            if cfg!(unix) {
                cmd!("{bin} --version").read().is_ok()
            } else {
                cmd!("cmd.exe /c {bin}.cmd --version").read().is_ok()
            }
        })
        .ok_or_else(|| {
            format_err!("Can't execute `{} --version`. Perhaps it is not in $PATH?", candidates[0])
        })?;

    // Install & verify.
    let installed_extensions = if cfg!(unix) {
        cmd!("{code} --install-extension rust-analyzer.vsix --force").run()?;
        cmd!("{code} --list-extensions").read()?
    } else {
        cmd!("cmd.exe /c {code}.cmd --install-extension rust-analyzer.vsix --force").run()?;
        cmd!("cmd.exe /c {code}.cmd --list-extensions").read()?
    };

    if !installed_extensions.contains("rust-analyzer") {
        bail!(
            "Could not install the Visual Studio Code extension. \
            Please make sure you have at least NodeJS 12.x together with the latest version of VS Code installed and try again. \
            Note that installing via xtask install does not work for VS Code Remote, instead you’ll need to install the .vsix manually."
        );
    }

    Ok(())
}

fn install_server(opts: ServerOpt) -> Result<()> {
    let mut old_rust = false;
    if let Ok(stdout) = cmd!("cargo --version").read() {
        if !check_version(&stdout, REQUIRED_RUST_VERSION) {
            old_rust = true;
        }
    }

    if old_rust {
        eprintln!(
            "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
            REQUIRED_RUST_VERSION,
        )
    }
    let features = match opts.malloc {
        Malloc::System => &[][..],
        Malloc::Mimalloc => &["--features", "mimalloc"],
        Malloc::Jemalloc => &["--features", "jemalloc"],
    };

    let cmd = cmd!("cargo install --path crates/rust-analyzer --locked --force --features force-always-assert {features...}");
    let res = cmd.run();

    if res.is_err() && old_rust {
        eprintln!(
            "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
            REQUIRED_RUST_VERSION,
        );
    }

    res?;
    Ok(())
}

fn check_version(version_output: &str, min_minor_version: u32) -> bool {
    // Parse second the number out of
    //      cargo 1.39.0-beta (1c6ec66d5 2019-09-30)
    let minor: Option<u32> = version_output.split('.').nth(1).and_then(|it| it.parse().ok());
    match minor {
        None => true,
        Some(minor) => minor >= min_minor_version,
    }
}
<commit_msg>Rust 1.51<commit_after>//! Installs rust-analyzer language server and/or editor plugin.

use std::{env, path::PathBuf, str};

use anyhow::{bail, format_err, Context, Result};
use xshell::{cmd, pushd};

use crate::flags;

// Latest stable, feel free to send a PR if this lags behind.
const REQUIRED_RUST_VERSION: u32 = 51;

impl flags::Install {
    pub(crate) fn run(self) -> Result<()> {
        if cfg!(target_os = "macos") {
            fix_path_for_mac().context("Fix path for mac")?
        }
        if let Some(server) = self.server() {
            install_server(server).context("install server")?;
        }
        if let Some(client) = self.client() {
            install_client(client).context("install client")?;
        }
        Ok(())
    }
}

#[derive(Clone)]
pub(crate) struct ClientOpt {
    pub(crate) code_bin: Option<String>,
}

const VS_CODES: &[&str] = &["code", "code-exploration", "code-insiders", "codium", "code-oss"];

pub(crate) struct ServerOpt {
    pub(crate) malloc: Malloc,
}

pub(crate) enum Malloc {
    System,
    Mimalloc,
    Jemalloc,
}

fn fix_path_for_mac() -> Result<()> {
    let mut vscode_path: Vec<PathBuf> = {
        const COMMON_APP_PATH: &str =
            r"/Applications/Visual Studio Code.app/Contents/Resources/app/bin";
        const ROOT_DIR: &str = "";
        let home_dir = match env::var("HOME") {
            Ok(home) => home,
            Err(e) => bail!("Failed getting HOME from environment with error: {}.", e),
        };

        [ROOT_DIR, &home_dir]
            .iter()
            .map(|dir| String::from(*dir) + COMMON_APP_PATH)
            .map(PathBuf::from)
            .filter(|path| path.exists())
            .collect()
    };

    if !vscode_path.is_empty() {
        let vars = match env::var_os("PATH") {
            Some(path) => path,
            None => bail!("Could not get PATH variable from env."),
        };

        let mut paths = env::split_paths(&vars).collect::<Vec<_>>();
        paths.append(&mut vscode_path);
        let new_paths = env::join_paths(paths).context("build env PATH")?;
        env::set_var("PATH", &new_paths);
    }

    Ok(())
}

fn install_client(client_opt: ClientOpt) -> Result<()> {
    let _dir = pushd("./editors/code");

    // Package extension.
    if cfg!(unix) {
        cmd!("npm --version").run().context("`npm` is required to build the VS Code plugin")?;
        cmd!("npm ci").run()?;

        cmd!("npm run package --scripts-prepend-node-path").run()?;
    } else {
        cmd!("cmd.exe /c npm --version")
            .run()
            .context("`npm` is required to build the VS Code plugin")?;
        cmd!("cmd.exe /c npm ci").run()?;

        cmd!("cmd.exe /c npm run package").run()?;
    };

    // Find the appropriate VS Code binary.
    let lifetime_extender;
    let candidates: &[&str] = match client_opt.code_bin.as_deref() {
        Some(it) => {
            lifetime_extender = [it];
            &lifetime_extender[..]
        }
        None => VS_CODES,
    };
    let code = candidates
        .iter()
        .copied()
        .find(|&bin| {
            if cfg!(unix) {
                cmd!("{bin} --version").read().is_ok()
            } else {
                cmd!("cmd.exe /c {bin}.cmd --version").read().is_ok()
            }
        })
        .ok_or_else(|| {
            format_err!("Can't execute `{} --version`. Perhaps it is not in $PATH?", candidates[0])
        })?;

    // Install & verify.
    let installed_extensions = if cfg!(unix) {
        cmd!("{code} --install-extension rust-analyzer.vsix --force").run()?;
        cmd!("{code} --list-extensions").read()?
    } else {
        cmd!("cmd.exe /c {code}.cmd --install-extension rust-analyzer.vsix --force").run()?;
        cmd!("cmd.exe /c {code}.cmd --list-extensions").read()?
    };

    if !installed_extensions.contains("rust-analyzer") {
        bail!(
            "Could not install the Visual Studio Code extension. \
            Please make sure you have at least NodeJS 12.x together with the latest version of VS Code installed and try again. \
            Note that installing via xtask install does not work for VS Code Remote, instead you’ll need to install the .vsix manually."
        );
    }

    Ok(())
}

fn install_server(opts: ServerOpt) -> Result<()> {
    let mut old_rust = false;
    if let Ok(stdout) = cmd!("cargo --version").read() {
        if !check_version(&stdout, REQUIRED_RUST_VERSION) {
            old_rust = true;
        }
    }

    if old_rust {
        eprintln!(
            "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
            REQUIRED_RUST_VERSION,
        )
    }
    let features = match opts.malloc {
        Malloc::System => &[][..],
        Malloc::Mimalloc => &["--features", "mimalloc"],
        Malloc::Jemalloc => &["--features", "jemalloc"],
    };

    let cmd = cmd!("cargo install --path crates/rust-analyzer --locked --force --features force-always-assert {features...}");
    let res = cmd.run();

    if res.is_err() && old_rust {
        eprintln!(
            "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
            REQUIRED_RUST_VERSION,
        );
    }

    res?;
    Ok(())
}

fn check_version(version_output: &str, min_minor_version: u32) -> bool {
    // Parse second the number out of
    //      cargo 1.39.0-beta (1c6ec66d5 2019-09-30)
    let minor: Option<u32> = version_output.split('.').nth(1).and_then(|it| it.parse().ok());
    match minor {
        None => true,
        Some(minor) => minor >= min_minor_version,
    }
}
<|endoftext|>


<commit_before>///! File system utilities, particularly functionality that requires
///! alternative implementations for alternative operating systems.
use eyre::Result;
use std::{fs, os, path::Path};

/// Set permissions on a file
pub fn set_perms<File: AsRef<Path>>(path: File, mode: u32) -> Result<()> {
    #[cfg(any(target_os = "linux", target_os = "macos"))]
    {
        use os::unix::fs::PermissionsExt;
        fs::set_permissions(path, fs::Permissions::from_mode(mode))?;
    }

    Ok(())
}

/// Create a symbolic (soft) link to a file
pub fn symlink_file<Original: AsRef<Path>, Link: AsRef<Path>>(
    original: Original,
    link: Link,
) -> Result<()> {
    #[cfg(any(target_os = "linux", target_os = "macos"))]
    os::unix::fs::symlink(original, link)?;

    #[cfg(target_os = "windows")]
    os::windows::fs::symlink_file(original, link)?;

    Ok(())
}

/// Create a symbolic (soft) link to a directory
pub fn symlink_dir<Original: AsRef<Path>, Link: AsRef<Path>>(
    original: Original,
    link: Link,
) -> Result<()> {
    #[cfg(any(target_os = "linux", target_os = "macos"))]
    os::unix::fs::symlink(original, link)?;

    #[cfg(target_os = "windows")]
    os::windows::fs::symlink_dir(original, link)?;

    Ok(())
}
<commit_msg>chore(Rust): Avoid linting warnings when on Windows<commit_after>///! File system utilities, particularly functionality that requires
///! alternative implementations for alternative operating systems.
use eyre::Result;
use std::{os, path::Path};

/// Set permissions on a file
#[allow(unused_variables)]
pub fn set_perms<File: AsRef<Path>>(path: File, mode: u32) -> Result<()> {
    #[cfg(any(target_os = "linux", target_os = "macos"))]
    {
        use os::unix::fs::PermissionsExt;
        std::fs::set_permissions(path, std::fs::Permissions::from_mode(mode))?;
    }

    Ok(())
}

/// Create a symbolic (soft) link to a file
pub fn symlink_file<Original: AsRef<Path>, Link: AsRef<Path>>(
    original: Original,
    link: Link,
) -> Result<()> {
    #[cfg(any(target_os = "linux", target_os = "macos"))]
    os::unix::fs::symlink(original, link)?;

    #[cfg(target_os = "windows")]
    os::windows::fs::symlink_file(original, link)?;

    Ok(())
}

/// Create a symbolic (soft) link to a directory
pub fn symlink_dir<Original: AsRef<Path>, Link: AsRef<Path>>(
    original: Original,
    link: Link,
) -> Result<()> {
    #[cfg(any(target_os = "linux", target_os = "macos"))]
    os::unix::fs::symlink(original, link)?;

    #[cfg(target_os = "windows")]
    os::windows::fs::symlink_dir(original, link)?;

    Ok(())
}
<|endoftext|>


<commit_before>//!Convert colors from one reference white point to another
//!
//!Chromatic adaptation is the human visual system’s ability to adjust to changes
//!in illumination in order to preserve the appearance of object colors. It is responsible
//!for the stable appearance of object colours despite the wide variation of light which
//!might be reflected from an object and observed by our eyes.
//!
//!This library provides three methods for chromatic adaptation Bradford (which is the default),
//!VonKries and XyzScaling
//!
//!```
//!use palette::Xyz;
//!use palette::white_point::{A, C};
//!use palette::chromatic_adaptation::AdaptInto;
//!
//!
//!let a = Xyz::<A, f32>::with_wp(0.315756, 0.162732, 0.015905);
//!
//!//Will convert Xyz<A, f32> to Xyz<C, f32> using Bradford chromatic adaptation
//!let c: Xyz<C, f32> = a.adapt_into();
//!
//!//Should print {x: 0.257963, y: 0.139776,z: 0.058825}
//!println!("{:?}", c)
//!```
use float::Float;

use {cast, Component, FromColor, IntoColor, Xyz};
use white_point::WhitePoint;
use matrix::{multiply_xyz, Mat3, multiply_3x3};

///Chromatic adaptation methods implemented in the library
pub enum Method {
    ///Bradford chromatic adaptation method
    Bradford,
    ///VonKries chromatic adaptation method
    VonKries,
    ///XyzScaling chromatic adaptation method
    XyzScaling,
}

///Holds the matrix coeffecients for the chromatic adaptation methods
pub struct ConeResponseMatrices<T: Float> {
    ///3x3 matrix for the cone response domains
    pub ma: Mat3<T>,
    ///3x3 matrix for the inverse of the cone response domains
    pub inv_ma: Mat3<T>,
}

///Generates a conversion matrix to convert the Xyz trisitmilus values from
///one illuminant to another (Swp -> Dwp)
pub trait TransformMatrix<Swp, Dwp, T>
where
    T: Component + Float,
    Swp: WhitePoint,
    Dwp: WhitePoint,
{
    ///Get the cone response functions for the chromatic adaptation method
    fn get_cone_response(&self) -> ConeResponseMatrices<T>;

    ///Generates a 3x3 transformation matrix to convert color from one reference white point
    ///to another with the given cone_response
    fn generate_transform_matrix(&self) -> Mat3<T> {
        let s_wp: Xyz<Swp, T> = Swp::get_xyz();
        let t_wp: Xyz<Dwp, T> = Dwp::get_xyz();
        let adapt = self.get_cone_response();

        let resp_src: Xyz<Swp, _> = multiply_xyz(&adapt.ma, &s_wp);
        let resp_dst: Xyz<Dwp, _> = multiply_xyz(&adapt.ma, &t_wp);
        let z = T::zero();
        let resp = [
            resp_dst.x / resp_src.x,
            z,
            z,
            z,
            resp_dst.y / resp_src.y,
            z,
            z,
            z,
            resp_dst.z / resp_src.z,
        ];

        let tmp = multiply_3x3(&resp, &adapt.ma);
        multiply_3x3(&adapt.inv_ma, &tmp)
    }
}

impl<Swp, Dwp, T> TransformMatrix<Swp, Dwp, T> for Method
where
    T: Component + Float,
    Swp: WhitePoint,
    Dwp: WhitePoint,
{
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn get_cone_response(&self) -> ConeResponseMatrices<T> {
        match *self {
             Method::Bradford => {
                ConeResponseMatrices::<T> {
                    ma: [cast(0.8951000), cast(0.2664000), cast(-0.1614000),
                         cast(-0.7502000), cast(1.7135000), cast(0.0367000),
                         cast(0.0389000), cast(-0.0685000), cast(1.0296000)
                         ],
                    inv_ma: [cast(0.9869929), cast(-0.1470543), cast(0.1599627),
                             cast(0.4323053), cast(0.5183603), cast(0.0492912),
                             cast(-0.0085287), cast(0.0400428), cast(0.9684867)
                            ],
                }
            }
             Method::VonKries => {
                ConeResponseMatrices::<T> {
                    ma: [cast(0.4002400), cast(0.7076000), cast(-0.0808100),
                         cast(-0.2263000), cast(1.1653200), cast(0.0457000),
                         cast(0.0000000), cast(0.0000000), cast(0.9182200)
                         ],
                    inv_ma: [cast(1.8599364), cast(-1.1293816), cast(0.2198974),
                             cast(0.3611914), cast(0.6388125), cast(-0.0000064),
                             cast(0.0000000), cast(0.0000000), cast(1.0890636)
                             ],
                }
            }
             Method::XyzScaling => {
                ConeResponseMatrices::<T> {
                    ma: [cast(1.0000000), cast(0.0000000), cast(0.0000000),
                         cast(0.0000000), cast(1.0000000), cast(0.0000000),
                         cast(0.0000000), cast(0.0000000), cast(1.0000000)
                         ],
                    inv_ma: [cast(1.0000000), cast(0.0000000), cast(0.0000000),
                             cast(0.0000000), cast(1.0000000), cast(0.0000000),
                             cast(0.0000000), cast(0.0000000), cast(1.0000000)
                             ],
                }
            }
        }
    }
}

///Trait to convert color from one reference white point to another
///
///Converts a color from the source white point (Swp) to the destination white point (Dwp).
///Uses the bradford method for conversion by default.
pub trait AdaptFrom<S, Swp, Dwp, T>: Sized
where
    T: Component + Float,
    Swp: WhitePoint,
    Dwp: WhitePoint,
{
    ///Convert the source color to the destination color using the bradford
    /// method by default
    fn adapt_from(color: S) -> Self {
        Self::adapt_from_using(color, Method::Bradford)
    }
    ///Convert the source color to the destination color using the specified
    /// method
    fn adapt_from_using<M: TransformMatrix<Swp, Dwp, T>>(color: S, method: M) -> Self;
}

impl<S, D, Swp, Dwp, T> AdaptFrom<S, Swp, Dwp, T> for D
where
    T: Component + Float,
    Swp: WhitePoint,
    Dwp: WhitePoint,
    S: IntoColor<Swp, T>,
    D: FromColor<Dwp, T>,
{
    fn adapt_from_using<M: TransformMatrix<Swp, Dwp, T>>(color: S, method: M) -> D {
        let src_xyz: Xyz<Swp, T> = color.into_xyz();
        let transform_matrix = method.generate_transform_matrix();
        let dst_xyz: Xyz<Dwp, T> = multiply_xyz(&transform_matrix, &src_xyz);
        D::from_xyz(dst_xyz)
    }
}

///Trait to convert color with one reference white point into another
///
///Converts a color with the source white point (Swp) into the destination white point (Dwp).
///Uses the bradford method for conversion by default.
pub trait AdaptInto<D, Swp, Dwp, T>: Sized
where
    T: Component + Float,
    Swp: WhitePoint,
    Dwp: WhitePoint,
{
    ///Convert the source color to the destination color using the bradford
    /// method by default
    fn adapt_into(self) -> D {
        self.adapt_into_using(Method::Bradford)
    }
    ///Convert the source color to the destination color using the specified
    /// method
    fn adapt_into_using<M: TransformMatrix<Swp, Dwp, T>>(self, method: M) -> D;
}

impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for S
where
    T: Component + Float,
    Swp: WhitePoint,
    Dwp: WhitePoint,
    D: AdaptFrom<S, Swp, Dwp, T>,
{
    fn adapt_into_using<M: TransformMatrix<Swp, Dwp, T>>(self, method: M) -> D {
        D::adapt_from_using(self, method)
    }
}

#[cfg(test)]
mod test {

    use Xyz;
    use white_point::{D50, D65, A, C};
    use super::{AdaptFrom, AdaptInto, Method, TransformMatrix};

    #[test]
    fn d65_to_d50_matrix_xyz_scaling() {
        let expected = [
            1.0144665, 0.0000000, 0.0000000, 0.0000000, 1.0000000, 0.0000000, 0.0000000, 0.0000000,
            0.7578869,
        ];
        let xyz_scaling = Method::XyzScaling;
        let computed = <TransformMatrix<D65, D50, _>>::generate_transform_matrix(&xyz_scaling);
        for (e, c) in expected.iter().zip(computed.iter()) {
            assert_relative_eq!(e, c, epsilon = 0.0001)
        }
    }
    #[test]
    fn d65_to_d50_matrix_von_kries() {
        let expected = [
            1.0160803, 0.0552297, -0.0521326, 0.0060666, 0.9955661, -0.0012235, 0.0000000,
            0.0000000, 0.7578869,
        ];
        let von_kries = Method::VonKries;
        let computed = <TransformMatrix<D65, D50, _>>::generate_transform_matrix(&von_kries);
        for (e, c) in expected.iter().zip(computed.iter()) {
            assert_relative_eq!(e, c, epsilon = 0.0001)
        }
    }
    #[test]
    fn d65_to_d50_matrix_bradford() {
        let expected = [
            1.0478112, 0.0228866, -0.0501270, 0.0295424, 0.9904844, -0.0170491, -0.0092345,
            0.0150436, 0.7521316,
        ];
        let bradford = Method::Bradford;
        let computed = <TransformMatrix<D65, D50, _>>::generate_transform_matrix(&bradford);
        for (e, c) in expected.iter().zip(computed.iter()) {
            assert_relative_eq!(e, c, epsilon = 0.0001)
        }
    }

    #[test]
    fn chromatic_adaptation_from_a_to_c() {
        let input_a = Xyz::<A, f32>::with_wp(0.315756, 0.162732, 0.015905);

        let expected_bradford = Xyz::<C, f32>::with_wp(0.257963, 0.139776, 0.058825);
        let expected_vonkries = Xyz::<C, f32>::with_wp(0.268446, 0.159139, 0.052843);
        let expected_xyz_scaling = Xyz::<C, f32>::with_wp(0.281868, 0.162732, 0.052844);

        let computed_bradford: Xyz<C, f32> = Xyz::adapt_from(input_a);
        assert_relative_eq!(expected_bradford, computed_bradford, epsilon = 0.0001);

        let computed_vonkries: Xyz<C, f32> = Xyz::adapt_from_using(input_a, Method::VonKries);
        assert_relative_eq!(expected_vonkries, computed_vonkries, epsilon = 0.0001);

        let computed_xyz_scaling: Xyz<C, _> = Xyz::adapt_from_using(input_a, Method::XyzScaling);
        assert_relative_eq!(expected_xyz_scaling, computed_xyz_scaling, epsilon = 0.0001);
    }

    #[test]
    fn chromatic_adaptation_into_a_to_c() {
        let input_a = Xyz::<A, f32>::with_wp(0.315756, 0.162732, 0.015905);

        let expected_bradford = Xyz::<C, f32>::with_wp(0.257963, 0.139776, 0.058825);
        let expected_vonkries = Xyz::<C, f32>::with_wp(0.268446, 0.159139, 0.052843);
        let expected_xyz_scaling = Xyz::<C, f32>::with_wp(0.281868, 0.162732, 0.052844);

        let computed_bradford: Xyz<C, f32> = input_a.adapt_into();
        assert_relative_eq!(expected_bradford, computed_bradford, epsilon = 0.0001);

        let computed_vonkries: Xyz<C, f32> = input_a.adapt_into_using(Method::VonKries);
        assert_relative_eq!(expected_vonkries, computed_vonkries, epsilon = 0.0001);

        let computed_xyz_scaling: Xyz<C, _> = input_a.adapt_into_using(Method::XyzScaling);
        assert_relative_eq!(expected_xyz_scaling, computed_xyz_scaling, epsilon = 0.0001);
    }
}
<commit_msg>Add the dyn keyword where trait objects are used<commit_after>//!Convert colors from one reference white point to another
//!
//!Chromatic adaptation is the human visual system’s ability to adjust to changes
//!in illumination in order to preserve the appearance of object colors. It is responsible
//!for the stable appearance of object colours despite the wide variation of light which
//!might be reflected from an object and observed by our eyes.
//!
//!This library provides three methods for chromatic adaptation Bradford (which is the default),
//!VonKries and XyzScaling
//!
//!```
//!use palette::Xyz;
//!use palette::white_point::{A, C};
//!use palette::chromatic_adaptation::AdaptInto;
//!
//!
//!let a = Xyz::<A, f32>::with_wp(0.315756, 0.162732, 0.015905);
//!
//!//Will convert Xyz<A, f32> to Xyz<C, f32> using Bradford chromatic adaptation
//!let c: Xyz<C, f32> = a.adapt_into();
//!
//!//Should print {x: 0.257963, y: 0.139776,z: 0.058825}
//!println!("{:?}", c)
//!```
use float::Float;

use {cast, Component, FromColor, IntoColor, Xyz};
use white_point::WhitePoint;
use matrix::{multiply_xyz, Mat3, multiply_3x3};

///Chromatic adaptation methods implemented in the library
pub enum Method {
    ///Bradford chromatic adaptation method
    Bradford,
    ///VonKries chromatic adaptation method
    VonKries,
    ///XyzScaling chromatic adaptation method
    XyzScaling,
}

///Holds the matrix coeffecients for the chromatic adaptation methods
pub struct ConeResponseMatrices<T: Float> {
    ///3x3 matrix for the cone response domains
    pub ma: Mat3<T>,
    ///3x3 matrix for the inverse of the cone response domains
    pub inv_ma: Mat3<T>,
}

///Generates a conversion matrix to convert the Xyz trisitmilus values from
///one illuminant to another (Swp -> Dwp)
pub trait TransformMatrix<Swp, Dwp, T>
where
    T: Component + Float,
    Swp: WhitePoint,
    Dwp: WhitePoint,
{
    ///Get the cone response functions for the chromatic adaptation method
    fn get_cone_response(&self) -> ConeResponseMatrices<T>;

    ///Generates a 3x3 transformation matrix to convert color from one reference white point
    ///to another with the given cone_response
    fn generate_transform_matrix(&self) -> Mat3<T> {
        let s_wp: Xyz<Swp, T> = Swp::get_xyz();
        let t_wp: Xyz<Dwp, T> = Dwp::get_xyz();
        let adapt = self.get_cone_response();

        let resp_src: Xyz<Swp, _> = multiply_xyz(&adapt.ma, &s_wp);
        let resp_dst: Xyz<Dwp, _> = multiply_xyz(&adapt.ma, &t_wp);
        let z = T::zero();
        let resp = [
            resp_dst.x / resp_src.x,
            z,
            z,
            z,
            resp_dst.y / resp_src.y,
            z,
            z,
            z,
            resp_dst.z / resp_src.z,
        ];

        let tmp = multiply_3x3(&resp, &adapt.ma);
        multiply_3x3(&adapt.inv_ma, &tmp)
    }
}

impl<Swp, Dwp, T> TransformMatrix<Swp, Dwp, T> for Method
where
    T: Component + Float,
    Swp: WhitePoint,
    Dwp: WhitePoint,
{
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn get_cone_response(&self) -> ConeResponseMatrices<T> {
        match *self {
             Method::Bradford => {
                ConeResponseMatrices::<T> {
                    ma: [cast(0.8951000), cast(0.2664000), cast(-0.1614000),
                         cast(-0.7502000), cast(1.7135000), cast(0.0367000),
                         cast(0.0389000), cast(-0.0685000), cast(1.0296000)
                         ],
                    inv_ma: [cast(0.9869929), cast(-0.1470543), cast(0.1599627),
                             cast(0.4323053), cast(0.5183603), cast(0.0492912),
                             cast(-0.0085287), cast(0.0400428), cast(0.9684867)
                            ],
                }
            }
             Method::VonKries => {
                ConeResponseMatrices::<T> {
                    ma: [cast(0.4002400), cast(0.7076000), cast(-0.0808100),
                         cast(-0.2263000), cast(1.1653200), cast(0.0457000),
                         cast(0.0000000), cast(0.0000000), cast(0.9182200)
                         ],
                    inv_ma: [cast(1.8599364), cast(-1.1293816), cast(0.2198974),
                             cast(0.3611914), cast(0.6388125), cast(-0.0000064),
                             cast(0.0000000), cast(0.0000000), cast(1.0890636)
                             ],
                }
            }
             Method::XyzScaling => {
                ConeResponseMatrices::<T> {
                    ma: [cast(1.0000000), cast(0.0000000), cast(0.0000000),
                         cast(0.0000000), cast(1.0000000), cast(0.0000000),
                         cast(0.0000000), cast(0.0000000), cast(1.0000000)
                         ],
                    inv_ma: [cast(1.0000000), cast(0.0000000), cast(0.0000000),
                             cast(0.0000000), cast(1.0000000), cast(0.0000000),
                             cast(0.0000000), cast(0.0000000), cast(1.0000000)
                             ],
                }
            }
        }
    }
}

///Trait to convert color from one reference white point to another
///
///Converts a color from the source white point (Swp) to the destination white point (Dwp).
///Uses the bradford method for conversion by default.
pub trait AdaptFrom<S, Swp, Dwp, T>: Sized
where
    T: Component + Float,
    Swp: WhitePoint,
    Dwp: WhitePoint,
{
    ///Convert the source color to the destination color using the bradford
    /// method by default
    fn adapt_from(color: S) -> Self {
        Self::adapt_from_using(color, Method::Bradford)
    }
    ///Convert the source color to the destination color using the specified
    /// method
    fn adapt_from_using<M: TransformMatrix<Swp, Dwp, T>>(color: S, method: M) -> Self;
}

impl<S, D, Swp, Dwp, T> AdaptFrom<S, Swp, Dwp, T> for D
where
    T: Component + Float,
    Swp: WhitePoint,
    Dwp: WhitePoint,
    S: IntoColor<Swp, T>,
    D: FromColor<Dwp, T>,
{
    fn adapt_from_using<M: TransformMatrix<Swp, Dwp, T>>(color: S, method: M) -> D {
        let src_xyz: Xyz<Swp, T> = color.into_xyz();
        let transform_matrix = method.generate_transform_matrix();
        let dst_xyz: Xyz<Dwp, T> = multiply_xyz(&transform_matrix, &src_xyz);
        D::from_xyz(dst_xyz)
    }
}

///Trait to convert color with one reference white point into another
///
///Converts a color with the source white point (Swp) into the destination white point (Dwp).
///Uses the bradford method for conversion by default.
pub trait AdaptInto<D, Swp, Dwp, T>: Sized
where
    T: Component + Float,
    Swp: WhitePoint,
    Dwp: WhitePoint,
{
    ///Convert the source color to the destination color using the bradford
    /// method by default
    fn adapt_into(self) -> D {
        self.adapt_into_using(Method::Bradford)
    }
    ///Convert the source color to the destination color using the specified
    /// method
    fn adapt_into_using<M: TransformMatrix<Swp, Dwp, T>>(self, method: M) -> D;
}

impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for S
where
    T: Component + Float,
    Swp: WhitePoint,
    Dwp: WhitePoint,
    D: AdaptFrom<S, Swp, Dwp, T>,
{
    fn adapt_into_using<M: TransformMatrix<Swp, Dwp, T>>(self, method: M) -> D {
        D::adapt_from_using(self, method)
    }
}

#[cfg(test)]
mod test {

    use Xyz;
    use white_point::{D50, D65, A, C};
    use super::{AdaptFrom, AdaptInto, Method, TransformMatrix};

    #[test]
    fn d65_to_d50_matrix_xyz_scaling() {
        let expected = [
            1.0144665, 0.0000000, 0.0000000, 0.0000000, 1.0000000, 0.0000000, 0.0000000, 0.0000000,
            0.7578869,
        ];
        let xyz_scaling = Method::XyzScaling;
        let computed = <dyn TransformMatrix<D65, D50, _>>::generate_transform_matrix(&xyz_scaling);
        for (e, c) in expected.iter().zip(computed.iter()) {
            assert_relative_eq!(e, c, epsilon = 0.0001)
        }
    }
    #[test]
    fn d65_to_d50_matrix_von_kries() {
        let expected = [
            1.0160803, 0.0552297, -0.0521326, 0.0060666, 0.9955661, -0.0012235, 0.0000000,
            0.0000000, 0.7578869,
        ];
        let von_kries = Method::VonKries;
        let computed = <dyn TransformMatrix<D65, D50, _>>::generate_transform_matrix(&von_kries);
        for (e, c) in expected.iter().zip(computed.iter()) {
            assert_relative_eq!(e, c, epsilon = 0.0001)
        }
    }
    #[test]
    fn d65_to_d50_matrix_bradford() {
        let expected = [
            1.0478112, 0.0228866, -0.0501270, 0.0295424, 0.9904844, -0.0170491, -0.0092345,
            0.0150436, 0.7521316,
        ];
        let bradford = Method::Bradford;
        let computed = <dyn TransformMatrix<D65, D50, _>>::generate_transform_matrix(&bradford);
        for (e, c) in expected.iter().zip(computed.iter()) {
            assert_relative_eq!(e, c, epsilon = 0.0001)
        }
    }

    #[test]
    fn chromatic_adaptation_from_a_to_c() {
        let input_a = Xyz::<A, f32>::with_wp(0.315756, 0.162732, 0.015905);

        let expected_bradford = Xyz::<C, f32>::with_wp(0.257963, 0.139776, 0.058825);
        let expected_vonkries = Xyz::<C, f32>::with_wp(0.268446, 0.159139, 0.052843);
        let expected_xyz_scaling = Xyz::<C, f32>::with_wp(0.281868, 0.162732, 0.052844);

        let computed_bradford: Xyz<C, f32> = Xyz::adapt_from(input_a);
        assert_relative_eq!(expected_bradford, computed_bradford, epsilon = 0.0001);

        let computed_vonkries: Xyz<C, f32> = Xyz::adapt_from_using(input_a, Method::VonKries);
        assert_relative_eq!(expected_vonkries, computed_vonkries, epsilon = 0.0001);

        let computed_xyz_scaling: Xyz<C, _> = Xyz::adapt_from_using(input_a, Method::XyzScaling);
        assert_relative_eq!(expected_xyz_scaling, computed_xyz_scaling, epsilon = 0.0001);
    }

    #[test]
    fn chromatic_adaptation_into_a_to_c() {
        let input_a = Xyz::<A, f32>::with_wp(0.315756, 0.162732, 0.015905);

        let expected_bradford = Xyz::<C, f32>::with_wp(0.257963, 0.139776, 0.058825);
        let expected_vonkries = Xyz::<C, f32>::with_wp(0.268446, 0.159139, 0.052843);
        let expected_xyz_scaling = Xyz::<C, f32>::with_wp(0.281868, 0.162732, 0.052844);

        let computed_bradford: Xyz<C, f32> = input_a.adapt_into();
        assert_relative_eq!(expected_bradford, computed_bradford, epsilon = 0.0001);

        let computed_vonkries: Xyz<C, f32> = input_a.adapt_into_using(Method::VonKries);
        assert_relative_eq!(expected_vonkries, computed_vonkries, epsilon = 0.0001);

        let computed_xyz_scaling: Xyz<C, _> = input_a.adapt_into_using(Method::XyzScaling);
        assert_relative_eq!(expected_xyz_scaling, computed_xyz_scaling, epsilon = 0.0001);
    }
}
<|endoftext|>


<commit_before>/// Check if needed fields are still public.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

extern crate mp4parse as mp4;

use std::io::{Cursor, Read};
use std::fs::File;

static MINI_MP4: &'static str = "tests/minimal.mp4";
static AUDIO_EME_MP4: &'static str = "tests/bipbop-cenc-audioinit.mp4";
static VIDEO_EME_MP4: &'static str = "tests/bipbop_480wp_1001kbps-cenc-video-key1-init.mp4";

// Taken from https://github.com/GuillaumeGomez/audio-video-metadata/blob/9dff40f565af71d5502e03a2e78ae63df95cfd40/src/metadata.rs#L53
#[test]
fn public_api() {
    let mut fd = File::open(MINI_MP4).expect("Unknown file");
    let mut buf = Vec::new();
    fd.read_to_end(&mut buf).expect("File error");

    let mut c = Cursor::new(&buf);
    let mut context = mp4::MediaContext::new();
    mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
    assert_eq!(context.timescale, Some(mp4::MediaTimeScale(1000)));
    for track in context.tracks {
        match track.data {
            Some(mp4::SampleEntry::Video(v)) => {
                // track part
                assert_eq!(track.duration, Some(mp4::TrackScaledTime(512, 0)));
                assert_eq!(track.empty_duration, Some(mp4::MediaScaledTime(0)));
                assert_eq!(track.media_time, Some(mp4::TrackScaledTime(0, 0)));
                assert_eq!(track.timescale, Some(mp4::TrackTimeScale(12800, 0)));
                assert_eq!(v.width, 320);
                assert_eq!(v.height, 240);

                // track.tkhd part
                let tkhd = track.tkhd.unwrap();
                assert_eq!(tkhd.disabled, false);
                assert_eq!(tkhd.duration, 40);
                assert_eq!(tkhd.width, 20971520);
                assert_eq!(tkhd.height, 15728640);

                // track.data part
                assert_eq!(match v.codec_specific {
                    mp4::VideoCodecSpecific::AVCConfig(v) => {
                        assert!(v.len() > 0);
                        "AVC"
                    }
                    mp4::VideoCodecSpecific::VPxConfig(vpx) => {
                        // We don't enter in here, we just check if fields are public.
                        assert!(vpx.bit_depth > 0);
                        assert!(vpx.color_space > 0);
                        assert!(vpx.chroma_subsampling > 0);
                        assert!(vpx.codec_init.len() > 0);
                        "VPx"
                    }
                }, "AVC");
            }
            Some(mp4::SampleEntry::Audio(a)) => {
                // track part
                assert_eq!(track.duration, Some(mp4::TrackScaledTime(2944, 1)));
                assert_eq!(track.empty_duration, Some(mp4::MediaScaledTime(0)));
                assert_eq!(track.media_time, Some(mp4::TrackScaledTime(1024, 1)));
                assert_eq!(track.timescale, Some(mp4::TrackTimeScale(48000, 1)));

                // track.tkhd part
                let tkhd = track.tkhd.unwrap();
                assert_eq!(tkhd.disabled, false);
                assert_eq!(tkhd.duration, 62);
                assert_eq!(tkhd.width, 0);
                assert_eq!(tkhd.height, 0);

                // track.data part
                assert_eq!(match a.codec_specific {
                    mp4::AudioCodecSpecific::ES_Descriptor(esds) => {
                        assert_eq!(esds.audio_codec, mp4::CodecType::AAC);
                        assert_eq!(esds.audio_sample_rate.unwrap(), 48000);
                        assert_eq!(esds.audio_object_type.unwrap(), 2);
                        "ES"
                    }
                    mp4::AudioCodecSpecific::FLACSpecificBox(flac) => {
                        // STREAMINFO block must be present and first.
                        assert!(flac.blocks.len() > 0);
                        assert_eq!(flac.blocks[0].block_type, 0);
                        assert_eq!(flac.blocks[0].data.len(), 34);
                        "FLAC"
                    }
                    mp4::AudioCodecSpecific::OpusSpecificBox(opus) => {
                        // We don't enter in here, we just check if fields are public.
                        assert!(opus.version > 0);
                        "Opus"
                    }
                    mp4::AudioCodecSpecific::MP3 => {
                        "MP3"
                    }
                }, "ES");
                assert!(a.samplesize > 0);
                assert!(a.samplerate > 0);
            }
            Some(mp4::SampleEntry::Unknown) | None => {}
        }
    }
}

#[test]
fn public_audio_tenc() {
    let kid =
        vec![0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04,
             0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04];

    let mut fd = File::open(AUDIO_EME_MP4).expect("Unknown file");
    let mut buf = Vec::new();
    fd.read_to_end(&mut buf).expect("File error");

    let mut c = Cursor::new(&buf);
    let mut context = mp4::MediaContext::new();
    mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
    for track in context.tracks {
        assert_eq!(track.codec_type, mp4::CodecType::EncryptedAudio);
        match track.data {
            Some(mp4::SampleEntry::Audio(a)) => {
                match a.protection_info.iter().find(|sinf| sinf.tenc.is_some()) {
                    Some(p) => {
                        assert_eq!(p.code_name, "mp4a");
                        if let Some(ref tenc) = p.tenc {
                            assert!(tenc.is_encrypted > 0);
                            assert_eq!(tenc.iv_size, 16);
                            assert_eq!(tenc.kid, kid);
                        } else {
                            assert!(false, "Invalid test condition");
                        }
                    },
                    _=> {
                        assert!(false, "Invalid test condition");
                    },
                }
            },
            _ => {
                assert!(false, "Invalid test condition");
            }
        }
    }
}

#[test]
fn public_video_cenc() {
    let system_id =
        vec![0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02,
             0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b];

    let kid =
        vec![0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x03,
             0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x11];

    let pssh_box =
        vec![0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68,
             0x01, 0x00, 0x00, 0x00, 0x10, 0x77, 0xef, 0xec,
             0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e,
             0x52, 0xe2, 0xfb, 0x4b, 0x00, 0x00, 0x00, 0x01,
             0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x03,
             0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x11,
             0x00, 0x00, 0x00, 0x00];

    let mut fd = File::open(VIDEO_EME_MP4).expect("Unknown file");
    let mut buf = Vec::new();
    fd.read_to_end(&mut buf).expect("File error");

    let mut c = Cursor::new(&buf);
    let mut context = mp4::MediaContext::new();
    mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
    for track in context.tracks {
        assert_eq!(track.codec_type, mp4::CodecType::EncryptedVideo);
        match track.data {
            Some(mp4::SampleEntry::Video(v)) => {
                match v.protection_info.iter().find(|sinf| sinf.tenc.is_some()) {
                    Some(p) => {
                        assert_eq!(p.code_name, "avc1");
                        if let Some(ref tenc) = p.tenc {
                            assert!(tenc.is_encrypted > 0);
                            assert_eq!(tenc.iv_size, 16);
                            assert_eq!(tenc.kid, kid);
                        } else {
                            assert!(false, "Invalid test condition");
                        }
                    },
                    _=> {
                        assert!(false, "Invalid test condition");
                    },
                }
            },
            _ => {
                assert!(false, "Invalid test condition");
            }
        }
    }

    for pssh in context.psshs {
        assert_eq!(pssh.system_id, system_id);
        for kid_id in pssh.kid {
            assert_eq!(kid_id, kid);
        }
        assert_eq!(pssh.data.len(), 0);
        assert_eq!(pssh.box_content, pssh_box);
    }
}
<commit_msg>Use Vec::is_empty() instead of length comparisons.<commit_after>/// Check if needed fields are still public.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

extern crate mp4parse as mp4;

use std::io::{Cursor, Read};
use std::fs::File;

static MINI_MP4: &'static str = "tests/minimal.mp4";
static AUDIO_EME_MP4: &'static str = "tests/bipbop-cenc-audioinit.mp4";
static VIDEO_EME_MP4: &'static str = "tests/bipbop_480wp_1001kbps-cenc-video-key1-init.mp4";

// Taken from https://github.com/GuillaumeGomez/audio-video-metadata/blob/9dff40f565af71d5502e03a2e78ae63df95cfd40/src/metadata.rs#L53
#[test]
fn public_api() {
    let mut fd = File::open(MINI_MP4).expect("Unknown file");
    let mut buf = Vec::new();
    fd.read_to_end(&mut buf).expect("File error");

    let mut c = Cursor::new(&buf);
    let mut context = mp4::MediaContext::new();
    mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
    assert_eq!(context.timescale, Some(mp4::MediaTimeScale(1000)));
    for track in context.tracks {
        match track.data {
            Some(mp4::SampleEntry::Video(v)) => {
                // track part
                assert_eq!(track.duration, Some(mp4::TrackScaledTime(512, 0)));
                assert_eq!(track.empty_duration, Some(mp4::MediaScaledTime(0)));
                assert_eq!(track.media_time, Some(mp4::TrackScaledTime(0, 0)));
                assert_eq!(track.timescale, Some(mp4::TrackTimeScale(12800, 0)));
                assert_eq!(v.width, 320);
                assert_eq!(v.height, 240);

                // track.tkhd part
                let tkhd = track.tkhd.unwrap();
                assert_eq!(tkhd.disabled, false);
                assert_eq!(tkhd.duration, 40);
                assert_eq!(tkhd.width, 20971520);
                assert_eq!(tkhd.height, 15728640);

                // track.data part
                assert_eq!(match v.codec_specific {
                    mp4::VideoCodecSpecific::AVCConfig(v) => {
                        assert!(!v.is_empty());
                        "AVC"
                    }
                    mp4::VideoCodecSpecific::VPxConfig(vpx) => {
                        // We don't enter in here, we just check if fields are public.
                        assert!(vpx.bit_depth > 0);
                        assert!(vpx.color_space > 0);
                        assert!(vpx.chroma_subsampling > 0);
                        assert!(!vpx.codec_init.is_empty());
                        "VPx"
                    }
                }, "AVC");
            }
            Some(mp4::SampleEntry::Audio(a)) => {
                // track part
                assert_eq!(track.duration, Some(mp4::TrackScaledTime(2944, 1)));
                assert_eq!(track.empty_duration, Some(mp4::MediaScaledTime(0)));
                assert_eq!(track.media_time, Some(mp4::TrackScaledTime(1024, 1)));
                assert_eq!(track.timescale, Some(mp4::TrackTimeScale(48000, 1)));

                // track.tkhd part
                let tkhd = track.tkhd.unwrap();
                assert_eq!(tkhd.disabled, false);
                assert_eq!(tkhd.duration, 62);
                assert_eq!(tkhd.width, 0);
                assert_eq!(tkhd.height, 0);

                // track.data part
                assert_eq!(match a.codec_specific {
                    mp4::AudioCodecSpecific::ES_Descriptor(esds) => {
                        assert_eq!(esds.audio_codec, mp4::CodecType::AAC);
                        assert_eq!(esds.audio_sample_rate.unwrap(), 48000);
                        assert_eq!(esds.audio_object_type.unwrap(), 2);
                        "ES"
                    }
                    mp4::AudioCodecSpecific::FLACSpecificBox(flac) => {
                        // STREAMINFO block must be present and first.
                        assert!(!flac.blocks.is_empty());
                        assert_eq!(flac.blocks[0].block_type, 0);
                        assert_eq!(flac.blocks[0].data.len(), 34);
                        "FLAC"
                    }
                    mp4::AudioCodecSpecific::OpusSpecificBox(opus) => {
                        // We don't enter in here, we just check if fields are public.
                        assert!(opus.version > 0);
                        "Opus"
                    }
                    mp4::AudioCodecSpecific::MP3 => {
                        "MP3"
                    }
                }, "ES");
                assert!(a.samplesize > 0);
                assert!(a.samplerate > 0);
            }
            Some(mp4::SampleEntry::Unknown) | None => {}
        }
    }
}

#[test]
fn public_audio_tenc() {
    let kid =
        vec![0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04,
             0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04];

    let mut fd = File::open(AUDIO_EME_MP4).expect("Unknown file");
    let mut buf = Vec::new();
    fd.read_to_end(&mut buf).expect("File error");

    let mut c = Cursor::new(&buf);
    let mut context = mp4::MediaContext::new();
    mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
    for track in context.tracks {
        assert_eq!(track.codec_type, mp4::CodecType::EncryptedAudio);
        match track.data {
            Some(mp4::SampleEntry::Audio(a)) => {
                match a.protection_info.iter().find(|sinf| sinf.tenc.is_some()) {
                    Some(p) => {
                        assert_eq!(p.code_name, "mp4a");
                        if let Some(ref tenc) = p.tenc {
                            assert!(tenc.is_encrypted > 0);
                            assert_eq!(tenc.iv_size, 16);
                            assert_eq!(tenc.kid, kid);
                        } else {
                            assert!(false, "Invalid test condition");
                        }
                    },
                    _=> {
                        assert!(false, "Invalid test condition");
                    },
                }
            },
            _ => {
                assert!(false, "Invalid test condition");
            }
        }
    }
}

#[test]
fn public_video_cenc() {
    let system_id =
        vec![0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02,
             0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b];

    let kid =
        vec![0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x03,
             0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x11];

    let pssh_box =
        vec![0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68,
             0x01, 0x00, 0x00, 0x00, 0x10, 0x77, 0xef, 0xec,
             0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e,
             0x52, 0xe2, 0xfb, 0x4b, 0x00, 0x00, 0x00, 0x01,
             0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x03,
             0x7e, 0x57, 0x1d, 0x03, 0x7e, 0x57, 0x1d, 0x11,
             0x00, 0x00, 0x00, 0x00];

    let mut fd = File::open(VIDEO_EME_MP4).expect("Unknown file");
    let mut buf = Vec::new();
    fd.read_to_end(&mut buf).expect("File error");

    let mut c = Cursor::new(&buf);
    let mut context = mp4::MediaContext::new();
    mp4::read_mp4(&mut c, &mut context).expect("read_mp4 failed");
    for track in context.tracks {
        assert_eq!(track.codec_type, mp4::CodecType::EncryptedVideo);
        match track.data {
            Some(mp4::SampleEntry::Video(v)) => {
                match v.protection_info.iter().find(|sinf| sinf.tenc.is_some()) {
                    Some(p) => {
                        assert_eq!(p.code_name, "avc1");
                        if let Some(ref tenc) = p.tenc {
                            assert!(tenc.is_encrypted > 0);
                            assert_eq!(tenc.iv_size, 16);
                            assert_eq!(tenc.kid, kid);
                        } else {
                            assert!(false, "Invalid test condition");
                        }
                    },
                    _=> {
                        assert!(false, "Invalid test condition");
                    },
                }
            },
            _ => {
                assert!(false, "Invalid test condition");
            }
        }
    }

    for pssh in context.psshs {
        assert_eq!(pssh.system_id, system_id);
        for kid_id in pssh.kid {
            assert_eq!(kid_id, kid);
        }
        assert!(pssh.data.is_empty());
        assert_eq!(pssh.box_content, pssh_box);
    }
}
<|endoftext|>


<commit_before>extern crate ansi_term;
extern crate rand;

use ansi_term::Colour::*;
use rand::Rng;
use std::io;

enum Card {
    ClubsAce,
    ClubsTen,
    ClubsKing,
    ClubsQueen,
    ClubsJack,
    ClubsNine,
    ClubsEight,
    ClubsSeven,
    SpadesAce,
    SpadesTen,
    SpadesKing,
    SpadesQueen,
    SpadesJack,
    SpadesNine,
    SpadesEight,
    SpadesSeven,
    HeartsAce,
    HeartsTen,
    HeartsKing,
    HeartsQueen,
    HeartsJack,
    HeartsNine,
    HeartsEight,
    HeartsSeven,
    DiamondsAce,
    DiamondsTen,
    DiamondsKing,
    DiamondsQueen,
    DiamondsJack,
    DiamondsNine,
    DiamondsEight,
    DiamondsSeven,
}

enum Game {
    Suit,
    Grand,
    Null,
}

enum PlayerId {
    A,
    B,
    C,
}

fn announce(player: u8) -> Game {
    Game::Suit
}

fn bid(dealer: u8) -> (u8, u8) {
    let winner: u8 = dealer;
    let highest: u8 = 18;
    // TODO
    (winner, highest)
}

fn deal(dealer: u8) {
    let mut cards: Vec<u8> = Vec::new();
    // print sorted cards
    for n in 0..32 {
        cards.push(n);
    }
    for n in 0..8 {
        print_card(n);
    };
    println!("");
    for n in 8..16 {
        print_card(n);
    }
    println!("");
    for n in 16..24 {
        print_card(n);
    };
    println!("");
    for n in 24..32 {
        print_card(n);
    };
    println!("");
    println!("");
    // shuffle cards
    let mut upper: u8 = 32;
    let mut shuffled: Vec<u8> = Vec::new();
    for n in 0..32 {
        // randomly select card
        let pile_index: u8 = rand::thread_rng().gen_range(0, upper - n);
        // remove selected card from old pile
        let card = cards.remove(pile_index as usize);
        // add selected card to new pile
        shuffled.push(card);
    }
    // print shuffled cards (per player plus Skat)
    for n in 0..10 {
        print_card(shuffled[n]);
    };
    println!("");
    for n in 10..20 {
        print_card(shuffled[n]);
    }
    println!("");
    for n in 20..30 {
        print_card(shuffled[n]);
    };
    println!("");
    for n in 30..32 {
        print_card(shuffled[n]);
    };
    println!("");
}

fn print_card(card: u8) {
    let club    = "♣";
    let spade   = "♠";
    let heart   = "♥";
    let diamond = "♦";
    match card {
        0 => {
            let mut ace = " A".to_string();
            ace.push_str(club);
            print!("{} ", Black.bold().paint(&ace));
        },
        1 => {
            let mut ten = "10".to_string();
            ten.push_str(club);
            print!("{} ", Black.bold().paint(&ten));
        },
        2 => {
            let mut king = " K".to_string();
            king.push_str(club);
            print!("{} ", Black.bold().paint(&king));
        },
        3 => {
            let mut queen = " Q".to_string();
            queen.push_str(club);
            print!("{} ", Black.bold().paint(&queen));
        },
        4 => {
            let mut jack = " J".to_string();
            jack.push_str(club);
            print!("{} ", Black.bold().paint(&jack));
        },
        5 => {
            let mut nine = " 9".to_string();
            nine.push_str(club);
            print!("{} ", Black.bold().paint(&nine));
        },
        6 => {
            let mut eight = " 8".to_string();
            eight.push_str(club);
            print!("{} ", Black.bold().paint(&eight));
        },
        7 => {
            let mut seven = " 7".to_string();
            seven.push_str(club);
            print!("{} ", Black.bold().paint(&seven));
        },
        8 => {
            let mut ace = " A".to_string();
            ace.push_str(spade);
            print!("{} ", Green.bold().paint(&ace));
        },
        9 => {
            let mut ten = "10".to_string();
            ten.push_str(spade);
            print!("{} ", Green.bold().paint(&ten));
        },
        10 => {
            let mut king = " K".to_string();
            king.push_str(spade);
            print!("{} ", Green.bold().paint(&king));
        },
        11 => {
            let mut queen = " Q".to_string();
            queen.push_str(spade);
            print!("{} ", Green.bold().paint(&queen));
        },
        12 => {
            let mut jack = " J".to_string();
            jack.push_str(spade);
            print!("{} ", Green.bold().paint(&jack));
        },
        13 => {
            let mut nine = " 9".to_string();
            nine.push_str(spade);
            print!("{} ", Green.bold().paint(&nine));
        },
        14 => {
            let mut eight = " 8".to_string();
            eight.push_str(spade);
            print!("{} ", Green.bold().paint(&eight));
        },
        15 => {
            let mut seven = " 7".to_string();
            seven.push_str(spade);
            print!("{} ", Green.bold().paint(&seven));
        },
        16 => {
            let mut ace = " A".to_string();
            ace.push_str(heart);
            print!("{} ", Red.bold().paint(&ace));
        },
        17 => {
            let mut ten = "10".to_string();
            ten.push_str(heart);
            print!("{} ", Red.bold().paint(&ten));
        },
        18 => {
            let mut king = " K".to_string();
            king.push_str(heart);
            print!("{} ", Red.bold().paint(&king));
        },
        19 => {
            let mut queen = " Q".to_string();
            queen.push_str(heart);
            print!("{} ", Red.bold().paint(&queen));
        },
        20 => {
            let mut jack = " J".to_string();
            jack.push_str(heart);
            print!("{} ", Red.bold().paint(&jack));
        },
        21 => {
            let mut nine = " 9".to_string();
            nine.push_str(heart);
            print!("{} ", Red.bold().paint(&nine));
        },
        22 => {
            let mut eight = " 8".to_string();
            eight.push_str(heart);
            print!("{} ", Red.bold().paint(&eight));
        },
        23 => {
            let mut seven = " 7".to_string();
            seven.push_str(heart);
            print!("{} ", Red.bold().paint(&seven));
        },
        24 => {
            let mut ace = " A".to_string();
            ace.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&ace));
        },
        25 => {
            let mut ten = "10".to_string();
            ten.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&ten));
        },
        26 => {
            let mut king = " K".to_string();
            king.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&king));
        },
        27 => {
            let mut queen = " Q".to_string();
            queen.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&queen));
        },
        28 => {
            let mut jack = " J".to_string();
            jack.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&jack));
        },
        29 => {
            let mut nine = " 9".to_string();
            nine.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&nine));
        },
        30 => {
            let mut eight = " 8".to_string();
            eight.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&eight));
        },
        31 => {
            let mut seven = " 7".to_string();
            seven.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&seven));
        },
        _ => panic!("Unknown card"),
    }
}

fn main() {
    // randomly select player
    let player_id: u8 = rand::thread_rng().gen_range(0, 3);
    match player_id {
        0 => println!("player A:"),
        1 => println!("player B:"),
        2 => println!("player C:"),
        _ => panic!("Unknown player {}", player_id),
    }
    loop {
        // player with player_id is dealing
        deal(player_id);
        // bid
        let (player, bid) = bid(player_id);
        // announce
        let game = announce(player);
        // play 10 tricks in a row
        for trick in 0..10 {
            println!("trick #{}:", trick);
            // ask for input
            let mut input = String::new();
            io::stdin().read_line(&mut input)
                .ok()
                .expect("failed to read line");
            let input: u8 = match input.trim().parse() {
                Ok(num) => num,
                Err(_) => break,
            };
            // is input valid?
        };
        println!("New game?");
        let mut input = String::new();
        io::stdin().read_line(&mut input)
            .ok()
            .expect("failed to read line");
        let input: u8 = match input.trim().parse() {
            Ok(num) => num,
            Err(_) => break,
        };
        println!("your input: {}", input);
        if input != 1 {
            break;
        }
    }
}
<commit_msg>Let's try to create a new Player via PlayerBuilder.<commit_after>extern crate ansi_term;
extern crate rand;

use ansi_term::Colour::*;
use rand::Rng;
use std::io;

enum Card {
    ClubsAce,
    ClubsTen,
    ClubsKing,
    ClubsQueen,
    ClubsJack,
    ClubsNine,
    ClubsEight,
    ClubsSeven,
    SpadesAce,
    SpadesTen,
    SpadesKing,
    SpadesQueen,
    SpadesJack,
    SpadesNine,
    SpadesEight,
    SpadesSeven,
    HeartsAce,
    HeartsTen,
    HeartsKing,
    HeartsQueen,
    HeartsJack,
    HeartsNine,
    HeartsEight,
    HeartsSeven,
    DiamondsAce,
    DiamondsTen,
    DiamondsKing,
    DiamondsQueen,
    DiamondsJack,
    DiamondsNine,
    DiamondsEight,
    DiamondsSeven,
}

enum Game {
    Suit,
    Grand,
    Null,
}

enum PlayerId {
    A,
    B,
    C,
}

struct Player {
    id: u8,
    cards: Vec<u8>,
}

struct PlayerBuilder {
    id: u8,
    cards: Vec<u8>,
}

impl PlayerBuilder {
    fn new() -> PlayerBuilder {
        PlayerBuilder { cards: Vec::new(), id: 3, }
    }

    fn id(&mut self, newId: u8) -> &mut PlayerBuilder {
        self.id = newId;
        self
    }

    fn finalize(&self) -> Player {
        Player { id: self.id, cards: self.cards.to_vec(), }
    }
}

fn announce(player: u8) -> Game {
    Game::Suit
}

fn bid(dealer: u8) -> (u8, u8) {
    let winner: u8 = dealer;
    let highest: u8 = 18;
    // TODO
    (winner, highest)
}

fn deal(dealer: u8) {
    let dealer = PlayerBuilder::new();
    let mut cards: Vec<u8> = Vec::new();
    // print sorted cards
    for n in 0..32 {
        cards.push(n);
    }
    for n in 0..8 {
        print_card(n);
    };
    println!("");
    for n in 8..16 {
        print_card(n);
    }
    println!("");
    for n in 16..24 {
        print_card(n);
    };
    println!("");
    for n in 24..32 {
        print_card(n);
    };
    println!("");
    println!("");
    // shuffle cards
    let mut upper: u8 = 32;
    let mut shuffled: Vec<u8> = Vec::new();
    for n in 0..32 {
        // randomly select card
        let pile_index: u8 = rand::thread_rng().gen_range(0, upper - n);
        // remove selected card from old pile
        let card = cards.remove(pile_index as usize);
        // add selected card to new pile
        shuffled.push(card);
    }
    // print shuffled cards (per player plus Skat)
    for n in 0..10 {
        print_card(shuffled[n]);
    };
    println!("");
    for n in 10..20 {
        print_card(shuffled[n]);
    }
    println!("");
    for n in 20..30 {
        print_card(shuffled[n]);
    };
    println!("");
    for n in 30..32 {
        print_card(shuffled[n]);
    };
    println!("");
}

fn print_card(card: u8) {
    let club    = "♣";
    let spade   = "♠";
    let heart   = "♥";
    let diamond = "♦";
    match card {
        0 => {
            let mut ace = " A".to_string();
            ace.push_str(club);
            print!("{} ", Black.bold().paint(&ace));
        },
        1 => {
            let mut ten = "10".to_string();
            ten.push_str(club);
            print!("{} ", Black.bold().paint(&ten));
        },
        2 => {
            let mut king = " K".to_string();
            king.push_str(club);
            print!("{} ", Black.bold().paint(&king));
        },
        3 => {
            let mut queen = " Q".to_string();
            queen.push_str(club);
            print!("{} ", Black.bold().paint(&queen));
        },
        4 => {
            let mut jack = " J".to_string();
            jack.push_str(club);
            print!("{} ", Black.bold().paint(&jack));
        },
        5 => {
            let mut nine = " 9".to_string();
            nine.push_str(club);
            print!("{} ", Black.bold().paint(&nine));
        },
        6 => {
            let mut eight = " 8".to_string();
            eight.push_str(club);
            print!("{} ", Black.bold().paint(&eight));
        },
        7 => {
            let mut seven = " 7".to_string();
            seven.push_str(club);
            print!("{} ", Black.bold().paint(&seven));
        },
        8 => {
            let mut ace = " A".to_string();
            ace.push_str(spade);
            print!("{} ", Green.bold().paint(&ace));
        },
        9 => {
            let mut ten = "10".to_string();
            ten.push_str(spade);
            print!("{} ", Green.bold().paint(&ten));
        },
        10 => {
            let mut king = " K".to_string();
            king.push_str(spade);
            print!("{} ", Green.bold().paint(&king));
        },
        11 => {
            let mut queen = " Q".to_string();
            queen.push_str(spade);
            print!("{} ", Green.bold().paint(&queen));
        },
        12 => {
            let mut jack = " J".to_string();
            jack.push_str(spade);
            print!("{} ", Green.bold().paint(&jack));
        },
        13 => {
            let mut nine = " 9".to_string();
            nine.push_str(spade);
            print!("{} ", Green.bold().paint(&nine));
        },
        14 => {
            let mut eight = " 8".to_string();
            eight.push_str(spade);
            print!("{} ", Green.bold().paint(&eight));
        },
        15 => {
            let mut seven = " 7".to_string();
            seven.push_str(spade);
            print!("{} ", Green.bold().paint(&seven));
        },
        16 => {
            let mut ace = " A".to_string();
            ace.push_str(heart);
            print!("{} ", Red.bold().paint(&ace));
        },
        17 => {
            let mut ten = "10".to_string();
            ten.push_str(heart);
            print!("{} ", Red.bold().paint(&ten));
        },
        18 => {
            let mut king = " K".to_string();
            king.push_str(heart);
            print!("{} ", Red.bold().paint(&king));
        },
        19 => {
            let mut queen = " Q".to_string();
            queen.push_str(heart);
            print!("{} ", Red.bold().paint(&queen));
        },
        20 => {
            let mut jack = " J".to_string();
            jack.push_str(heart);
            print!("{} ", Red.bold().paint(&jack));
        },
        21 => {
            let mut nine = " 9".to_string();
            nine.push_str(heart);
            print!("{} ", Red.bold().paint(&nine));
        },
        22 => {
            let mut eight = " 8".to_string();
            eight.push_str(heart);
            print!("{} ", Red.bold().paint(&eight));
        },
        23 => {
            let mut seven = " 7".to_string();
            seven.push_str(heart);
            print!("{} ", Red.bold().paint(&seven));
        },
        24 => {
            let mut ace = " A".to_string();
            ace.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&ace));
        },
        25 => {
            let mut ten = "10".to_string();
            ten.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&ten));
        },
        26 => {
            let mut king = " K".to_string();
            king.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&king));
        },
        27 => {
            let mut queen = " Q".to_string();
            queen.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&queen));
        },
        28 => {
            let mut jack = " J".to_string();
            jack.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&jack));
        },
        29 => {
            let mut nine = " 9".to_string();
            nine.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&nine));
        },
        30 => {
            let mut eight = " 8".to_string();
            eight.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&eight));
        },
        31 => {
            let mut seven = " 7".to_string();
            seven.push_str(diamond);
            print!("{} ", Yellow.bold().paint(&seven));
        },
        _ => panic!("Unknown card"),
    }
}

fn main() {
    // randomly select player
    let player_id: u8 = rand::thread_rng().gen_range(0, 3);
    match player_id {
        0 => println!("player A:"),
        1 => println!("player B:"),
        2 => println!("player C:"),
        _ => panic!("Unknown player {}", player_id),
    }
    loop {
        // player with player_id is dealing
        deal(player_id);
        // bid
        let (player, bid) = bid(player_id);
        // announce
        let game = announce(player);
        // play 10 tricks in a row
        for trick in 0..10 {
            println!("trick #{}:", trick);
            // ask for input
            let mut input = String::new();
            io::stdin().read_line(&mut input)
                .ok()
                .expect("failed to read line");
            let input: u8 = match input.trim().parse() {
                Ok(num) => num,
                Err(_) => break,
            };
            // is input valid?
        };
        println!("New game?");
        let mut input = String::new();
        io::stdin().read_line(&mut input)
            .ok()
            .expect("failed to read line");
        let input: u8 = match input.trim().parse() {
            Ok(num) => num,
            Err(_) => break,
        };
        println!("your input: {}", input);
        if input != 1 {
            break;
        }
    }
}
<|endoftext|>


<commit_before>use std::time::{Duration, Instant};
use tokio::timer::Delay;
use std::io;
use tokio::prelude::*;

/// `Incoming` is a stream of incoming sockets
/// Polling the stream may return a temporary io::Error (for instance if we can't open the connection because of "too many open files" limit)
/// we use for_each combinator which:
/// 1. Runs for every Ok(socket)
/// 2. Stops on the FIRST Err()
/// So any temporary io::Error will cause the entire server to terminate.
/// This wrapper type for tokio::Incoming stops accepting new connections
/// for a specified amount of time once an io::Error is encountered
pub struct SuspendableStream<S> {
	stream: S,
	next_delay: Duration,
	initial_delay: Duration,
	max_delay: Duration,
	timeout: Option<Delay>,
}

impl<S> SuspendableStream<S> {
	/// construct a new Suspendable stream, given tokio::Incoming
	/// and the amount of time to pause for.
	pub fn new(stream: S) -> Self {
		SuspendableStream {
			stream,
			next_delay: Duration::from_millis(20),
			initial_delay: Duration::from_millis(10),
			max_delay: Duration::from_secs(5),
			timeout: None,
		}
	}
}

impl<S, I> Stream for SuspendableStream<S>
	where S: Stream<Item=I, Error=io::Error>
{
	type Item = I;
	type Error = ();

	fn poll(&mut self) -> Result<Async<Option<Self::Item>>, ()> {
		if let Some(mut timeout) = self.timeout.take() {
			match timeout.poll() {
				Ok(Async::Ready(_)) => {}
				Ok(Async::NotReady) => {
					self.timeout = Some(timeout);
					return Ok(Async::NotReady);
				}
				Err(_) => unreachable!("Polling a delay shouldn't yield any errors; qed")
			}
		}

		loop {
			match self.stream.poll() {
				Ok(item) => {
					if self.next_delay > self.initial_delay {
						self.next_delay = self.initial_delay;
					}
					return Ok(item)
				},
				Err(ref e) => if connection_error(e) {
					warn!("Connection Error: {:?}", e);
					continue
				}
				Err(err) => {
					self.next_delay = if self.next_delay < self.max_delay {
						self.next_delay * 2
					} else {
						self.next_delay
					};
					warn!("Error accepting connection: {}", err);
					warn!("The server will stop accepting connections for {:?}", self.next_delay);
					self.timeout = Some(Delay::new(Instant::now() + self.next_delay));
				}
			}
		}
	}
}

/// assert that the error was a connection error
fn connection_error(e: &io::Error) -> bool {
	e.kind() == io::ErrorKind::ConnectionRefused ||
		e.kind() == io::ErrorKind::ConnectionAborted ||
		e.kind() == io::ErrorKind::ConnectionReset
}

<commit_msg>Drop timeout if max concurrent timeouts reached (#324)<commit_after>use std::time::{Duration, Instant};
use tokio::timer::Delay;
use std::io;
use tokio::prelude::*;

/// `Incoming` is a stream of incoming sockets
/// Polling the stream may return a temporary io::Error (for instance if we can't open the connection because of "too many open files" limit)
/// we use for_each combinator which:
/// 1. Runs for every Ok(socket)
/// 2. Stops on the FIRST Err()
/// So any temporary io::Error will cause the entire server to terminate.
/// This wrapper type for tokio::Incoming stops accepting new connections
/// for a specified amount of time once an io::Error is encountered
pub struct SuspendableStream<S> {
	stream: S,
	next_delay: Duration,
	initial_delay: Duration,
	max_delay: Duration,
	timeout: Option<Delay>,
}

impl<S> SuspendableStream<S> {
	/// construct a new Suspendable stream, given tokio::Incoming
	/// and the amount of time to pause for.
	pub fn new(stream: S) -> Self {
		SuspendableStream {
			stream,
			next_delay: Duration::from_millis(20),
			initial_delay: Duration::from_millis(10),
			max_delay: Duration::from_secs(5),
			timeout: None,
		}
	}
}

impl<S, I> Stream for SuspendableStream<S>
	where S: Stream<Item=I, Error=io::Error>
{
	type Item = I;
	type Error = ();

	fn poll(&mut self) -> Result<Async<Option<Self::Item>>, ()> {
		loop {
			if let Some(mut timeout) = self.timeout.take() {
				match timeout.poll() {
					Ok(Async::Ready(_)) => {}
					Ok(Async::NotReady) => {
						self.timeout = Some(timeout);
						return Ok(Async::NotReady);
					}
					Err(err) => {
						warn!("Timeout error {:?}", err);
						task::current().notify();
						return Ok(Async::NotReady);
					}
				}
			}

			match self.stream.poll() {
				Ok(item) => {
					if self.next_delay > self.initial_delay {
						self.next_delay = self.initial_delay;
					}
					return Ok(item)
				}
				Err(ref err) => {
					if connection_error(err) {
						warn!("Connection Error: {:?}", err);
						continue
					}
					self.next_delay = if self.next_delay < self.max_delay {
						self.next_delay * 2
					} else {
						self.next_delay
					};
					warn!("Error accepting connection: {}", err);
					warn!("The server will stop accepting connections for {:?}", self.next_delay);
					self.timeout = Some(Delay::new(Instant::now() + self.next_delay));
				}
			}
		}
	}
}

/// assert that the error was a connection error
fn connection_error(e: &io::Error) -> bool {
	e.kind() == io::ErrorKind::ConnectionRefused ||
		e.kind() == io::ErrorKind::ConnectionAborted ||
		e.kind() == io::ErrorKind::ConnectionReset
}

<|endoftext|>


<commit_before>use definitions::program::{Instruction, Program, Target, Value};
use definitions::typedef::*;
use error::*;
use std::cmp::Ordering;

const STACK_COUNT: usize = 2;
const REGISTER_COUNT: usize = 4;

/// The whole state of the VM
pub struct VM {
    image_data: Vec<Instruction>,
    pc: Address,
    data_stacks: [Vec<Value>; STACK_COUNT],
    data_registers: [Value; REGISTER_COUNT],
    cmp_reg: Option<Ordering>,
    call_stack: Vec<Address>,
    skip_advance: bool,
}

impl VM {
    /// Creates a new VM state for executing programs
    pub fn new() -> VM {
        VM {
            image_data: Vec::new(),
            pc: 0,
            data_stacks: [Vec::new(), Vec::new()],
            data_registers: [Value::Nil, Value::Nil, Value::Nil, Value::Nil],
            cmp_reg: None,
            call_stack: Vec::new(),
            skip_advance: false,
        }
    }

    // # Maintainance functions

    /// Executes te given program
    pub fn exec(&mut self, program: Program) -> VMResult<()> {
        self.reset();
        self.load_program(program);

        while self.pc < self.image_data.len() {
            let current_instruction = self.image_data[self.pc].clone();

            match current_instruction {
                Instruction::Halt => break,
                Instruction::Add(dest, src) => self.add(dest, src)?,
                Instruction::Sub(dest, src) => self.sub(dest, src)?,
                Instruction::Div(dest, src) => self.div(dest, src)?,
                Instruction::Mul(dest, src) => self.mul(dest, src)?,
                Instruction::Mod(dest, src) => self.modulo(dest, src)?,

                Instruction::Cmp(target_a, target_b) => self.cmp(target_a, target_b)?,
                Instruction::Jmp(addr) => self.jmp(addr),
                Instruction::JmpLt(addr) => self.jmp_lt(addr),
                Instruction::JmpGt(addr) => self.jmp_gt(addr),
                Instruction::JmpEq(addr) => self.jmp_eq(addr),

                Instruction::Push(dest, value) => self.push(dest, value),
                Instruction::Mov(dest, src) => self.mov(dest, src)?,
                Instruction::Swp(target_a, target_b) => self.swp(target_a, target_b)?,

                Instruction::Call(addr) => self.call(addr),
                Instruction::Ret => self.ret()?,
            }

            self.advance_pc();
        }

        Ok(())
    }

    /// Loads the instructions of the given program to the VM's state
    fn load_program(&mut self, program: Program) {
        self.image_data = program.instructions;
    }

    /// Resets the VM to a clean state
    fn reset(&mut self) {
        *self = VM::new();
    }

    fn reset_cmp(&mut self) {
        self.cmp_reg = None;
    }

    /// Advances the program counter
    fn advance_pc(&mut self) {
        if !self.skip_advance {
            self.pc += 1;
        } else {
            self.skip_advance = false;
        }
    }

    /// Return the value at the specified target. The value will be consumed
    /// from the target.
    fn pop(&mut self, target: &Target) -> VMResult<Value> {
        match target {
            &Target::Register(index) => {
                let value = self.data_registers[index].clone();
                self.data_registers[index] = Value::Nil;

                Ok(value)
            }
            &Target::Stack(index) => {
                if let Some(value) = self.data_stacks[index].pop() {
                    Ok(value)
                } else {
                    bail!("unable to pop value off an empty stack");
                }
            }
        }
    }

    // # Instruction functions

    /// Adds the value of the src target to the value of the dest target
    fn add(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value + src_value);

        Ok(())
    }

    /// Subtracts the value of the src target from the value of the dest target
    fn sub(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value - src_value);

        Ok(())
    }

    /// Divides the value of the dest target through the value of the src target
    fn div(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value / src_value);

        Ok(())
    }

    /// Multiplies the value of the dest target with the value of the src target
    fn mul(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value * src_value);

        Ok(())
    }

    /// Applies the modulo operator on the value of the dest target using the
    /// value of the src target
    fn modulo(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value * src_value);

        Ok(())
    }

    /// Compares the top values of the two targets and saves the result to
    /// `self.cmp_reg`
    fn cmp(&mut self, target_a: Target, target_b: Target) -> VMResult<()> {
        self.reset_cmp();

        let target_a_value = self.pop(&target_a)?;
        let target_b_value = self.pop(&target_b)?;

        if target_a_value < target_b_value {
            self.cmp_reg = Some(Ordering::Less);
        } else if target_a_value > target_b_value {
            self.cmp_reg = Some(Ordering::Greater);
        } else if target_a_value == target_b_value {
            self.cmp_reg = Some(Ordering::Equal);
        }

        Ok(())
    }

    /// Jumps unconditionally to the specified address
    fn jmp(&mut self, addr: Address) {
        self.pc = addr;
        self.skip_advance = true;
    }

    /// Jumps if the last compare got the result `Some(Ordering::Less)`
    fn jmp_lt(&mut self, addr: Address) {
        if self.cmp_reg == Some(Ordering::Less) {
            self.jmp(addr);
            self.reset_cmp();
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Greater)`
    fn jmp_gt(&mut self, addr: Address) {
        if self.cmp_reg == Some(Ordering::Greater) {
            self.jmp(addr);
            self.reset_cmp();
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Equal)`
    fn jmp_eq(&mut self, addr: Address) {
        if self.cmp_reg == Some(Ordering::Equal) {
            self.jmp(addr);
            self.reset_cmp();
        }
    }

    /// Pushes the given value to the given target
    fn push(&mut self, dest: Target, value: Value) {
        match dest {
            Target::Register(index) => self.data_registers[index] = value,
            Target::Stack(index) => self.data_stacks[index].push(value),
        }
    }

    /// Moves the top value of the src target to the dest target
    fn mov(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let src_value = self.pop(&src)?;
        self.push(dest, src_value);

        Ok(())
    }

    /// Swaps the top values of the targets
    fn swp(&mut self, target_a: Target, target_b: Target) -> VMResult<()> {
        let a_value = self.pop(&target_a)?;
        let b_value = self.pop(&target_b)?;

        self.push(target_a, b_value);
        self.push(target_b, a_value);

        Ok(())
    }

    /// Calls the function at the specified address saving the return address
    /// to the call stack
    fn call(&mut self, addr: Address) {
        self.call_stack.push(self.pc + 1);
        self.jmp(addr);
    }

    /// Returns from an ongoing function call
    fn ret(&mut self) -> VMResult<()> {
        if self.call_stack.is_empty() {
            bail!("unable to return from an empty call stack");
        }

        let retur_addr = self.call_stack.pop().unwrap();

        self.jmp(retur_addr);

        Ok(())
    }
}
<commit_msg>Added some more documentation<commit_after>use definitions::program::{Instruction, Program, Target, Value};
use definitions::typedef::*;
use error::*;
use std::cmp::Ordering;

const STACK_COUNT: usize = 2;
const REGISTER_COUNT: usize = 4;

/// The whole state of the VM
pub struct VM {
    /// The instructions that are currently executed
    image_data: Vec<Instruction>,
    /// The current program counter
    pc: Address,
    data_stacks: [Vec<Value>; STACK_COUNT],
    data_registers: [Value; REGISTER_COUNT],
    /// A register for holding infomation about a recent comparison
    cmp_reg: Option<Ordering>,
    call_stack: Vec<Address>,
    /// A boolean lock used for jumps
    skip_advance: bool,
}

impl VM {
    /// Creates a new VM state for executing programs
    pub fn new() -> VM {
        VM {
            image_data: Vec::new(),
            pc: 0,
            data_stacks: [Vec::new(), Vec::new()],
            data_registers: [Value::Nil, Value::Nil, Value::Nil, Value::Nil],
            cmp_reg: None,
            call_stack: Vec::new(),
            skip_advance: false,
        }
    }

    // # Maintainance functions

    /// Executes the given program
    pub fn exec(&mut self, program: Program) -> VMResult<()> {
        self.reset();
        self.load_program(program);

        while self.pc < self.image_data.len() {
            let current_instruction = self.image_data[self.pc].clone();

            match current_instruction {
                Instruction::Halt => break,

                Instruction::Add(dest, src) => self.add(dest, src)?,
                Instruction::Sub(dest, src) => self.sub(dest, src)?,
                Instruction::Div(dest, src) => self.div(dest, src)?,
                Instruction::Mul(dest, src) => self.mul(dest, src)?,
                Instruction::Mod(dest, src) => self.modulo(dest, src)?,

                Instruction::Cmp(target_a, target_b) => self.cmp(target_a, target_b)?,
                Instruction::Jmp(addr) => self.jmp(addr),
                Instruction::JmpLt(addr) => self.jmp_lt(addr),
                Instruction::JmpGt(addr) => self.jmp_gt(addr),
                Instruction::JmpEq(addr) => self.jmp_eq(addr),

                Instruction::Push(dest, value) => self.push(dest, value),
                Instruction::Mov(dest, src) => self.mov(dest, src)?,
                Instruction::Swp(target_a, target_b) => self.swp(target_a, target_b)?,

                Instruction::Call(addr) => self.call(addr),
                Instruction::Ret => self.ret()?,
            }

            self.advance_pc();
        }

        Ok(())
    }

    /// Loads the instructions of the given program to the VM's state
    fn load_program(&mut self, program: Program) {
        self.image_data = program.instructions;
    }

    /// Resets the VM to a clean state
    fn reset(&mut self) {
        *self = VM::new();
    }

    fn reset_cmp(&mut self) {
        self.cmp_reg = None;
    }

    /// Advances the program counter
    fn advance_pc(&mut self) {
        if !self.skip_advance {
            self.pc += 1;
        } else {
            self.skip_advance = false;
        }
    }

    /// Return the value at the specified target. The value will be consumed
    /// from the target.
    fn pop(&mut self, target: &Target) -> VMResult<Value> {
        match target {
            &Target::Register(index) => {
                let value = self.data_registers[index].clone();
                self.data_registers[index] = Value::Nil;

                Ok(value)
            }
            &Target::Stack(index) => {
                if let Some(value) = self.data_stacks[index].pop() {
                    Ok(value)
                } else {
                    bail!("unable to pop value off an empty stack");
                }
            }
        }
    }

    // # Instruction functions

    /// Adds the value of the src target to the value of the dest target
    fn add(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value + src_value);

        Ok(())
    }

    /// Subtracts the value of the src target from the value of the dest target
    fn sub(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value - src_value);

        Ok(())
    }

    /// Divides the value of the dest target through the value of the src target
    fn div(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value / src_value);

        Ok(())
    }

    /// Multiplies the value of the dest target with the value of the src target
    fn mul(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value * src_value);

        Ok(())
    }

    /// Applies the modulo operator on the value of the dest target using the
    /// value of the src target
    fn modulo(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let dest_value = self.pop(&dest)?;
        let src_value = self.pop(&src)?;

        self.push(dest, dest_value * src_value);

        Ok(())
    }

    /// Compares the top values of the two targets and saves the result to
    /// `self.cmp_reg`
    fn cmp(&mut self, target_a: Target, target_b: Target) -> VMResult<()> {
        self.reset_cmp();

        let target_a_value = self.pop(&target_a)?;
        let target_b_value = self.pop(&target_b)?;

        if target_a_value < target_b_value {
            self.cmp_reg = Some(Ordering::Less);
        } else if target_a_value > target_b_value {
            self.cmp_reg = Some(Ordering::Greater);
        } else if target_a_value == target_b_value {
            self.cmp_reg = Some(Ordering::Equal);
        }

        Ok(())
    }

    /// Jumps unconditionally to the specified address
    fn jmp(&mut self, addr: Address) {
        self.pc = addr;
        self.skip_advance = true;
    }

    /// Jumps if the last compare got the result `Some(Ordering::Less)`
    fn jmp_lt(&mut self, addr: Address) {
        if self.cmp_reg == Some(Ordering::Less) {
            self.jmp(addr);
            self.reset_cmp();
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Greater)`
    fn jmp_gt(&mut self, addr: Address) {
        if self.cmp_reg == Some(Ordering::Greater) {
            self.jmp(addr);
            self.reset_cmp();
        }
    }

    /// Jumps if the last compare got the result `Some(Ordering::Equal)`
    fn jmp_eq(&mut self, addr: Address) {
        if self.cmp_reg == Some(Ordering::Equal) {
            self.jmp(addr);
            self.reset_cmp();
        }
    }

    /// Pushes the given value to the given target
    fn push(&mut self, dest: Target, value: Value) {
        match dest {
            Target::Register(index) => self.data_registers[index] = value,
            Target::Stack(index) => self.data_stacks[index].push(value),
        }
    }

    /// Moves the top value of the src target to the dest target
    fn mov(&mut self, dest: Target, src: Target) -> VMResult<()> {
        let src_value = self.pop(&src)?;
        self.push(dest, src_value);

        Ok(())
    }

    /// Swaps the top values of the targets
    fn swp(&mut self, target_a: Target, target_b: Target) -> VMResult<()> {
        let a_value = self.pop(&target_a)?;
        let b_value = self.pop(&target_b)?;

        self.push(target_a, b_value);
        self.push(target_b, a_value);

        Ok(())
    }

    /// Calls the function at the specified address saving the return address
    /// to the call stack
    fn call(&mut self, addr: Address) {
        self.call_stack.push(self.pc + 1);
        self.jmp(addr);
    }

    /// Returns from an ongoing function call
    fn ret(&mut self) -> VMResult<()> {
        if self.call_stack.is_empty() {
            bail!("unable to return from an empty call stack");
        }

        let retur_addr = self.call_stack.pop().unwrap();

        self.jmp(retur_addr);

        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::fmt;

use crate::protobuf_abs_path::ProtobufAbsPath;
use crate::protobuf_rel_path::ProtobufRelPath;

/// Protobuf identifier can be absolute or relative.
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub enum ProtobufPath {
    Abs(ProtobufAbsPath),
    Rel(ProtobufRelPath),
}

impl ProtobufPath {
    pub fn new<S: Into<String>>(path: S) -> ProtobufPath {
        let path = path.into();
        if path.starts_with('.') {
            ProtobufPath::Abs(ProtobufAbsPath::new(path))
        } else {
            ProtobufPath::Rel(ProtobufRelPath::new(path))
        }
    }

    pub fn _resolve(&self, package: &ProtobufAbsPath) -> ProtobufAbsPath {
        match self {
            ProtobufPath::Abs(p) => p.clone(),
            ProtobufPath::Rel(p) => {
                let mut package = package.clone();
                package.push_relative(p);
                package
            }
        }
    }
}

impl fmt::Display for ProtobufPath {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ProtobufPath::Abs(p) => write!(f, "{}", p),
            ProtobufPath::Rel(p) => write!(f, "{}", p),
        }
    }
}
<commit_msg>Make ProtobufPath type crate-private<commit_after>use std::fmt;

use crate::protobuf_abs_path::ProtobufAbsPath;
use crate::protobuf_rel_path::ProtobufRelPath;

/// Protobuf identifier can be absolute or relative.
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub(crate) enum ProtobufPath {
    Abs(ProtobufAbsPath),
    Rel(ProtobufRelPath),
}

impl ProtobufPath {
    pub fn new<S: Into<String>>(path: S) -> ProtobufPath {
        let path = path.into();
        if path.starts_with('.') {
            ProtobufPath::Abs(ProtobufAbsPath::new(path))
        } else {
            ProtobufPath::Rel(ProtobufRelPath::new(path))
        }
    }

    pub fn _resolve(&self, package: &ProtobufAbsPath) -> ProtobufAbsPath {
        match self {
            ProtobufPath::Abs(p) => p.clone(),
            ProtobufPath::Rel(p) => {
                let mut package = package.clone();
                package.push_relative(p);
                package
            }
        }
    }
}

impl fmt::Display for ProtobufPath {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ProtobufPath::Abs(p) => write!(f, "{}", p),
            ProtobufPath::Rel(p) => write!(f, "{}", p),
        }
    }
}
<|endoftext|>