<commit_before>use std::cmp::{PartialEq, Eq};
use std::ops::{Neg, Add, Sub, Mul, Div};

#[derive(Copy, Debug)]
pub struct Vector3 {
    pub x: f64,
    pub y: f64,
    pub z: f64,
}

pub const ZERO: Vector3 = Vector3 { x: 0.0, y: 0.0, z: 0.0 };

impl Vector3 {
    pub fn new(_x: f64, _y: f64, _z: f64) -> Vector3 {
        Vector3 { x: _x, y: _y, z: _z }
    }

    pub fn length_square(&self) -> f64 {
        self.x.powi(2) + self.y.powi(2) + self.z.powi(2)
    }

    pub fn length(&self) -> f64 {
        self.length_square().sqrt()
    }

    pub fn normalize(&mut self) {
        let reciprocal_length = self.length().recip();
        self.x *= reciprocal_length;
        self.y *= reciprocal_length;
        self.z *= reciprocal_length;
    }

    pub fn is_normalized(&self) -> bool {
        self.length_square() == 1.0
    }

    pub fn cross(&self, other: &Vector3) -> Vector3 {
        Vector3 {
            x: self.y * other.z - self.z * other.y,
            y: self.z * other.x - self.x * other.z,
            z: self.x * other.y - self.y * other.x,
        }
    }
}

impl Clone for Vector3 {
    fn clone(&self) -> Vector3 {
        Vector3 {
            x: self.x,
            y: self.y,
            z: self.z,
        }
    }
}

impl Neg for Vector3 {
    type Output = Vector3;

    fn neg(self) -> Vector3 {
        Vector3 {
            x: -self.x,
            y: -self.y,
            z: -self.z,
        }
    }
}

impl Add for Vector3 {
    type Output = Vector3;

    fn add(self, other: Vector3) -> Vector3 {
        Vector3 {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
        }
    }
}

impl Sub for Vector3 {
    type Output = Vector3;

    fn sub(self, other: Vector3) -> Vector3 {
        Vector3 {
            x: self.x - other.x,
            y: self.y - other.y,
            z: self.z - other.z,
        }
    }
}

impl Mul<f64> for Vector3 {
    type Output = Vector3;

    fn mul(self, other: f64) -> Vector3 {
        Vector3 {
            x: self.x * other,
            y: self.y * other,
            z: self.z * other,
        }
    }
}

impl Mul<Vector3> for f64 {
    type Output = Vector3;

    fn mul(self, other: Vector3) -> Vector3 {
        Vector3 {
            x: self * other.x,
            y: self * other.y,
            z: self * other.z
        }
    }
}

impl Mul for Vector3 {
    type Output = f64;

    fn mul(self, other: Vector3) -> f64 {
        self.x * other.x + self.y * other.y + self.z * other.z
    }
}

impl Div<f64> for Vector3 {
    type Output = Vector3;

    fn div(self, other: f64) -> Vector3 {
        Vector3 {
            x: self.x / other,
            y: self.y / other,
            z: self.z / other,
        }
    }
}

impl PartialEq for Vector3 {
    fn eq(&self, other: &Vector3) -> bool {
        self.x == other.x && self.y == other.y && self.z == other.z
    }
}

impl Eq for Vector3 { }

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

    #[test]
    fn test_length_square() {
        let v = Vector3::new(1.0, 2.0, 3.0);
        assert_eq!(v.length_square(), 14.0);
    }

    #[test]
    fn test_length() {
        let v = Vector3::new(1.0, 2.0, 3.0);
        assert_eq!(v.length(), 14_f64.sqrt());
    }

    #[test]
    fn test_normalize() {
        let mut v = Vector3::new(2.0, 0.0, 0.0);
        v.normalize();
        assert_eq!(v, Vector3::new(1.0, 0.0, 0.0));
    }

    #[test]
    fn test_is_normalized() {
        let v1 = Vector3::new(1.0, 0.0, 0.0);
        let v2 = Vector3::new(1.0, 2.0, 3.0);
        assert!(v1.is_normalized());
        assert!(!v2.is_normalized());
    }

    #[test]
    fn test_cross() {
        let i = Vector3::new(1.0, 0.0, 0.0);
        let j = Vector3::new(0.0, 1.0, 0.0);
        let k = Vector3::new(0.0, 0.0, 1.0);

        assert_eq!(i.cross(&j), k);
        assert_eq!(j.cross(&i), -k);

        assert_eq!(j.cross(&k), i);
        assert_eq!(k.cross(&j), -i);

        assert_eq!(k.cross(&i), j);
        assert_eq!(i.cross(&k), -j);
    }

    #[test]
    fn test_neg() {
        let v = Vector3::new(1.0, 2.0, 3.0);
        assert_eq!(-v, Vector3::new(-1.0, -2.0, -3.0));
    }

    #[test]
    fn test_add() {
        let v1 = Vector3::new(1.0, 2.0, 3.0);
        let v2 = Vector3::new(4.0, 5.0, 6.0);
        let sum = v1 + v2;
        assert_eq!(sum, Vector3::new(5.0, 7.0, 9.0));
    }

    #[test]
    fn test_sub() {
        let v1 = Vector3::new(1.0, 2.0, 3.0);
        let v2 = Vector3::new(4.0, 5.0, 6.0);
        let sub = v2 - v1;
        assert_eq!(sub, Vector3::new(3.0, 3.0, 3.0));
    }

    #[test]
    fn test_mul() {
        let v1 = Vector3::new(1.0, 2.0, 3.0);
        let v2 = Vector3::new(4.0, 5.0, 6.0);
        let v3 = Vector3::new(2.0, 4.0, 6.0);
        assert_eq!(v1 * v2, 32.0);
        assert_eq!(2.0 * v1, v3);
        assert_eq!(v1 * 2.0, v3);
    }

    #[test]
    fn test_div() {
        let v = Vector3::new(2.0, 4.0, 6.0);
        assert_eq!(v / 2.0, Vector3::new(1.0, 2.0, 3.0));
    }

}
<commit_msg>derive Copy for struct Vector3<commit_after>use std::cmp::{PartialEq, Eq};
use std::ops::{Neg, Add, Sub, Mul, Div};

#[derive(Copy, Clone, Debug)]
pub struct Vector3 {
    pub x: f64,
    pub y: f64,
    pub z: f64,
}

pub const ZERO: Vector3 = Vector3 { x: 0.0, y: 0.0, z: 0.0 };

impl Vector3 {
    pub fn new(_x: f64, _y: f64, _z: f64) -> Vector3 {
        Vector3 { x: _x, y: _y, z: _z }
    }

    pub fn length_square(&self) -> f64 {
        self.x.powi(2) + self.y.powi(2) + self.z.powi(2)
    }

    pub fn length(&self) -> f64 {
        self.length_square().sqrt()
    }

    pub fn normalize(&mut self) {
        let reciprocal_length = self.length().recip();
        self.x *= reciprocal_length;
        self.y *= reciprocal_length;
        self.z *= reciprocal_length;
    }

    pub fn is_normalized(&self) -> bool {
        self.length_square() == 1.0
    }

    pub fn cross(&self, other: &Vector3) -> Vector3 {
        Vector3 {
            x: self.y * other.z - self.z * other.y,
            y: self.z * other.x - self.x * other.z,
            z: self.x * other.y - self.y * other.x,
        }
    }
}

impl Neg for Vector3 {
    type Output = Vector3;

    fn neg(self) -> Vector3 {
        Vector3 {
            x: -self.x,
            y: -self.y,
            z: -self.z,
        }
    }
}

impl Add for Vector3 {
    type Output = Vector3;

    fn add(self, other: Vector3) -> Vector3 {
        Vector3 {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
        }
    }
}

impl Sub for Vector3 {
    type Output = Vector3;

    fn sub(self, other: Vector3) -> Vector3 {
        Vector3 {
            x: self.x - other.x,
            y: self.y - other.y,
            z: self.z - other.z,
        }
    }
}

impl Mul<f64> for Vector3 {
    type Output = Vector3;

    fn mul(self, other: f64) -> Vector3 {
        Vector3 {
            x: self.x * other,
            y: self.y * other,
            z: self.z * other,
        }
    }
}

impl Mul<Vector3> for f64 {
    type Output = Vector3;

    fn mul(self, other: Vector3) -> Vector3 {
        Vector3 {
            x: self * other.x,
            y: self * other.y,
            z: self * other.z
        }
    }
}

impl Mul for Vector3 {
    type Output = f64;

    fn mul(self, other: Vector3) -> f64 {
        self.x * other.x + self.y * other.y + self.z * other.z
    }
}

impl Div<f64> for Vector3 {
    type Output = Vector3;

    fn div(self, other: f64) -> Vector3 {
        Vector3 {
            x: self.x / other,
            y: self.y / other,
            z: self.z / other,
        }
    }
}

impl PartialEq for Vector3 {
    fn eq(&self, other: &Vector3) -> bool {
        self.x == other.x && self.y == other.y && self.z == other.z
    }
}

impl Eq for Vector3 { }

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

    #[test]
    fn test_length_square() {
        let v = Vector3::new(1.0, 2.0, 3.0);
        assert_eq!(v.length_square(), 14.0);
    }

    #[test]
    fn test_length() {
        let v = Vector3::new(1.0, 2.0, 3.0);
        assert_eq!(v.length(), 14_f64.sqrt());
    }

    #[test]
    fn test_normalize() {
        let mut v = Vector3::new(2.0, 0.0, 0.0);
        v.normalize();
        assert_eq!(v, Vector3::new(1.0, 0.0, 0.0));
    }

    #[test]
    fn test_is_normalized() {
        let v1 = Vector3::new(1.0, 0.0, 0.0);
        let v2 = Vector3::new(1.0, 2.0, 3.0);
        assert!(v1.is_normalized());
        assert!(!v2.is_normalized());
    }

    #[test]
    fn test_cross() {
        let i = Vector3::new(1.0, 0.0, 0.0);
        let j = Vector3::new(0.0, 1.0, 0.0);
        let k = Vector3::new(0.0, 0.0, 1.0);

        assert_eq!(i.cross(&j), k);
        assert_eq!(j.cross(&i), -k);

        assert_eq!(j.cross(&k), i);
        assert_eq!(k.cross(&j), -i);

        assert_eq!(k.cross(&i), j);
        assert_eq!(i.cross(&k), -j);
    }

    #[test]
    fn test_neg() {
        let v = Vector3::new(1.0, 2.0, 3.0);
        assert_eq!(-v, Vector3::new(-1.0, -2.0, -3.0));
    }

    #[test]
    fn test_add() {
        let v1 = Vector3::new(1.0, 2.0, 3.0);
        let v2 = Vector3::new(4.0, 5.0, 6.0);
        let sum = v1 + v2;
        assert_eq!(sum, Vector3::new(5.0, 7.0, 9.0));
    }

    #[test]
    fn test_sub() {
        let v1 = Vector3::new(1.0, 2.0, 3.0);
        let v2 = Vector3::new(4.0, 5.0, 6.0);
        let sub = v2 - v1;
        assert_eq!(sub, Vector3::new(3.0, 3.0, 3.0));
    }

    #[test]
    fn test_mul() {
        let v1 = Vector3::new(1.0, 2.0, 3.0);
        let v2 = Vector3::new(4.0, 5.0, 6.0);
        let v3 = Vector3::new(2.0, 4.0, 6.0);
        assert_eq!(v1 * v2, 32.0);
        assert_eq!(2.0 * v1, v3);
        assert_eq!(v1 * 2.0, v3);
    }

    #[test]
    fn test_div() {
        let v = Vector3::new(2.0, 4.0, 6.0);
        assert_eq!(v / 2.0, Vector3::new(1.0, 2.0, 3.0));
    }

}
<|endoftext|>


<commit_before>#![allow(clippy::manual_assert)]

mod progress;

use self::progress::Progress;
use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "5e57faa78aa7661c6000204591558f6665f11abc";

#[rustfmt::skip]
static EXCLUDE: &[&str] = &[
    // TODO
    "src/test/ui/expr/if/attrs/let-chains-attr.rs",
    "src/test/ui/mir/mir_let_chains_drop_order.rs",
    "src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs",
    "src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs",
    "src/test/ui/rfc-2497-if-let-chains/issue-90722.rs",
    "src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs",
    "src/tools/rustfmt/tests/source/async_block.rs",
    "src/tools/rustfmt/tests/target/async_block.rs",

    // TODO: impl ~const T {}
    // https://github.com/dtolnay/syn/issues/1051
    "src/test/ui/rfc-2632-const-trait-impl/syntax.rs",

    // Compile-fail expr parameter in const generic position: f::<1 + 2>()
    "src/test/ui/const-generics/early/closing-args-token.rs",
    "src/test/ui/const-generics/early/const-expression-parameter.rs",

    // Deprecated anonymous parameter syntax in traits
    "src/test/ui/issues/issue-13105.rs",
    "src/test/ui/issues/issue-13775.rs",
    "src/test/ui/issues/issue-34074.rs",
    "src/test/ui/proc-macro/trait-fn-args-2015.rs",
    "src/tools/rustfmt/tests/source/trait.rs",
    "src/tools/rustfmt/tests/target/trait.rs",

    // Excessive nesting
    "src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs",

    // Testing rustfmt on invalid syntax
    "src/tools/rustfmt/tests/coverage/target/comments.rs",
    "src/tools/rustfmt/tests/parser/issue-4126/invalid.rs",
    "src/tools/rustfmt/tests/parser/issue_4418.rs",
    "src/tools/rustfmt/tests/parser/unclosed-delims/issue_4466.rs",
    "src/tools/rustfmt/tests/source/configs/disable_all_formatting/true.rs",
    "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/false.rs",
    "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/true.rs",
    "src/tools/rustfmt/tests/source/type.rs",
    "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/false.rs",
    "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/true.rs",
    "src/tools/rustfmt/tests/target/type.rs",

    // Clippy lint lists represented as expressions
    "src/tools/clippy/clippy_lints/src/lib.deprecated.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_all.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_cargo.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_complexity.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_correctness.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_internal.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_lints.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_nursery.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_perf.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_restriction.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_style.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs",

    // Not actually test cases
    "src/test/rustdoc-ui/test-compile-fail2.rs",
    "src/test/rustdoc-ui/test-compile-fail3.rs",
    "src/test/ui/json-bom-plus-crlf-multifile-aux.rs",
    "src/test/ui/lint/expansion-time-include.rs",
    "src/test/ui/macros/auxiliary/macro-comma-support.rs",
    "src/test/ui/macros/auxiliary/macro-include-items-expr.rs",
    "src/test/ui/macros/include-single-expr-helper.rs",
    "src/test/ui/macros/include-single-expr-helper-1.rs",
    "src/test/ui/parser/issues/auxiliary/issue-21146-inc.rs",
];

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map_or(true, |e| e != "rs") {
        return false;
    }

    let mut path_string = path.to_string_lossy();
    if cfg!(windows) {
        path_string = path_string.replace('\\', "/").into();
    }
    let path = if let Some(path) = path_string.strip_prefix("tests/rust/") {
        path
    } else {
        panic!("unexpected path in Rust dist: {}", path_string);
    };

    if path.starts_with("src/test/compile-fail") || path.starts_with("src/test/rustfix") {
        return false;
    }

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

    !EXCLUDE.contains(&path)
}

#[allow(dead_code)]
pub fn edition(path: &Path) -> &'static str {
    if path.ends_with("dyn-2015-no-warnings-without-lints.rs") {
        "2015"
    } else {
        "2018"
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
    let mut missing = String::new();
    let test_src = Path::new("tests/rust");
    for exclude in EXCLUDE {
        if !test_src.join(exclude).exists() {
            missing += "\ntests/rust/";
            missing += exclude;
        }
    }
    if !missing.is_empty() {
        panic!("excluded test file does not exist:{}\n", missing);
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let response = reqwest::blocking::get(&url)?.error_for_status()?;
    let progress = Progress::new(response);
    let decoder = GzDecoder::new(progress);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<commit_msg>Categorize most recent group of upstream's tests<commit_after>#![allow(clippy::manual_assert)]

mod progress;

use self::progress::Progress;
use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "5e57faa78aa7661c6000204591558f6665f11abc";

#[rustfmt::skip]
static EXCLUDE: &[&str] = &[
    // TODO: let chains
    "src/test/ui/expr/if/attrs/let-chains-attr.rs",
    "src/test/ui/mir/mir_let_chains_drop_order.rs",
    "src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs",
    "src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs",
    "src/test/ui/rfc-2497-if-let-chains/issue-90722.rs",
    "src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs",

    // TODO: static async closure keyword order
    "src/tools/rustfmt/tests/source/async_block.rs",
    "src/tools/rustfmt/tests/target/async_block.rs",

    // TODO: impl ~const T {}
    // https://github.com/dtolnay/syn/issues/1051
    "src/test/ui/rfc-2632-const-trait-impl/syntax.rs",

    // Compile-fail expr parameter in const generic position: f::<1 + 2>()
    "src/test/ui/const-generics/early/closing-args-token.rs",
    "src/test/ui/const-generics/early/const-expression-parameter.rs",

    // Deprecated anonymous parameter syntax in traits
    "src/test/ui/issues/issue-13105.rs",
    "src/test/ui/issues/issue-13775.rs",
    "src/test/ui/issues/issue-34074.rs",
    "src/test/ui/proc-macro/trait-fn-args-2015.rs",
    "src/tools/rustfmt/tests/source/trait.rs",
    "src/tools/rustfmt/tests/target/trait.rs",

    // Excessive nesting
    "src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs",

    // Testing rustfmt on invalid syntax
    "src/tools/rustfmt/tests/coverage/target/comments.rs",
    "src/tools/rustfmt/tests/parser/issue-4126/invalid.rs",
    "src/tools/rustfmt/tests/parser/issue_4418.rs",
    "src/tools/rustfmt/tests/parser/unclosed-delims/issue_4466.rs",
    "src/tools/rustfmt/tests/source/configs/disable_all_formatting/true.rs",
    "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/false.rs",
    "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/true.rs",
    "src/tools/rustfmt/tests/source/type.rs",
    "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/false.rs",
    "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/true.rs",
    "src/tools/rustfmt/tests/target/type.rs",

    // Clippy lint lists represented as expressions
    "src/tools/clippy/clippy_lints/src/lib.deprecated.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_all.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_cargo.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_complexity.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_correctness.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_internal.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_lints.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_nursery.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_perf.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_restriction.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_style.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs",

    // Not actually test cases
    "src/test/rustdoc-ui/test-compile-fail2.rs",
    "src/test/rustdoc-ui/test-compile-fail3.rs",
    "src/test/ui/json-bom-plus-crlf-multifile-aux.rs",
    "src/test/ui/lint/expansion-time-include.rs",
    "src/test/ui/macros/auxiliary/macro-comma-support.rs",
    "src/test/ui/macros/auxiliary/macro-include-items-expr.rs",
    "src/test/ui/macros/include-single-expr-helper.rs",
    "src/test/ui/macros/include-single-expr-helper-1.rs",
    "src/test/ui/parser/issues/auxiliary/issue-21146-inc.rs",
];

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map_or(true, |e| e != "rs") {
        return false;
    }

    let mut path_string = path.to_string_lossy();
    if cfg!(windows) {
        path_string = path_string.replace('\\', "/").into();
    }
    let path = if let Some(path) = path_string.strip_prefix("tests/rust/") {
        path
    } else {
        panic!("unexpected path in Rust dist: {}", path_string);
    };

    if path.starts_with("src/test/compile-fail") || path.starts_with("src/test/rustfix") {
        return false;
    }

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

    !EXCLUDE.contains(&path)
}

#[allow(dead_code)]
pub fn edition(path: &Path) -> &'static str {
    if path.ends_with("dyn-2015-no-warnings-without-lints.rs") {
        "2015"
    } else {
        "2018"
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
    let mut missing = String::new();
    let test_src = Path::new("tests/rust");
    for exclude in EXCLUDE {
        if !test_src.join(exclude).exists() {
            missing += "\ntests/rust/";
            missing += exclude;
        }
    }
    if !missing.is_empty() {
        panic!("excluded test file does not exist:{}\n", missing);
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let response = reqwest::blocking::get(&url)?.error_for_status()?;
    let progress = Progress::new(response);
    let decoder = GzDecoder::new(progress);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<|endoftext|>


<commit_before>

#[macro_export]
pub macro_rules! map {
  ($a: expr, $b: expr) => {
    ::peruse::parsers::MapParser{
      parser: $a,
      mapper: box $b
    }
  }
}

#[macro_export]
macro_rules! or {
  ($a: expr, $b: expr) => {
    ::peruse::parsers::OrParser{
      a: $a,
      b: $b,
    }
 };
  ($a: expr, $b: expr $(, $c: expr)* ) => {
    ::peruse::parsers::OrParser{
      a: $a,
      b: or!($b, $($c),*),
    }
  };
  ($a: expr $(, $b: expr)+ to $mapper: expr) => {
    map!(or!($a, $($b),+), $mapper)
  }

}

#[macro_export]
pub macro_rules! seq {
  ($a: expr, $b: expr ) => {
    ::peruse::parsers::DualParser{
      first: $a,
      second: $b,
    }
 };
  ($a: expr, $b: expr $(, $c: expr)* ) => {
    ::peruse::parsers::DualParser{
      first: $a,
      second: seq!($b, $($c),* ),
    }
  };
  ($a: expr $(, $b: expr)+ to $mapper: expr) => {
    map!(seq!($a, $($b),+), $mapper)
  }
}

#[macro_export]
pub macro_rules! repsep {
  ($rep: expr, $sep: expr, $min: expr) => {
    ::peruse::parsers::RepSepParser{
      rep: $rep,
      sep: $sep,
      min_reps: $min,
    }
  };
  ($rep: expr, $sep: expr) => {
    repsep!($rep, $sep, 0)
  };
}

#[macro_export]
pub macro_rules! rep {
  ($rep: expr) => {
    ::peruse::parsers::RepParser{
      parser: $rep,
    }
  }
}

#[macro_export]
pub macro_rules! opt {
  ($rep: expr) => {
    ::peruse::parsers::OptionParser{
      parser: $rep,
    }
  }
}

#[macro_export]
pub macro_rules! lazy {
  ($rep: expr) => {
    ::peruse::parsers::LazyParser{
      generator: box |&:| $rep
    }
  }
}

#[macro_export]
pub macro_rules! matcher {
  ($t: ty : $($m: pat => $map: expr),+) => {
    ::peruse::parsers::MatchParser{
      matcher: box |&: i: &$t| match *i {
        $(
        $m => Ok($map),
        )+
        other => Err(format!("Match error"))
      }
    }
  }
}
<commit_msg>Fix macro compile errors on newer Rust<commit_after>

#[macro_export]
pub macro_rules! map {
  ($a: expr, $b: expr) => {
    ::peruse::parsers::MapParser{
      parser: $a,
      mapper: box $b
    }
  }
}

#[macro_export]
macro_rules! or {
  ($a: expr, $b: expr) => {
    ::peruse::parsers::OrParser{
      a: $a,
      b: $b,
    }
 };
  ($a: expr, $b: expr, $($c: expr),* ) => {
    ::peruse::parsers::OrParser{
      a: $a,
      b: or!($b, $($c),*),
    }
  };
  ($a: expr, $($b: expr),+ to $mapper: expr) => {
    map!(or!($a, $($b),+), $mapper)
  }

}

#[macro_export]
pub macro_rules! seq {
  ($a: expr, $b: expr ) => {
    ::peruse::parsers::DualParser{
      first: $a,
      second: $b,
    }
 };
  ($a: expr, $b: expr, $($c: expr),* ) => {
    ::peruse::parsers::DualParser{
      first: $a,
      second: seq!($b, $($c),* ),
    }
  };
  ($a: expr, $($b: expr),+ to $mapper: expr) => {
    map!(seq!($a, $($b),+), $mapper)
  }
}

#[macro_export]
pub macro_rules! repsep {
  ($rep: expr, $sep: expr, $min: expr) => {
    ::peruse::parsers::RepSepParser{
      rep: $rep,
      sep: $sep,
      min_reps: $min,
    }
  };
  ($rep: expr, $sep: expr) => {
    repsep!($rep, $sep, 0)
  };
}

#[macro_export]
pub macro_rules! rep {
  ($rep: expr) => {
    ::peruse::parsers::RepParser{
      parser: $rep,
    }
  }
}

#[macro_export]
pub macro_rules! opt {
  ($rep: expr) => {
    ::peruse::parsers::OptionParser{
      parser: $rep,
    }
  }
}

#[macro_export]
pub macro_rules! lazy {
  ($rep: expr) => {
    ::peruse::parsers::LazyParser{
      generator: box |&:| $rep
    }
  }
}

#[macro_export]
pub macro_rules! matcher {
  ($t: ty : $($m: pat => $map: expr),+) => {
    ::peruse::parsers::MatchParser{
      matcher: box |&: i: &$t| match *i {
        $(
        $m => Ok($map),
        )+
        other => Err(format!("Match error"))
      }
    }
  }
}
<|endoftext|>


<commit_before>//! Utilities for generalized iterators over trees of arbitrary types.

use std;

#[repr(u8)]

/// Descriptions of actions that may be taken on a given node when traversing
/// a pattern tree.
pub mod action {
    enum Flag {
        /// Terminate iteration after performing other specified actions.
        TERMINATE = 1,
    }

    pub use self::Flag::*;

    struct Action<U,V> {
        yield_value: Option<U>,
        recurse_on: Option<V>,
        flags: u8
    }
}

pub use self::action::Action;

/// Interface for patterns whose elements may be visited in
/// a runtime-specified manner.
///
/// @tparam Tag Marker type used to discriminate the "type" of walk being
///     implemented.  A particular type may be walked for different purposes,
///     such as to visit *all* elements, or only certain ones.
///
/// @tparam Yielded Type of item the walkable should implement an iterator for.
trait Walkable<Tag,Yielded>: std::marker::PhantomFn<Tag> {
    /// Iterator type that for the implementer's underlying container.
    type BaseIterator;
    type Item = <Self::BaseIterator as Iterator>::Item;
    type Action = Action<Yielded,Self::Item>;

    /// Fetch the initial iterator to use for a walk.
    fn iter(&self) -> Self::BaseIterator;

    /// Determine the action to take for a given node in the implementor's
    /// element tree.
    ///
    /// @param element Pattern element to process.
    ///
    /// @return Tuple containing the optionally-yielded element, and a set of
    ///     flags indicating how to proceed.  Action::RECURSE is only valid
    ///     when `Item` implements Walkable<Yielded>.
    fn action<'a>(element: &'a Self::Item) -> Self::Action
        where Self::Item: Walkable<Tag,Yielded>;
}

// FIXME: should the order of `T` and `Yielded` be reversed?
/// Iterator used to perform a particular walk on a particular type.
///
/// @tparam Tag Walk-type tag.
///
/// @tparam Yielded `Item` type for the iterator implementation of
///     the structure.
///
/// @tparam T Top-level Walkable type for which this structure is an iterator.
struct Walker<Tag,Yielded,T> where T: Walkable<Tag,Yielded> {
    base_iterator: Option<<T as Walkable<Tag,Yielded>>::BaseIterator>,
    sub_iterator: Option<Walker<Tag,Yielded,Yielded>>,
}

impl<Tag,Yielded,T> Walker<Tag,Yielded,T>
where T: Walkable<Tag,Yielded> {
    /// Create a new walker iterator from the given base iterator.
    pub fn new(base: <T as Walkable<Tag,Yielded>>::BaseIterator) -> Walker<Tag,Yielded,T> {
        Walker{base_iterator: base, sub_iterator: None}
    }
}

impl<'a,Tag,Yielded,T> Iterator for Walker<Tag,Yielded,T>
where T: Walkable<Tag,Yielded>, Yielded: Walkable<Tag,Yielded> {
    type Item = &'a Yielded;

    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
        // "can't use type parameter from outer function" Why not?  And it's not a function.
        //type Walk = Walkable<Tag,Yielded>;
        // "huh?  why's there a less-than sign in here?"  Because I put it there.
        //use self::Walkable<Tag,Yielded> as Walk;

        if let Some(ref iter) = self.sub_iterator {
            if let Some(yielded) = (*iter).next() {
                return yielded; }
            else {
                // Sub-iterator is empty; clear it and fall through to the
                // base iterator.
                self.sub_iterator = None;
            } }
        if let Some(ref iter) = self.base_iterator {
            if let Some(ref element) = (*iter).next() {
                let action = <T as Walkable<Tag,Yielded>>::action(element);

                // FIXME: need to provide a way to specify order in which
                // to recurse vs. yield.  The solution should allow for
                // selection of different traversal methods -- need to come
                // up with an API for that.
                if let Some(recurse_item) = action.recurse_on {
                    self.sub_iterator = Some(Walker::new(<Yielded as Walkable<Tag,Yielded>>::iter(recurse_item)));

                    // Recurse immediately if we have no value to yield.
                    if ! action.yield_value.is_some() {
                        self.next()
                    }
                }

                // For now we'll just do depth-first, since it's simplest.
                if let Some(yielded) = action.yield_value {
                    return yielded;
                }

                // Clear the base iterator if we were asked to terminate
                // the walk.  Note that any recursive walks on
                // `self.sub_iterator` will continue until that iterator
                // is exhausted.
                if action.flags & action::TERMINATE {
                    self.base_iterator = None; }
            } else {
                // Base iterator is exhausted; clear it.
                self.base_iterator = None;
            }
        }
        return None;
    }

    /// We implement `size_hint` as the sum of the hints for the current base-
    /// and sub-iterators, if they're not `None`.  We return an upper bound
    /// only if both iterators are `None`.
    fn size_hint(&self) -> (usize, Option<usize>) {
        let mut min = 0;
        if let Some(iter) = self.sub_iterator { min += iter.size_hint().0 }
        if let Some(iter) = self.base_iterator { min += iter.size_hint().0 }

        (min, if self.sub_iterator.is_none() && self.base_iterator.is_none() { Some(0) } else { None })
    }
}
<commit_msg>pattern/walk: removed stray `#[repr(u8)]`<commit_after>//! Utilities for generalized iterators over trees of arbitrary types.

use std;

/// Descriptions of actions that may be taken on a given node when traversing
/// a pattern tree.
pub mod action {
    enum Flag {
        /// Terminate iteration after performing other specified actions.
        TERMINATE = 1,
    }

    pub use self::Flag::*;

    struct Action<U,V> {
        yield_value: Option<U>,
        recurse_on: Option<V>,
        flags: u8
    }
}

pub use self::action::Action;

/// Interface for patterns whose elements may be visited in
/// a runtime-specified manner.
///
/// @tparam Tag Marker type used to discriminate the "type" of walk being
///     implemented.  A particular type may be walked for different purposes,
///     such as to visit *all* elements, or only certain ones.
///
/// @tparam Yielded Type of item the walkable should implement an iterator for.
trait Walkable<Tag,Yielded>: std::marker::PhantomFn<Tag> {
    /// Iterator type that for the implementer's underlying container.
    type BaseIterator;
    type Item = <Self::BaseIterator as Iterator>::Item;
    type Action = Action<Yielded,Self::Item>;

    /// Fetch the initial iterator to use for a walk.
    fn iter(&self) -> Self::BaseIterator;

    /// Determine the action to take for a given node in the implementor's
    /// element tree.
    ///
    /// @param element Pattern element to process.
    ///
    /// @return Tuple containing the optionally-yielded element, and a set of
    ///     flags indicating how to proceed.  Action::RECURSE is only valid
    ///     when `Item` implements Walkable<Yielded>.
    fn action<'a>(element: &'a Self::Item) -> Self::Action
        where Self::Item: Walkable<Tag,Yielded>;
}

// FIXME: should the order of `T` and `Yielded` be reversed?
/// Iterator used to perform a particular walk on a particular type.
///
/// @tparam Tag Walk-type tag.
///
/// @tparam Yielded `Item` type for the iterator implementation of
///     the structure.
///
/// @tparam T Top-level Walkable type for which this structure is an iterator.
struct Walker<Tag,Yielded,T> where T: Walkable<Tag,Yielded> {
    base_iterator: Option<<T as Walkable<Tag,Yielded>>::BaseIterator>,
    sub_iterator: Option<Walker<Tag,Yielded,Yielded>>,
}

impl<Tag,Yielded,T> Walker<Tag,Yielded,T>
where T: Walkable<Tag,Yielded> {
    /// Create a new walker iterator from the given base iterator.
    pub fn new(base: <T as Walkable<Tag,Yielded>>::BaseIterator) -> Walker<Tag,Yielded,T> {
        Walker{base_iterator: base, sub_iterator: None}
    }
}

impl<'a,Tag,Yielded,T> Iterator for Walker<Tag,Yielded,T>
where T: Walkable<Tag,Yielded>, Yielded: Walkable<Tag,Yielded> {
    type Item = &'a Yielded;

    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
        // "can't use type parameter from outer function" Why not?  And it's not a function.
        //type Walk = Walkable<Tag,Yielded>;
        // "huh?  why's there a less-than sign in here?"  Because I put it there.
        //use self::Walkable<Tag,Yielded> as Walk;

        if let Some(ref iter) = self.sub_iterator {
            if let Some(yielded) = (*iter).next() {
                return yielded; }
            else {
                // Sub-iterator is empty; clear it and fall through to the
                // base iterator.
                self.sub_iterator = None;
            } }
        if let Some(ref iter) = self.base_iterator {
            if let Some(ref element) = (*iter).next() {
                let action = <T as Walkable<Tag,Yielded>>::action(element);

                // FIXME: need to provide a way to specify order in which
                // to recurse vs. yield.  The solution should allow for
                // selection of different traversal methods -- need to come
                // up with an API for that.
                if let Some(recurse_item) = action.recurse_on {
                    self.sub_iterator = Some(Walker::new(<Yielded as Walkable<Tag,Yielded>>::iter(recurse_item)));

                    // Recurse immediately if we have no value to yield.
                    if ! action.yield_value.is_some() {
                        self.next()
                    }
                }

                // For now we'll just do depth-first, since it's simplest.
                if let Some(yielded) = action.yield_value {
                    return yielded;
                }

                // Clear the base iterator if we were asked to terminate
                // the walk.  Note that any recursive walks on
                // `self.sub_iterator` will continue until that iterator
                // is exhausted.
                if action.flags & action::TERMINATE {
                    self.base_iterator = None; }
            } else {
                // Base iterator is exhausted; clear it.
                self.base_iterator = None;
            }
        }
        return None;
    }

    /// We implement `size_hint` as the sum of the hints for the current base-
    /// and sub-iterators, if they're not `None`.  We return an upper bound
    /// only if both iterators are `None`.
    fn size_hint(&self) -> (usize, Option<usize>) {
        let mut min = 0;
        if let Some(iter) = self.sub_iterator { min += iter.size_hint().0 }
        if let Some(iter) = self.base_iterator { min += iter.size_hint().0 }

        (min, if self.sub_iterator.is_none() && self.base_iterator.is_none() { Some(0) } else { None })
    }
}
<|endoftext|>


<commit_before>extern crate serde_bytes;
use serde_bytes::{Bytes, ByteBuf};

extern crate serde_test;
use serde_test::{assert_tokens, assert_ser_tokens, assert_de_tokens, Token};

#[test]
fn test_bytes() {
    let empty = Bytes::new(&[]);
    assert_ser_tokens(&empty, &[Token::Bytes(b"")]);

    let buf = vec![65, 66, 67];
    let bytes = Bytes::new(&buf);
    assert_ser_tokens(&bytes, &[Token::Bytes(b"ABC")]);
}

#[test]
fn test_byte_buf() {
    let empty = ByteBuf::new();
    assert_tokens(&empty, &[Token::Bytes(b"")]);
    assert_de_tokens(&empty, &[Token::ByteBuf(b"")]);
    assert_de_tokens(&empty, &[Token::Str("")]);
    assert_de_tokens(&empty, &[Token::String("")]);
    assert_de_tokens(&empty, &[
        Token::Seq { len: None },
        Token::SeqEnd,
    ]);
    assert_de_tokens(&empty, &[
        Token::Seq { len: Some(0) },
        Token::SeqEnd,
    ]);

    let buf = ByteBuf::from(vec![65, 66, 67]);
    assert_tokens(&buf, &[Token::Bytes(b"ABC")]);
    assert_de_tokens(&buf, &[Token::ByteBuf(b"ABC")]);
    assert_de_tokens(&buf, &[Token::Str("ABC")]);
    assert_de_tokens(&buf, &[Token::String("ABC")]);
    assert_de_tokens(&buf, &[
        Token::Seq { len: None },
        Token::U8(65),
        Token::U8(66),
        Token::U8(67),
        Token::SeqEnd,
    ]);
    assert_de_tokens(&buf, &[
        Token::Seq { len: Some(3) },
        Token::U8(65),
        Token::U8(66),
        Token::U8(67),
        Token::SeqEnd,
    ]);
}
<commit_msg>Add tests<commit_after>extern crate serde_bytes;
use serde_bytes::{Bytes, ByteBuf};

extern crate serde_test;
use serde_test::{assert_tokens, assert_ser_tokens, assert_de_tokens, Token};

#[test]
fn test_bytes() {
    let empty = Bytes::new(&[]);
    assert_tokens(&empty, &[Token::BorrowedBytes(b"")]);
    assert_ser_tokens(&empty, &[Token::Bytes(b"")]);
    assert_ser_tokens(&empty, &[Token::ByteBuf(b"")]);
    assert_de_tokens(&empty, &[Token::BorrowedStr("")]);

    let buf = vec![65, 66, 67];
    let bytes = Bytes::new(&buf);
    assert_tokens(&bytes, &[Token::BorrowedBytes(b"ABC")]);
    assert_ser_tokens(&bytes, &[Token::Bytes(b"ABC")]);
    assert_ser_tokens(&bytes, &[Token::ByteBuf(b"ABC")]);
    assert_de_tokens(&bytes, &[Token::BorrowedStr("ABC")]);
}

#[test]
fn test_byte_buf() {
    let empty = ByteBuf::new();
    assert_tokens(&empty, &[Token::BorrowedBytes(b"")]);
    assert_tokens(&empty, &[Token::Bytes(b"")]);
    assert_tokens(&empty, &[Token::ByteBuf(b"")]);
    assert_de_tokens(&empty, &[Token::BorrowedStr("")]);
    assert_de_tokens(&empty, &[Token::Str("")]);
    assert_de_tokens(&empty, &[Token::String("")]);
    assert_de_tokens(&empty, &[
        Token::Seq { len: None },
        Token::SeqEnd,
    ]);
    assert_de_tokens(&empty, &[
        Token::Seq { len: Some(0) },
        Token::SeqEnd,
    ]);

    let buf = ByteBuf::from(vec![65, 66, 67]);
    assert_tokens(&buf, &[Token::BorrowedBytes(b"ABC")]);
    assert_tokens(&buf, &[Token::Bytes(b"ABC")]);
    assert_tokens(&buf, &[Token::ByteBuf(b"ABC")]);
    assert_de_tokens(&buf, &[Token::BorrowedStr("ABC")]);
    assert_de_tokens(&buf, &[Token::Str("ABC")]);
    assert_de_tokens(&buf, &[Token::String("ABC")]);
    assert_de_tokens(&buf, &[
        Token::Seq { len: None },
        Token::U8(65),
        Token::U8(66),
        Token::U8(67),
        Token::SeqEnd,
    ]);
    assert_de_tokens(&buf, &[
        Token::Seq { len: Some(3) },
        Token::U8(65),
        Token::U8(66),
        Token::U8(67),
        Token::SeqEnd,
    ]);
}
<|endoftext|>


<commit_before>use cssparser::{self, Parser};

use crate::allowed_url::Fragment;
use crate::bbox::BoundingBox;
use crate::drawing_ctx::DrawingCtx;
use crate::error::*;
use crate::node::{CascadedValues, RsvgNode};
use crate::parsers::Parse;
use crate::properties::ComputedValues;
use crate::unit_interval::UnitInterval;

#[derive(Debug, Clone, PartialEq)]
pub enum PaintServer {
    None,
    Iri {
        iri: Fragment,
        alternate: Option<cssparser::Color>,
    },
    SolidColor(cssparser::Color),
}

impl Parse for PaintServer {
    type Err = ValueErrorKind;

    fn parse(parser: &mut Parser<'_, '_>) -> Result<PaintServer, ValueErrorKind> {
        if parser
            .try_parse(|i| i.expect_ident_matching("none"))
            .is_ok()
        {
            Ok(PaintServer::None)
        } else if let Ok(url) = parser.try_parse(|i| i.expect_url()) {
            let alternate = if !parser.is_exhausted() {
                if parser
                    .try_parse(|i| i.expect_ident_matching("none"))
                    .is_ok()
                {
                    None
                } else {
                    Some(parser.try_parse(|i| cssparser::Color::parse(i))?)
                }
            } else {
                None
            };

            Ok(PaintServer::Iri {
                iri: Fragment::parse(&url)?,
                alternate,
            })
        } else {
            cssparser::Color::parse(parser)
                .map(PaintServer::SolidColor)
                .map_err(ValueErrorKind::from)
        }
    }
}

pub trait PaintSource {
    type Resolved: ResolvedPaintSource;

    fn resolve(
        &self,
        node: &RsvgNode,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<Self::Resolved, PaintServerError>;

    fn resolve_fallbacks_and_set_pattern(
        &self,
        node: &RsvgNode,
        draw_ctx: &mut DrawingCtx,
        opacity: &UnitInterval,
        bbox: &BoundingBox,
    ) -> Result<bool, RenderingError> {
        match self.resolve(&node, draw_ctx) {
            Ok(resolved) => {
                let cascaded = CascadedValues::new_from_node(node);
                let values = cascaded.get();
                resolved.set_pattern_on_draw_context(values, draw_ctx, opacity, bbox)
            }

            Err(PaintServerError::CircularReference(_)) => {
                // FIXME: add a fragment or node id to this:
                rsvg_log!("circular reference in paint server {}", node);
                Err(RenderingError::CircularReference)
            }

            Err(e) => {
                rsvg_log!("not using paint server {}: {}", node, e);

                // "could not resolve" means caller needs to fall back to color
                Ok(false)
            }
        }
    }
}

pub trait ResolvedPaintSource {
    fn set_pattern_on_draw_context(
        self,
        values: &ComputedValues,
        draw_ctx: &mut DrawingCtx,
        opacity: &UnitInterval,
        bbox: &BoundingBox,
    ) -> Result<bool, RenderingError>;
}

// Any of the attributes in gradient and pattern elements may be omitted.
// The missing ones are resolved from the "fallback" IRI. If still missing,
// they are resolved to the default value
pub trait Resolve {
    fn is_resolved(&self) -> bool;

    fn resolve_from_fallback(&mut self, fallback: &Self);

    fn resolve_from_defaults(&mut self);
}

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

    #[test]
    fn catches_invalid_syntax() {
        assert!(PaintServer::parse_str("").is_err());
        assert!(PaintServer::parse_str("42").is_err());
        assert!(PaintServer::parse_str("invalid").is_err());
    }

    #[test]
    fn parses_none() {
        assert_eq!(PaintServer::parse_str("none"), Ok(PaintServer::None));
    }

    #[test]
    fn parses_solid_color() {
        assert_eq!(
            PaintServer::parse_str("rgb(255, 128, 64, 0.5)"),
            Ok(PaintServer::SolidColor(cssparser::Color::RGBA(
                cssparser::RGBA::new(255, 128, 64, 128)
            )))
        );

        assert_eq!(
            PaintServer::parse_str("currentColor"),
            Ok(PaintServer::SolidColor(cssparser::Color::CurrentColor))
        );
    }

    #[test]
    fn parses_iri() {
        assert_eq!(
            PaintServer::parse_str("url(#link)"),
            Ok(PaintServer::Iri {
                iri: Fragment::new(None, "link".to_string()),
                alternate: None,
            },)
        );

        assert_eq!(
            PaintServer::parse_str("url(foo#link) none"),
            Ok(PaintServer::Iri {
                iri: Fragment::new(Some("foo".to_string()), "link".to_string()),
                alternate: None,
            },)
        );

        assert_eq!(
            PaintServer::parse_str("url(#link) #ff8040"),
            Ok(PaintServer::Iri {
                iri: Fragment::new(None, "link".to_string()),
                alternate: Some(cssparser::Color::RGBA(cssparser::RGBA::new(
                    255, 128, 64, 255
                ))),
            },)
        );

        assert_eq!(
            PaintServer::parse_str("url(#link) rgb(255, 128, 64, 0.5)"),
            Ok(PaintServer::Iri {
                iri: Fragment::new(None, "link".to_string()),
                alternate: Some(cssparser::Color::RGBA(cssparser::RGBA::new(
                    255, 128, 64, 128
                ))),
            },)
        );

        assert_eq!(
            PaintServer::parse_str("url(#link) currentColor"),
            Ok(PaintServer::Iri {
                iri: Fragment::new(None, "link".to_string()),
                alternate: Some(cssparser::Color::CurrentColor),
            },)
        );

        assert!(PaintServer::parse_str("url(#link) invalid").is_err());
    }
}
<commit_msg>Prepare trait Resolve for immutability later<commit_after>use cssparser::{self, Parser};

use crate::allowed_url::Fragment;
use crate::bbox::BoundingBox;
use crate::drawing_ctx::DrawingCtx;
use crate::error::*;
use crate::node::{CascadedValues, RsvgNode};
use crate::parsers::Parse;
use crate::properties::ComputedValues;
use crate::unit_interval::UnitInterval;

#[derive(Debug, Clone, PartialEq)]
pub enum PaintServer {
    None,
    Iri {
        iri: Fragment,
        alternate: Option<cssparser::Color>,
    },
    SolidColor(cssparser::Color),
}

impl Parse for PaintServer {
    type Err = ValueErrorKind;

    fn parse(parser: &mut Parser<'_, '_>) -> Result<PaintServer, ValueErrorKind> {
        if parser
            .try_parse(|i| i.expect_ident_matching("none"))
            .is_ok()
        {
            Ok(PaintServer::None)
        } else if let Ok(url) = parser.try_parse(|i| i.expect_url()) {
            let alternate = if !parser.is_exhausted() {
                if parser
                    .try_parse(|i| i.expect_ident_matching("none"))
                    .is_ok()
                {
                    None
                } else {
                    Some(parser.try_parse(|i| cssparser::Color::parse(i))?)
                }
            } else {
                None
            };

            Ok(PaintServer::Iri {
                iri: Fragment::parse(&url)?,
                alternate,
            })
        } else {
            cssparser::Color::parse(parser)
                .map(PaintServer::SolidColor)
                .map_err(ValueErrorKind::from)
        }
    }
}

pub trait PaintSource {
    type Resolved: ResolvedPaintSource;

    fn resolve(
        &self,
        node: &RsvgNode,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<Self::Resolved, PaintServerError>;

    fn resolve_fallbacks_and_set_pattern(
        &self,
        node: &RsvgNode,
        draw_ctx: &mut DrawingCtx,
        opacity: &UnitInterval,
        bbox: &BoundingBox,
    ) -> Result<bool, RenderingError> {
        match self.resolve(&node, draw_ctx) {
            Ok(resolved) => {
                let cascaded = CascadedValues::new_from_node(node);
                let values = cascaded.get();
                resolved.set_pattern_on_draw_context(values, draw_ctx, opacity, bbox)
            }

            Err(PaintServerError::CircularReference(_)) => {
                // FIXME: add a fragment or node id to this:
                rsvg_log!("circular reference in paint server {}", node);
                Err(RenderingError::CircularReference)
            }

            Err(e) => {
                rsvg_log!("not using paint server {}: {}", node, e);

                // "could not resolve" means caller needs to fall back to color
                Ok(false)
            }
        }
    }
}

pub trait ResolvedPaintSource {
    fn set_pattern_on_draw_context(
        self,
        values: &ComputedValues,
        draw_ctx: &mut DrawingCtx,
        opacity: &UnitInterval,
        bbox: &BoundingBox,
    ) -> Result<bool, RenderingError>;
}

// Any of the attributes in gradient and pattern elements may be omitted.
// The missing ones are resolved from the "fallback" IRI. If still missing,
// they are resolved to the default value
pub trait Resolve {
    fn is_resolved(&self) -> bool;

    fn resolve_from_fallback(&self, fallback: &Self) -> Self;

    fn resolve_from_defaults(&self) -> Self;
}

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

    #[test]
    fn catches_invalid_syntax() {
        assert!(PaintServer::parse_str("").is_err());
        assert!(PaintServer::parse_str("42").is_err());
        assert!(PaintServer::parse_str("invalid").is_err());
    }

    #[test]
    fn parses_none() {
        assert_eq!(PaintServer::parse_str("none"), Ok(PaintServer::None));
    }

    #[test]
    fn parses_solid_color() {
        assert_eq!(
            PaintServer::parse_str("rgb(255, 128, 64, 0.5)"),
            Ok(PaintServer::SolidColor(cssparser::Color::RGBA(
                cssparser::RGBA::new(255, 128, 64, 128)
            )))
        );

        assert_eq!(
            PaintServer::parse_str("currentColor"),
            Ok(PaintServer::SolidColor(cssparser::Color::CurrentColor))
        );
    }

    #[test]
    fn parses_iri() {
        assert_eq!(
            PaintServer::parse_str("url(#link)"),
            Ok(PaintServer::Iri {
                iri: Fragment::new(None, "link".to_string()),
                alternate: None,
            },)
        );

        assert_eq!(
            PaintServer::parse_str("url(foo#link) none"),
            Ok(PaintServer::Iri {
                iri: Fragment::new(Some("foo".to_string()), "link".to_string()),
                alternate: None,
            },)
        );

        assert_eq!(
            PaintServer::parse_str("url(#link) #ff8040"),
            Ok(PaintServer::Iri {
                iri: Fragment::new(None, "link".to_string()),
                alternate: Some(cssparser::Color::RGBA(cssparser::RGBA::new(
                    255, 128, 64, 255
                ))),
            },)
        );

        assert_eq!(
            PaintServer::parse_str("url(#link) rgb(255, 128, 64, 0.5)"),
            Ok(PaintServer::Iri {
                iri: Fragment::new(None, "link".to_string()),
                alternate: Some(cssparser::Color::RGBA(cssparser::RGBA::new(
                    255, 128, 64, 128
                ))),
            },)
        );

        assert_eq!(
            PaintServer::parse_str("url(#link) currentColor"),
            Ok(PaintServer::Iri {
                iri: Fragment::new(None, "link".to_string()),
                alternate: Some(cssparser::Color::CurrentColor),
            },)
        );

        assert!(PaintServer::parse_str("url(#link) invalid").is_err());
    }
}
<|endoftext|>


<commit_before>extern crate term;

use std::time::duration::Duration;
use std::io::timer::{sleep};

pub fn spinner(rx: Receiver<int>, tx: Sender<int>) {
    let spinner = vec!["|", "/", "-", "\\",];
    for spin in spinner.iter().cycle() {
        say("white", "\x08");
        say("yellow", *spin);
        let r = rx.try_recv();
        match r {
            Ok(_) => {
                say("white", "\x08 ");
                tx.send(1);
                break;
            },
            Err(_) => {
                sleep(Duration::milliseconds(100i64));
                continue;
            }
        }
    }
}

pub fn say(color: &str, to_say: &str) {
    let mut t = term::stdout().unwrap();
    let color_const = match color {
        "green" => term::color::BRIGHT_GREEN,
        "yellow" => term::color::BRIGHT_YELLOW,
        "red" => term::color::BRIGHT_RED,
        "magenta" => term::color::BRIGHT_MAGENTA,
        "white" => term::color::WHITE,
        _ => term::color::WHITE
    };
    t.fg(color_const).unwrap();
    (write!(t, "{}", to_say)).unwrap();
    t.reset().unwrap()
}

pub fn sayln(color: &str, to_say: &str) {
    let mut t = term::stdout().unwrap();
    say(color, to_say);
    (write!(t, "\n")).unwrap();
}

<commit_msg>Say needs an extra backspace<commit_after>extern crate term;

use std::time::duration::Duration;
use std::io::timer::{sleep};

pub fn spinner(rx: Receiver<int>, tx: Sender<int>) {
    let spinner = vec!["|", "/", "-", "\\",];
    for spin in spinner.iter().cycle() {
        say("white", "\x08");
        say("yellow", *spin);
        let r = rx.try_recv();
        match r {
            Ok(_) => {
                say("white", "\x08 \x08");
                tx.send(1);
                break;
            },
            Err(_) => {
                sleep(Duration::milliseconds(100i64));
                continue;
            }
        }
    }
}

pub fn say(color: &str, to_say: &str) {
    let mut t = term::stdout().unwrap();
    let color_const = match color {
        "green" => term::color::BRIGHT_GREEN,
        "yellow" => term::color::BRIGHT_YELLOW,
        "red" => term::color::BRIGHT_RED,
        "magenta" => term::color::BRIGHT_MAGENTA,
        "white" => term::color::WHITE,
        _ => term::color::WHITE
    };
    t.fg(color_const).unwrap();
    (write!(t, "{}", to_say)).unwrap();
    t.reset().unwrap()
}

pub fn sayln(color: &str, to_say: &str) {
    let mut t = term::stdout().unwrap();
    say(color, to_say);
    (write!(t, "\n")).unwrap();
}

<|endoftext|>


<commit_before>//  Copyright (C) 2016 Sebastian Dröge <sebastian@centricular.com>
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Library General Public License for more details.
//
//  You should have received a copy of the GNU Library General Public
//  License along with this library; if not, write to the
//  Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
//  Boston, MA 02110-1301, USA.

use std::os::raw::c_void;
use std::ptr;
use libc::c_char;
use std::ffi::{CStr, CString};
use caps::Caps;
use tags::TagList;

pub struct Stream(*mut c_void);
pub struct StreamCollection(*mut c_void);

bitflags! {
    #[repr(C)]
    pub flags StreamType: u32 {
        const TYPE_UNKNOWN   = 0b00000001,
        const TYPE_AUDIO     = 0b00000010,
        const TYPE_VIDEO     = 0b00000100,
        const TYPE_CONTAINER = 0b00001000,
        const TYPE_TEXT      = 0b00010000,
    }
}

bitflags! {
    #[repr(C)]
    pub flags StreamFlags: u32 {
        const FLAG_SPARSE   = 0b00000001,
        const FLAG_SELECT   = 0b00000010,
        const FLAG_UNSELECT = 0b00000100,
    }
}

impl Stream {
    pub fn new(stream_id: &str, caps: Option<Caps>, t: StreamType, flags: StreamFlags) -> Self {
        extern "C" {
            fn gst_stream_new(stream_id: *const c_char,
                              caps: *const c_void,
                              t: StreamType,
                              flags: StreamFlags)
                              -> *mut c_void;
        }

        let stream_id_cstr = CString::new(stream_id).unwrap();
        let caps = caps.map(|caps| unsafe { caps.as_ptr() }).unwrap_or(ptr::null_mut());

        Stream(unsafe { gst_stream_new(stream_id_cstr.as_ptr(), caps, t, flags) })
    }

    pub unsafe fn as_ptr(&self) -> *const c_void {
        self.0
    }

    pub fn get_caps(&self) -> Option<Caps> {
        extern "C" {
            fn gst_stream_get_caps(stream: *mut c_void) -> *mut c_void;
        }

        let ptr = unsafe { gst_stream_get_caps(self.0) };

        if ptr.is_null() {
            return None;
        }

        Some(unsafe { Caps::new_from_ptr(ptr) })
    }

    pub fn get_stream_flags(&self) -> StreamFlags {
        extern "C" {
            fn gst_stream_get_stream_flags(stream: *mut c_void) -> u32;
        }

        StreamFlags::from_bits_truncate(unsafe { gst_stream_get_stream_flags(self.0) })
    }

    pub fn get_stream_type(&self) -> StreamType {
        extern "C" {
            fn gst_stream_get_stream_type(stream: *mut c_void) -> u32;
        }

        StreamType::from_bits_truncate(unsafe { gst_stream_get_stream_type(self.0) })
    }

    pub fn get_stream_id(&self) -> String {
        extern "C" {
            fn gst_stream_get_stream_id(collection: *mut c_void) -> *mut c_char;
        }

        unsafe {
            CStr::from_ptr(gst_stream_get_stream_id(self.0))
                .to_str()
                .unwrap()
                .into()
        }
    }

    pub fn get_tags(&self) -> Option<TagList> {
        extern "C" {
            fn gst_stream_get_tags(stream: *mut c_void) -> *mut c_void;
        }

        let ptr = unsafe { gst_stream_get_tags(self.0) };

        if ptr.is_null() {
            return None;
        }

        Some(unsafe { TagList::new_from_ptr(ptr) })
    }

    pub fn set_caps(&self, caps: Option<Caps>) {
        extern "C" {
            fn gst_stream_set_caps(stream: *mut c_void, caps: *mut c_void);
        }

        let ptr = caps.map(|caps| unsafe { caps.as_ptr() }).unwrap_or(ptr::null_mut());

        unsafe { gst_stream_set_caps(self.0, ptr as *mut c_void) }
    }

    pub fn set_stream_flags(&self, flags: StreamFlags) {
        extern "C" {
            fn gst_stream_set_stream_flags(stream: *mut c_void, flags: u32);
        }

        unsafe { gst_stream_set_stream_flags(self.0, flags.bits()) }
    }

    pub fn set_stream_type(&self, t: StreamType) {
        extern "C" {
            fn gst_stream_set_stream_type(stream: *mut c_void, t: u32);
        }

        unsafe { gst_stream_set_stream_type(self.0, t.bits()) }
    }

    pub fn set_tags(&self, tags: Option<TagList>) {
        extern "C" {
            fn gst_stream_set_tags(stream: *mut c_void, tags: *mut c_void);
        }

        let ptr = tags.map(|tags| unsafe { tags.as_ptr() }).unwrap_or(ptr::null_mut());

        unsafe { gst_stream_set_tags(self.0, ptr as *mut c_void) }
    }
}

impl Clone for Stream {
    fn clone(&self) -> Self {
        extern "C" {
            fn gst_object_ref(object: *mut c_void) -> *mut c_void;
        }

        unsafe { Stream(gst_object_ref(self.0)) }
    }
}

impl Drop for Stream {
    fn drop(&mut self) {
        extern "C" {
            fn gst_object_unref(object: *mut c_void);
        }

        unsafe { gst_object_unref(self.0) }
    }
}

impl StreamCollection {
    pub fn new(upstream_id: &str, streams: &[Stream]) -> Self {
        extern "C" {
            fn gst_stream_collection_new(upstream_id: *const c_char) -> *mut c_void;
            fn gst_stream_collection_add_stream(collection: *mut c_void, stream: *mut c_void);
        }

        let upstream_id_cstr = CString::new(upstream_id).unwrap();
        let collection =
            StreamCollection(unsafe { gst_stream_collection_new(upstream_id_cstr.as_ptr()) });

        for stream in streams {
            unsafe { gst_stream_collection_add_stream(collection.0, stream.clone().0) }
        }

        collection
    }

    pub fn streams(&self) -> StreamCollectionIterator {
        StreamCollectionIterator::new(self)
    }

    pub fn len(&self) -> u32 {
        extern "C" {
            fn gst_stream_collection_get_size(collection: *mut c_void) -> u32;
        }

        unsafe { gst_stream_collection_get_size(self.0) }
    }

    pub fn get_upstream_id(&self) -> String {
        extern "C" {
            fn gst_stream_collection_get_upstream_id(collection: *mut c_void) -> *mut c_char;
        }

        unsafe {
            CStr::from_ptr(gst_stream_collection_get_upstream_id(self.0))
                .to_str()
                .unwrap()
                .into()
        }
    }

    pub unsafe fn as_ptr(&self) -> *const c_void {
        self.0
    }
}

pub struct StreamCollectionIterator<'a> {
    position: u32,
    length: u32,
    collection: &'a StreamCollection,
}

impl<'a> StreamCollectionIterator<'a> {
    fn new(collection: &'a StreamCollection) -> Self {
        StreamCollectionIterator {
            position: 0,
            length: collection.len(),
            collection: collection,
        }
    }
}

impl<'a> Iterator for StreamCollectionIterator<'a> {
    type Item = Stream;

    fn next(&mut self) -> Option<Stream> {
        extern "C" {
            fn gst_stream_collection_get_stream(collection: *mut c_void,
                                                index: u32)
                                                -> *mut c_void;
            fn gst_object_ref(object: *mut c_void) -> *mut c_void;
        }

        if self.position == self.length {
            return None;
        }

        let stream = unsafe { gst_stream_collection_get_stream(self.collection.0, self.position) };
        if stream.is_null() {
            self.position = self.length;
            return None;
        }
        self.position += 1;

        Some(unsafe { Stream(gst_object_ref(stream)) })
    }
}

impl Clone for StreamCollection {
    fn clone(&self) -> Self {
        extern "C" {
            fn gst_object_ref(object: *mut c_void) -> *mut c_void;
        }

        unsafe { StreamCollection(gst_object_ref(self.0)) }
    }
}

impl Drop for StreamCollection {
    fn drop(&mut self) {
        extern "C" {
            fn gst_object_unref(object: *mut c_void);
        }

        unsafe { gst_object_unref(self.0) }
    }
}
<commit_msg>Return stream IDs directly instead of creating an owned String<commit_after>//  Copyright (C) 2016 Sebastian Dröge <sebastian@centricular.com>
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Library General Public License for more details.
//
//  You should have received a copy of the GNU Library General Public
//  License along with this library; if not, write to the
//  Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
//  Boston, MA 02110-1301, USA.

use std::os::raw::c_void;
use std::ptr;
use libc::c_char;
use std::ffi::{CStr, CString};
use caps::Caps;
use tags::TagList;

pub struct Stream(*mut c_void);
pub struct StreamCollection(*mut c_void);

bitflags! {
    #[repr(C)]
    pub flags StreamType: u32 {
        const TYPE_UNKNOWN   = 0b00000001,
        const TYPE_AUDIO     = 0b00000010,
        const TYPE_VIDEO     = 0b00000100,
        const TYPE_CONTAINER = 0b00001000,
        const TYPE_TEXT      = 0b00010000,
    }
}

bitflags! {
    #[repr(C)]
    pub flags StreamFlags: u32 {
        const FLAG_SPARSE   = 0b00000001,
        const FLAG_SELECT   = 0b00000010,
        const FLAG_UNSELECT = 0b00000100,
    }
}

impl Stream {
    pub fn new(stream_id: &str, caps: Option<Caps>, t: StreamType, flags: StreamFlags) -> Self {
        extern "C" {
            fn gst_stream_new(stream_id: *const c_char,
                              caps: *const c_void,
                              t: StreamType,
                              flags: StreamFlags)
                              -> *mut c_void;
        }

        let stream_id_cstr = CString::new(stream_id).unwrap();
        let caps = caps.map(|caps| unsafe { caps.as_ptr() }).unwrap_or(ptr::null_mut());

        Stream(unsafe { gst_stream_new(stream_id_cstr.as_ptr(), caps, t, flags) })
    }

    pub unsafe fn as_ptr(&self) -> *const c_void {
        self.0
    }

    pub fn get_caps(&self) -> Option<Caps> {
        extern "C" {
            fn gst_stream_get_caps(stream: *mut c_void) -> *mut c_void;
        }

        let ptr = unsafe { gst_stream_get_caps(self.0) };

        if ptr.is_null() {
            return None;
        }

        Some(unsafe { Caps::new_from_ptr(ptr) })
    }

    pub fn get_stream_flags(&self) -> StreamFlags {
        extern "C" {
            fn gst_stream_get_stream_flags(stream: *mut c_void) -> u32;
        }

        StreamFlags::from_bits_truncate(unsafe { gst_stream_get_stream_flags(self.0) })
    }

    pub fn get_stream_type(&self) -> StreamType {
        extern "C" {
            fn gst_stream_get_stream_type(stream: *mut c_void) -> u32;
        }

        StreamType::from_bits_truncate(unsafe { gst_stream_get_stream_type(self.0) })
    }

    pub fn get_stream_id(&self) -> &str {
        extern "C" {
            fn gst_stream_get_stream_id(collection: *mut c_void) -> *mut c_char;
        }

        unsafe {
            CStr::from_ptr(gst_stream_get_stream_id(self.0))
                .to_str()
                .unwrap()
        }
    }

    pub fn get_tags(&self) -> Option<TagList> {
        extern "C" {
            fn gst_stream_get_tags(stream: *mut c_void) -> *mut c_void;
        }

        let ptr = unsafe { gst_stream_get_tags(self.0) };

        if ptr.is_null() {
            return None;
        }

        Some(unsafe { TagList::new_from_ptr(ptr) })
    }

    pub fn set_caps(&self, caps: Option<Caps>) {
        extern "C" {
            fn gst_stream_set_caps(stream: *mut c_void, caps: *mut c_void);
        }

        let ptr = caps.map(|caps| unsafe { caps.as_ptr() }).unwrap_or(ptr::null_mut());

        unsafe { gst_stream_set_caps(self.0, ptr as *mut c_void) }
    }

    pub fn set_stream_flags(&self, flags: StreamFlags) {
        extern "C" {
            fn gst_stream_set_stream_flags(stream: *mut c_void, flags: u32);
        }

        unsafe { gst_stream_set_stream_flags(self.0, flags.bits()) }
    }

    pub fn set_stream_type(&self, t: StreamType) {
        extern "C" {
            fn gst_stream_set_stream_type(stream: *mut c_void, t: u32);
        }

        unsafe { gst_stream_set_stream_type(self.0, t.bits()) }
    }

    pub fn set_tags(&self, tags: Option<TagList>) {
        extern "C" {
            fn gst_stream_set_tags(stream: *mut c_void, tags: *mut c_void);
        }

        let ptr = tags.map(|tags| unsafe { tags.as_ptr() }).unwrap_or(ptr::null_mut());

        unsafe { gst_stream_set_tags(self.0, ptr as *mut c_void) }
    }
}

impl Clone for Stream {
    fn clone(&self) -> Self {
        extern "C" {
            fn gst_object_ref(object: *mut c_void) -> *mut c_void;
        }

        unsafe { Stream(gst_object_ref(self.0)) }
    }
}

impl Drop for Stream {
    fn drop(&mut self) {
        extern "C" {
            fn gst_object_unref(object: *mut c_void);
        }

        unsafe { gst_object_unref(self.0) }
    }
}

impl StreamCollection {
    pub fn new(upstream_id: &str, streams: &[Stream]) -> Self {
        extern "C" {
            fn gst_stream_collection_new(upstream_id: *const c_char) -> *mut c_void;
            fn gst_stream_collection_add_stream(collection: *mut c_void, stream: *mut c_void);
        }

        let upstream_id_cstr = CString::new(upstream_id).unwrap();
        let collection =
            StreamCollection(unsafe { gst_stream_collection_new(upstream_id_cstr.as_ptr()) });

        for stream in streams {
            unsafe { gst_stream_collection_add_stream(collection.0, stream.clone().0) }
        }

        collection
    }

    pub fn streams(&self) -> StreamCollectionIterator {
        StreamCollectionIterator::new(self)
    }

    pub fn len(&self) -> u32 {
        extern "C" {
            fn gst_stream_collection_get_size(collection: *mut c_void) -> u32;
        }

        unsafe { gst_stream_collection_get_size(self.0) }
    }

    pub fn get_upstream_id(&self) -> &str {
        extern "C" {
            fn gst_stream_collection_get_upstream_id(collection: *mut c_void) -> *mut c_char;
        }

        unsafe {
            CStr::from_ptr(gst_stream_collection_get_upstream_id(self.0))
                .to_str()
                .unwrap()
        }
    }

    pub unsafe fn as_ptr(&self) -> *const c_void {
        self.0
    }
}

pub struct StreamCollectionIterator<'a> {
    position: u32,
    length: u32,
    collection: &'a StreamCollection,
}

impl<'a> StreamCollectionIterator<'a> {
    fn new(collection: &'a StreamCollection) -> Self {
        StreamCollectionIterator {
            position: 0,
            length: collection.len(),
            collection: collection,
        }
    }
}

impl<'a> Iterator for StreamCollectionIterator<'a> {
    type Item = Stream;

    fn next(&mut self) -> Option<Stream> {
        extern "C" {
            fn gst_stream_collection_get_stream(collection: *mut c_void,
                                                index: u32)
                                                -> *mut c_void;
            fn gst_object_ref(object: *mut c_void) -> *mut c_void;
        }

        if self.position == self.length {
            return None;
        }

        let stream = unsafe { gst_stream_collection_get_stream(self.collection.0, self.position) };
        if stream.is_null() {
            self.position = self.length;
            return None;
        }
        self.position += 1;

        Some(unsafe { Stream(gst_object_ref(stream)) })
    }
}

impl Clone for StreamCollection {
    fn clone(&self) -> Self {
        extern "C" {
            fn gst_object_ref(object: *mut c_void) -> *mut c_void;
        }

        unsafe { StreamCollection(gst_object_ref(self.0)) }
    }
}

impl Drop for StreamCollection {
    fn drop(&mut self) {
        extern "C" {
            fn gst_object_unref(object: *mut c_void);
        }

        unsafe { gst_object_unref(self.0) }
    }
}
<|endoftext|>


<commit_before>use iron::prelude::*;
use iron::Handler;
use iron::response::modifiers::{Status, Body};
use iron::status;

// Re-export Logger and Router so you can use redstart::Router instead of redstart::router::Router.
pub use self::logger::Logger;
pub use self::urlparser::URLParser;
pub use self::permission::PermCheck;

mod logger;
mod urlparser;
mod permission;
// End Re-export

pub struct RedStart;

pub enum Controller
{
    Reservation,
    Administration,
    User,
}

impl Handler for RedStart
{
    fn call(&self, _: &mut Request) -> IronResult<Response>
    {
        Ok(Response::new().set(Status(status::Ok)).set(Body("Hello world!\n")))
    }

    fn catch(&self, _: &mut Request, err: IronError) -> (Response, IronResult<()>)
    {
        // Its definetely *not* pretty. But it works.
        match err.name()
        {
            "NotLoggedIn" => { (Response::new().set(Status(status::Unauthorized)), Ok(())) },
            "InsufficientPermissions" => { (Response::new().set(Status(status::Forbidden)), Ok(())) },
            "NoRoute" => { (Response::new().set(Status(status::NotFound)), Ok(())) },
            "MalformedRequest" => { (Response::new().set(Status(status::BadRequest)), Ok(())) },
            _ => { (Response::new().set(Status(status::InternalServerError)), Ok(())) },
        }
    }
}
<commit_msg>End of segment commit. Nothing is working as far as I can tell. :P<commit_after>use iron::prelude::*;
use iron::Handler;
use iron::response::modifiers::{Status, Body};
use iron::status;

use self::

// Re-export Logger and Router so you can use redstart::Router instead of redstart::router::Router.
pub use self::logger::Logger;
pub use self::urlparser::URLParser;
pub use self::permission::PermCheck;

mod logger;
mod urlparser;
mod permission;
// End Re-export

pub struct RedStart;

pub enum Controller
{
    Reservation,
    Administration,
    User,
}

impl Handler for RedStart
{
    fn call(&self, _: &mut Request) -> IronResult<Response>
    {
        // Define some arbitrary variables. ToDo: These should be set by URLParser later on
        let controller = Controller::Reservation;

        match controller
        {
            User => {},
            Reservation => {},
            Administration => {},
        }

        Ok(Response::new().set(Status(status::Ok)).set(Body("Hello world!\n")))
    }

    fn catch(&self, _: &mut Request, err: IronError) -> (Response, IronResult<()>)
    {
        // Its definetely *not* pretty. But it works.
        match err.name()
        {
            "NotLoggedIn" => { (Response::new().set(Status(status::Unauthorized)), Ok(())) },
            "InsufficientPermissions" => { (Response::new().set(Status(status::Forbidden)), Ok(())) },
            "NoRoute" => { (Response::new().set(Status(status::NotFound)), Ok(())) },
            "MalformedRequest" => { (Response::new().set(Status(status::BadRequest)), Ok(())) },
            _ => { (Response::new().set(Status(status::InternalServerError)), Ok(())) },
        }
    }
}
<|endoftext|>


<commit_before>//! An augmentation of the rust-http Response struct.

use std::io::{IoResult, File};
use std::io::util::copy;

use http::status::Status;

pub use Response = http::server::response::ResponseWriter;

use self::mimes::get_content_type;

mod mimes;

/// Allow file-serving
pub trait ServeFile: Writer {
    /// Serve the file located at `path`.
    ///
    /// This is usually a terminal process, and `Middleware` may want to
    /// call `Unwind` after a file is served. If the status should be
    /// anything other than `200`, the `Middleware` must set it, including in
    /// the case of an `Err`.
    ///
    /// `serve_file` will err out if the file does not exist, the process
    /// does not have correct permissions, or it has other issues in reading
    /// from the file. Middleware should handle this gracefully.
    fn serve_file(&mut self, &Path) -> IoResult<()>;
}

impl<'a> ServeFile for Response<'a> {
    fn serve_file(&mut self, path: &Path) -> IoResult<()> {
        let mut file = try!(File::open(path));
        self.headers.content_type = get_content_type(path);
        copy(&mut file, self)
    }
}

/// Send data with a statuscode quickly.
pub trait SendData {
    /// Write the statuscode and data to the response.
    ///
    /// send will forward write errors to the request to its
    /// caller.
    fn send(&mut self, status: Status, body: &str) -> IoResult<()>;
}

impl<'a> SendData for Response<'a> {
    fn send(&mut self, status: Status, body: &str) -> IoResult<()> {
        self.status = status;
        Ok(try!(self.write(body.as_bytes())))
    }
}

<commit_msg>(refactor) Refactored to use a single mixin trait.<commit_after>//! An augmentation of the rust-http Response struct.

use std::io::{IoResult, File};
use std::io::util::copy;

use http::status::Status;

pub use Response = http::server::response::ResponseWriter;

use self::mimes::get_content_type;

mod mimes;

/// Adds common serving methods to Response.
pub trait Serve: Writer {
    /// Serve the file located at `path`.
    ///
    /// This is usually a terminal process, and `Middleware` may want to
    /// call `Unwind` after a file is served. If the status should be
    /// anything other than `200`, the `Middleware` must set it, including in
    /// the case of an `Err`.
    ///
    /// `serve_file` will err out if the file does not exist, the process
    /// does not have correct permissions, or it has other issues in reading
    /// from the file. Middleware should handle this gracefully.
    fn serve_file(&mut self, &Path) -> IoResult<()>;

    /// Write the `Status` and data to the `Response`.
    ///
    /// `serve` will forward write errors to its caller.
    fn serve(&mut self, status: Status, body: &str) -> IoResult<()>;
}

impl<'a> Serve for Response<'a> {
    fn serve_file(&mut self, path: &Path) -> IoResult<()> {
        let mut file = try!(File::open(path));
        self.headers.content_type = get_content_type(path);
        copy(&mut file, self)
    }

    fn serve(&mut self, status: Status, body: &str) -> IoResult<()> {
        self.status = status;
        Ok(try!(self.write(body.as_bytes())))
    }
}

<|endoftext|>


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

use std::io::BufRead;

use error::{Error, Result};

pub struct Plan {
    pub name: String,
    pub version: String,
}

impl Plan {
    pub fn new(name: String, version: String) -> Self {
        Plan {
            name: name,
            version: version,
        }
    }

    pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
        let mut name: Option<String> = None;
        let mut version: Option<String> = None;
        for line in bytes.lines() {
            if let Ok(line) = line {
                let parts: Vec<&str> = line.splitn(2, "=").collect();
                match parts[0] {
                    "pkg_name" => name = Some(parts[1].to_string()),
                    "pkg_version" => version = Some(parts[1].to_string()),
                    _ => (),
                }
            }
        }

        // Only the name is required to be present initiallly in the plan.sh
        if name.is_none() {
            return Err(Error::PlanMalformed);
        }

        // Default the version to 'undefined' if it's not present
        let v = if version.is_none() {
            String::from("undefined")
        } else {
            version.unwrap()
        };

        let plan = Plan::new(name.unwrap(), v);
        Ok(plan)
    }
}
<commit_msg>Process GitHub Push Hook notifications<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::BufRead;

use error::{Error, Result};

#[derive(Debug)]
pub struct Plan {
    pub name: String,
    pub origin: String,
    pub version: String,
}

impl Plan {
    pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
        let mut name: Option<String> = None;
        let mut origin: Option<String> = None;
        let mut version: Option<String> = None;
        for line in bytes.lines() {
            if let Ok(line) = line {
                let parts: Vec<&str> = line.splitn(2, "=").collect();
                match parts[0] {
                    "pkg_name" => name = Some(parts[1].to_string()),
                    "pkg_origin" => origin = Some(parts[1].to_string()),
                    "pkg_version" => version = Some(parts[1].to_string()),
                    _ => (),
                }
            }
        }

        if name.is_none() || origin.is_none() {
            return Err(Error::PlanMalformed);
        }

        // Default the version to 'undefined' if it's not present
        let version = version.unwrap_or("undefined".to_string());
        Ok(Plan {
            name: name.unwrap(),
            origin: origin.unwrap(),
            version: version,
        })
    }
}
<|endoftext|>


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

use super::lexer::{Lexer, LexError};
use super::token::{TokenSpan, Token, Lit};
use super::exec::*; // TODO: remove * import

pub struct Parser<'a> {
    lexer: Lexer<'a>,

    curr: Option<TokenSpan>,
    last: Option<TokenSpan>,
    peek: Option<TokenSpan>,
}

impl<'a> Parser<'a> {
    pub fn from_query(q: &'a str) -> Parser<'a> {
        let lex = Lexer::from_query(q);
        let mut p = Parser {
            lexer: lex,
            curr: None,
            last: None,
            peek: None,
        };

        // TODO: fix this
        p.bump().unwrap();
        p.bump().unwrap();
        p
    }

    pub fn parse(&mut self) -> Result<(), ParserError> {
        try!(self.parse_commands());
        Ok(())
    }

    fn bump(&mut self) -> Result<(), ParserError> {
        // do stuff. Mainly swap last = curr, curr = peek, then peek = next_real
        mem::swap(&mut self.last, &mut self.curr);
        mem::swap(&mut self.curr, &mut self.peek);
        self.peek = try!(self.lexer.next_real());
        Ok(())
    }

    // SQL Commands

    fn parse_commands(&mut self) -> Result<(), ParserError> {
        let curr = self.curr.clone();

        // Parse first word that
        match curr.unwrap().token {
            Token::Word(val) => self.run_major_command(val),
            _ => return Err(ParserError::FirstCmdNotWord),
        }

        Ok(())
    }

    fn run_major_command(&mut self, cmd: String) {
        match Keyword::from_str(&*cmd) {
            Keyword::Select => self.parse_select(),
            Keyword::Insert => self.parse_insert(),
            _ => panic!("not select"),
        };
    }

    fn parse_select(&mut self) -> Query {
        // TODO: impl parse_select

        Query::Table(TableStmt::Select(SelectStmt {
            cols: vec![Col { name: "id".to_owned() }],
            table: Table {
                name: "user_v1".to_owned(),
                alias: None,
            },
        }))
    }

    fn parse_insert(&mut self) -> Query {
        // TODO: impl parse_insert

        Query::Table(TableStmt::Insert(InsertStmt {
            table: Table {
                name: "user_v1".to_owned(),
                alias: None,
            },
            cols: HashMap::new(),
        }))
    }
}

#[derive(Debug)]
pub enum Keyword {
    // Major
    Select,
    Insert,

    // Minor
    From,
}

impl Keyword {
    pub fn from_str(k: &str) -> Keyword {
        match &*k.to_lowercase() {
            "select" => Keyword::Select,
            "insert" => Keyword::Insert,
            "from" => Keyword::From,
            keyword => panic!("unexpected keyword {}", keyword),
        }

    }
}

#[derive(Debug)]
pub enum ParserError {
    InvalidCommand,
    LexerError(LexError),
    FirstCmdNotWord,
}

impl From<LexError> for ParserError {
    fn from(e: LexError) -> ParserError {
        ParserError::LexerError(e)
    }
}
<commit_msg>cleaned up error handling in parser<commit_after>use std::mem;
use std::collections::HashMap;

use super::lexer::{Lexer, LexError};
use super::token::{TokenSpan, Token, Lit};
use super::exec::*; // TODO: remove * import

pub struct Parser<'a> {
    lexer: Lexer<'a>,

    curr: Option<TokenSpan>,
    last: Option<TokenSpan>,
    peek: Option<TokenSpan>,
}

impl<'a> Parser<'a> {
    pub fn from_query(q: &'a str) -> Parser<'a> {
        let lex = Lexer::from_query(q);
        let mut p = Parser {
            lexer: lex,
            curr: None,
            last: None,
            peek: None,
        };

        // TODO: fix this
        p.bump().unwrap();
        p.bump().unwrap();
        p
    }

    pub fn parse(&mut self) -> Result<(), ParserError> {
        try!(self.parse_commands());
        Ok(())
    }

    fn bump(&mut self) -> Result<(), ParserError> {
        // do stuff. Mainly swap last = curr, curr = peek, then peek = next_real
        mem::swap(&mut self.last, &mut self.curr);
        mem::swap(&mut self.curr, &mut self.peek);
        self.peek = try!(self.lexer.next_real());
        Ok(())
    }

    // SQL Commands

    fn parse_commands(&mut self) -> Result<(), ParserError> {
        let curr = self.curr.clone();

        // Parse first word that
        match curr.unwrap().token {
            Token::Word(val) => try!(self.run_major_command(val)),
            _ => return Err(ParserError::FirstCmdNotWord),
        }

        Ok(())
    }

    fn run_major_command(&mut self, cmd: String) -> Result<(), ParserError> {
        match Keyword::from_str(&*cmd) {
            Keyword::Select => self.parse_select(),
            Keyword::Insert => self.parse_insert(),

            _ => return Err(ParserError::FirstCmdNotMajor),
        };

        Ok(())
    }

    fn parse_select(&mut self) -> Query {
        // TODO: impl parse_select

        Query::Table(TableStmt::Select(SelectStmt {
            cols: vec![Col { name: "id".to_owned() }],
            table: Table {
                name: "user_v1".to_owned(),
                alias: None,
            },
        }))
    }

    fn parse_insert(&mut self) -> Query {
        // TODO: impl parse_insert

        Query::Table(TableStmt::Insert(InsertStmt {
            table: Table {
                name: "user_v1".to_owned(),
                alias: None,
            },
            cols: HashMap::new(),
        }))
    }
}

#[derive(Debug)]
pub enum Keyword {
    // Major
    Select,
    Insert,

    // Minor
    From,
}

impl Keyword {
    pub fn from_str(k: &str) -> Keyword {
        match &*k.to_lowercase() {
            "select" => Keyword::Select,
            "insert" => Keyword::Insert,
            "from" => Keyword::From,
            keyword => panic!("unexpected keyword {}", keyword),
        }

    }
}

#[derive(Debug)]
pub enum ParserError {
    InvalidCommand,
    LexerError(LexError),
    FirstCmdNotWord,
    FirstCmdNotMajor,
}

impl From<LexError> for ParserError {
    fn from(e: LexError) -> ParserError {
        ParserError::LexerError(e)
    }
}
<|endoftext|>


<commit_before>extern crate rand;

//use std::process::Command;
use chip8::Chip8;

pub struct Interpreter;

impl Interpreter {
	pub fn execute_next_instruction(chip8: &mut Chip8) {
		// debug
		/*println!("PC= {:x}", chip8.register_pc);
		println!("I= {:x}", chip8.register_i);
		println!("DT= {:x}", chip8.register_dt);
		println!("ST= {:x}", chip8.register_st);
		println!("SP= {:x}", chip8.register_sp);

		for i in 0..16 as usize {
			println!("V{}= {:x}", i, chip8.register_v[i]);
		}

		let _ = Command::new("cmd.exe").arg("/c").arg("pause").status();*/

		// fetch
		let high_byte = chip8.memory[chip8.register_pc as usize];
		let low_byte = chip8.memory[chip8.register_pc as usize + 1];
		let opcode = (high_byte >> 4, high_byte & 0x0F, low_byte >> 4, low_byte & 0x0F);
		chip8.register_pc += 2;

		// decode & execute
		let nnn = ((high_byte as u16 & 0x0F) << 8) | low_byte as u16;
		let x = high_byte as usize & 0x0F;
		let y = low_byte as usize >> 4;

		match opcode {
			(0x0, 0x0, 0xE, 0x0) => chip8.display.clear(),
			(0x0, 0x0, 0xE, 0xE) => {
				chip8.register_pc = chip8.stack[chip8.register_sp as usize];
				chip8.register_sp -= 1;
			},
			(0x1, ..) => chip8.register_pc = nnn,
			(0x2, ..) => {
				chip8.register_sp += 1;
				chip8.stack[chip8.register_sp as usize] = chip8.register_pc;
				chip8.register_pc = nnn;
			},
			(0x3, ..) => {
				if chip8.register_v[x] == low_byte {
					chip8.register_pc += 2;
				}
			},
			(0x4, ..) => {
				if chip8.register_v[x] != low_byte {
					chip8.register_pc += 2;
				}
			},
			(0x5, _, _, 0x0) => {
				if chip8.register_v[x] == chip8.register_v[y] {
					chip8.register_pc += 2;
				}
			},
			(0x6, ..) => chip8.register_v[x] = low_byte,
			(0x7, ..) => chip8.register_v[x] = chip8.register_v[x].wrapping_add(low_byte),
			(0x8, _, _, 0x0) => chip8.register_v[x] = chip8.register_v[y],
			(0x8, _, _, 0x1) => chip8.register_v[x] |= chip8.register_v[y],
			(0x8, _, _, 0x2) => chip8.register_v[x] &= chip8.register_v[y],
			(0x8, _, _, 0x3) => chip8.register_v[x] ^= chip8.register_v[y],
			(0x8, _, _, 0x4) => {
				let result = chip8.register_v[x] as u16 + chip8.register_v[y] as u16;
				chip8.register_v[x] = result as u8;
				chip8.register_v[0xF] = (result > 0xFF) as u8;
			},
			(0x8, _, _, 0x5) => {
				chip8.register_v[0xF] = (chip8.register_v[x] >= chip8.register_v[y]) as u8;
				chip8.register_v[x] = chip8.register_v[x].wrapping_sub(chip8.register_v[y]);
			},
			(0x8, _, _, 0x6) => {
				chip8.register_v[0xF] = chip8.register_v[x] & 1;
				chip8.register_v[x] >>= 1;
			},
			(0x8, _, _, 0x7) => {
				chip8.register_v[0xF] = (chip8.register_v[x] <= chip8.register_v[y]) as u8;
				chip8.register_v[x] = chip8.register_v[y].wrapping_sub(chip8.register_v[x]);
			},
			(0x8, _, _, 0xE) => {
				chip8.register_v[0xF] = chip8.register_v[x] >> 7;
				chip8.register_v[x] <<= 1;
			},
			(0x9, _, _, 0x0) => {
				if chip8.register_v[x] != chip8.register_v[y] {
					chip8.register_pc += 2;
				}
			},
			(0xA, ..) => chip8.register_i = nnn,
			(0xB, ..) => chip8.register_pc = nnn + chip8.register_v[0] as u16,
			(0xC, ..) => chip8.register_v[x] = rand::random::<u8>() & low_byte,
			(0xD, _, _, n) => {
				let sprite = &chip8.memory[chip8.register_i as usize .. chip8.register_i as usize + n as usize];
				chip8.register_v[0xF] = chip8.display.draw_sprite(chip8.register_v[x], chip8.register_v[y], sprite) as u8;
			},
			(0xE, _, 0x9, 0xE) => {
				if chip8.keyboard.is_pressed(chip8.register_v[x]) {
					chip8.register_pc += 2;
				}
			},
			(0xE, _, 0xA, 0x1) => {
				if !chip8.keyboard.is_pressed(chip8.register_v[x]) {
					chip8.register_pc += 2;
				}
			},
			(0xF, _, 0x0, 0x7) => chip8.register_v[x] = chip8.register_dt,
			(0xF, _, 0x0, 0xA) => chip8.register_v[x] = chip8.keyboard.wait_key_press(),
			(0xF, _, 0x1, 0x5) => chip8.register_dt = chip8.register_v[x],
			(0xF, _, 0x1, 0x8) => chip8.register_st = chip8.register_v[x],
			(0xF, _, 0x1, 0xE) => chip8.register_i += chip8.register_v[x] as u16,
			(0xF, _, 0x2, 0x9) => chip8.register_i = chip8.register_v[x] as u16 * 5,
			(0xF, _, 0x3, 0x3) => {
				chip8.memory[chip8.register_i as usize] = chip8.register_v[x] / 100;
				chip8.memory[chip8.register_i as usize + 1] = (chip8.register_v[x] % 100) / 10;
				chip8.memory[chip8.register_i as usize + 2] = chip8.register_v[x] % 10;
			},
			(0xF, _, 0x5, 0x5) => {
				for i in 0..(x + 1) {
					chip8.memory[chip8.register_i as usize + i] = chip8.register_v[i];
				}
			},
			(0xF, _, 0x6, 0x5) => {
				for i in 0..(x + 1) {
					chip8.register_v[i] = chip8.memory[chip8.register_i as usize + i];
				}
			},
			_ => panic!("unknown opcode")
		}
	}
}
<commit_msg>Interpreter: fix 8XY6 and 8XYE<commit_after>extern crate rand;

//use std::process::Command;
use chip8::Chip8;

pub struct Interpreter;

impl Interpreter {
	pub fn execute_next_instruction(chip8: &mut Chip8) {
		// debug
		/*println!("PC= {:x}", chip8.register_pc);
		println!("I= {:x}", chip8.register_i);
		println!("DT= {:x}", chip8.register_dt);
		println!("ST= {:x}", chip8.register_st);
		println!("SP= {:x}", chip8.register_sp);

		for i in 0..16 as usize {
			println!("V{}= {:x}", i, chip8.register_v[i]);
		}

		let _ = Command::new("cmd.exe").arg("/c").arg("pause").status();*/

		// fetch
		let high_byte = chip8.memory[chip8.register_pc as usize];
		let low_byte = chip8.memory[chip8.register_pc as usize + 1];
		let opcode = (high_byte >> 4, high_byte & 0x0F, low_byte >> 4, low_byte & 0x0F);
		chip8.register_pc += 2;

		// decode & execute
		let nnn = ((high_byte as u16 & 0x0F) << 8) | low_byte as u16;
		let x = high_byte as usize & 0x0F;
		let y = low_byte as usize >> 4;

		match opcode {
			(0x0, 0x0, 0xE, 0x0) => chip8.display.clear(),
			(0x0, 0x0, 0xE, 0xE) => {
				chip8.register_pc = chip8.stack[chip8.register_sp as usize];
				chip8.register_sp -= 1;
			},
			(0x1, ..) => chip8.register_pc = nnn,
			(0x2, ..) => {
				chip8.register_sp += 1;
				chip8.stack[chip8.register_sp as usize] = chip8.register_pc;
				chip8.register_pc = nnn;
			},
			(0x3, ..) => {
				if chip8.register_v[x] == low_byte {
					chip8.register_pc += 2;
				}
			},
			(0x4, ..) => {
				if chip8.register_v[x] != low_byte {
					chip8.register_pc += 2;
				}
			},
			(0x5, _, _, 0x0) => {
				if chip8.register_v[x] == chip8.register_v[y] {
					chip8.register_pc += 2;
				}
			},
			(0x6, ..) => chip8.register_v[x] = low_byte,
			(0x7, ..) => chip8.register_v[x] = chip8.register_v[x].wrapping_add(low_byte),
			(0x8, _, _, 0x0) => chip8.register_v[x] = chip8.register_v[y],
			(0x8, _, _, 0x1) => chip8.register_v[x] |= chip8.register_v[y],
			(0x8, _, _, 0x2) => chip8.register_v[x] &= chip8.register_v[y],
			(0x8, _, _, 0x3) => chip8.register_v[x] ^= chip8.register_v[y],
			(0x8, _, _, 0x4) => {
				let result = chip8.register_v[x] as u16 + chip8.register_v[y] as u16;
				chip8.register_v[x] = result as u8;
				chip8.register_v[0xF] = (result > 0xFF) as u8;
			},
			(0x8, _, _, 0x5) => {
				chip8.register_v[0xF] = (chip8.register_v[x] >= chip8.register_v[y]) as u8;
				chip8.register_v[x] = chip8.register_v[x].wrapping_sub(chip8.register_v[y]);
			},
			(0x8, _, _, 0x6) => {
				chip8.register_v[0xF] = chip8.register_v[y] & 1;
				chip8.register_v[x] = chip8.register_v[y] >> 1;
			},
			(0x8, _, _, 0x7) => {
				chip8.register_v[0xF] = (chip8.register_v[x] <= chip8.register_v[y]) as u8;
				chip8.register_v[x] = chip8.register_v[y].wrapping_sub(chip8.register_v[x]);
			},
			(0x8, _, _, 0xE) => {
				chip8.register_v[0xF] = chip8.register_v[y] >> 7;
				chip8.register_v[x] = chip8.register_v[y] << 1;
			},
			(0x9, _, _, 0x0) => {
				if chip8.register_v[x] != chip8.register_v[y] {
					chip8.register_pc += 2;
				}
			},
			(0xA, ..) => chip8.register_i = nnn,
			(0xB, ..) => chip8.register_pc = nnn + chip8.register_v[0] as u16,
			(0xC, ..) => chip8.register_v[x] = rand::random::<u8>() & low_byte,
			(0xD, _, _, n) => {
				let sprite = &chip8.memory[chip8.register_i as usize .. chip8.register_i as usize + n as usize];
				chip8.register_v[0xF] = chip8.display.draw_sprite(chip8.register_v[x], chip8.register_v[y], sprite) as u8;
			},
			(0xE, _, 0x9, 0xE) => {
				if chip8.keyboard.is_pressed(chip8.register_v[x]) {
					chip8.register_pc += 2;
				}
			},
			(0xE, _, 0xA, 0x1) => {
				if !chip8.keyboard.is_pressed(chip8.register_v[x]) {
					chip8.register_pc += 2;
				}
			},
			(0xF, _, 0x0, 0x7) => chip8.register_v[x] = chip8.register_dt,
			(0xF, _, 0x0, 0xA) => chip8.register_v[x] = chip8.keyboard.wait_key_press(),
			(0xF, _, 0x1, 0x5) => chip8.register_dt = chip8.register_v[x],
			(0xF, _, 0x1, 0x8) => chip8.register_st = chip8.register_v[x],
			(0xF, _, 0x1, 0xE) => chip8.register_i += chip8.register_v[x] as u16,
			(0xF, _, 0x2, 0x9) => chip8.register_i = chip8.register_v[x] as u16 * 5,
			(0xF, _, 0x3, 0x3) => {
				chip8.memory[chip8.register_i as usize] = chip8.register_v[x] / 100;
				chip8.memory[chip8.register_i as usize + 1] = (chip8.register_v[x] % 100) / 10;
				chip8.memory[chip8.register_i as usize + 2] = chip8.register_v[x] % 10;
			},
			(0xF, _, 0x5, 0x5) => {
				for i in 0..(x + 1) {
					chip8.memory[chip8.register_i as usize + i] = chip8.register_v[i];
				}
			},
			(0xF, _, 0x6, 0x5) => {
				for i in 0..(x + 1) {
					chip8.register_v[i] = chip8.memory[chip8.register_i as usize + i];
				}
			},
			_ => panic!("unknown opcode")
		}
	}
}
<|endoftext|>