<commit_before>use std::fs;

use test_utils::{assert_eq_text, project_dir, read_text};

use crate::{mock_analysis::single_file, FileRange, TextRange};

#[test]
fn test_highlighting() {
    check_highlighting(
        r#"
#[derive(Clone, Debug)]
struct Foo {
    pub x: i32,
    pub y: i32,
}

trait Bar {
    fn bar(&self) -> i32;
}

impl Bar for Foo {
    fn bar(&self) -> i32 {
        self.x
    }
}

static mut STATIC_MUT: i32 = 0;

fn foo<'a, T>() -> T {
    foo::<'a, i32>()
}

macro_rules! def_fn {
    ($($tt:tt)*) => {$($tt)*}
}

def_fn! {
    fn bar() -> u32 {
        100
    }
}

macro_rules! noop {
    ($expr:expr) => {
        $expr
    }
}

// comment
fn main() {
    println!("Hello, {}!", 92);

    let mut vec = Vec::new();
    if true {
        let x = 92;
        vec.push(Foo { x, y: 1 });
    }
    unsafe {
        vec.set_len(0);
        STATIC_MUT = 1;
    }

    for e in vec {
        // Do nothing
    }

    noop!(noop!(1));

    let mut x = 42;
    let y = &mut x;
    let z = &y;

    let Foo { x: z, y } = Foo { x: z, y };

    y;
}

enum Option<T> {
    Some(T),
    None,
}
use Option::*;

impl<T> Option<T> {
    fn and<U>(self, other: Option<U>) -> Option<(T, U)> {
        match other {
            None => unimplemented!(),
            Nope => Nope,
        }
    }
}
"#
        .trim(),
        "crates/ra_ide/src/snapshots/highlighting.html",
        false,
    );
}

#[test]
fn test_rainbow_highlighting() {
    check_highlighting(
        r#"
fn main() {
    let hello = "hello";
    let x = hello.to_string();
    let y = hello.to_string();

    let x = "other color please!";
    let y = x.to_string();
}

fn bar() {
    let mut hello = "hello";
}
"#
        .trim(),
        "crates/ra_ide/src/snapshots/rainbow_highlighting.html",
        true,
    );
}

#[test]
fn accidentally_quadratic() {
    let file = project_dir().join("crates/ra_syntax/test_data/accidentally_quadratic");
    let src = fs::read_to_string(file).unwrap();

    let (analysis, file_id) = single_file(&src);

    // let t = std::time::Instant::now();
    let _ = analysis.highlight(file_id).unwrap();
    // eprintln!("elapsed: {:?}", t.elapsed());
}

#[test]
fn test_ranges() {
    let (analysis, file_id) = single_file(
        r#"
#[derive(Clone, Debug)]
struct Foo {
    pub x: i32,
    pub y: i32,
}
"#,
    );

    // The "x"
    let highlights = &analysis
        .highlight_range(FileRange { file_id, range: TextRange::at(45.into(), 1.into()) })
        .unwrap();

    assert_eq!(&highlights[0].highlight.to_string(), "field.declaration");
}

#[test]
fn test_flattening() {
    check_highlighting(
        r##"
fn fixture(ra_fixture: &str) {}

fn main() {
    fixture(r#"
        trait Foo {
            fn foo() {
                println!("2 + 2 = {}", 4);
            }
        }"#
    );
}"##
        .trim(),
        "crates/ra_ide/src/snapshots/highlight_injection.html",
        false,
    );
}

#[test]
fn ranges_sorted() {
    let (analysis, file_id) = single_file(
        r#"
#[foo(bar = "bar")]
macro_rules! test {}
}"#
        .trim(),
    );
    let _ = analysis.highlight(file_id).unwrap();
}

#[test]
fn test_string_highlighting() {
    // The format string detection is based on macro-expansion,
    // thus, we have to copy the macro definition from `std`
    check_highlighting(
        r#"
macro_rules! println {
    ($($arg:tt)*) => ({
        $crate::io::_print($crate::format_args_nl!($($arg)*));
    })
}
#[rustc_builtin_macro]
macro_rules! format_args_nl {
    ($fmt:expr) => {{ /* compiler built-in */ }};
    ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
}

fn main() {
    // from https://doc.rust-lang.org/std/fmt/index.html
    println!("Hello");                 // => "Hello"
    println!("Hello, {}!", "world");   // => "Hello, world!"
    println!("The number is {}", 1);   // => "The number is 1"
    println!("{:?}", (3, 4));          // => "(3, 4)"
    println!("{value}", value=4);      // => "4"
    println!("{} {}", 1, 2);           // => "1 2"
    println!("{:04}", 42);             // => "0042" with leading zerosV
    println!("{1} {} {0} {}", 1, 2);   // => "2 1 1 2"
    println!("{argument}", argument = "test");   // => "test"
    println!("{name} {}", 1, name = 2);          // => "2 1"
    println!("{a} {c} {b}", a="a", b='b', c=3);  // => "a 3 b"
    println!("{{{}}}", 2);                       // => "{2}"
    println!("Hello {:5}!", "x");
    println!("Hello {:1$}!", "x", 5);
    println!("Hello {1:0$}!", 5, "x");
    println!("Hello {:width$}!", "x", width = 5);
    println!("Hello {:<5}!", "x");
    println!("Hello {:-<5}!", "x");
    println!("Hello {:^5}!", "x");
    println!("Hello {:>5}!", "x");
    println!("Hello {:+}!", 5);
    println!("{:#x}!", 27);
    println!("Hello {:05}!", 5);
    println!("Hello {:05}!", -5);
    println!("{:#010x}!", 27);
    println!("Hello {0} is {1:.5}", "x", 0.01);
    println!("Hello {1} is {2:.0$}", 5, "x", 0.01);
    println!("Hello {0} is {2:.1$}", "x", 5, 0.01);
    println!("Hello {} is {:.*}",    "x", 5, 0.01);
    println!("Hello {} is {2:.*}",   "x", 5, 0.01);
    println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01);
    println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56);
    println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56");
    println!("{}, `{name:>8.*}` has 3 right-aligned characters", "Hello", 3, name="1234.56");
    println!("Hello {{}}");
    println!("{{ Hello");

    println!(r"Hello, {}!", "world");

    // escape sequences
    println!("Hello\nWorld");
    println!("\u{48}\x65\x6C\x6C\x6F World");

    println!("{\x41}", A = 92);
    println!("{ничоси}", ничоси = 92);
}"#
        .trim(),
        "crates/ra_ide/src/snapshots/highlight_strings.html",
        false,
    );
}

#[test]
fn test_unsafe_highlighting() {
    check_highlighting(
        r#"
unsafe fn unsafe_fn() {}

struct HasUnsafeFn;

impl HasUnsafeFn {
    unsafe fn unsafe_method(&self) {}
}

fn main() {
    let x = &5 as *const usize;
    unsafe {
        unsafe_fn();
        HasUnsafeFn.unsafe_method();
        let y = *(x);
        let z = -x;
    }
}
"#
        .trim(),
        "crates/ra_ide/src/snapshots/highlight_unsafe.html",
        false,
    );
}

#[test]
fn test_highlight_doctest() {
    check_highlighting(
        r#"
/// ```
/// let _ = "early doctests should not go boom";
/// ```
struct Foo {
    bar: bool,
}

impl Foo {
    pub const bar: bool = true;

    /// Constructs a new `Foo`.
    ///
    /// # Examples
    ///
    /// ```
    /// # #![allow(unused_mut)]
    /// let mut foo: Foo = Foo::new();
    /// ```
    pub const fn new() -> Foo {
        Foo { bar: true }
    }

    /// `bar` method on `Foo`.
    ///
    /// # Examples
    ///
    /// ```
    /// use x::y;
    ///
    /// let foo = Foo::new();
    ///
    /// // calls bar on foo
    /// assert!(foo.bar());
    ///
    /// let bar = foo.bar || Foo::bar;
    ///
    /// /* multi-line
    ///        comment */
    ///
    /// let multi_line_string = "Foo
    ///   bar
    ///          ";
    ///
    /// ```
    ///
    /// ```rust,no_run
    /// let foobar = Foo::new().bar();
    /// ```
    ///
    /// ```sh
    /// echo 1
    /// ```
    pub fn foo(&self) -> bool {
        true
    }
}

/// ```
/// noop!(1);
/// ```
macro_rules! noop {
    ($expr:expr) => {
        $expr
    }
}
"#
        .trim(),
        "crates/ra_ide/src/snapshots/highlight_doctest.html",
        false,
    );
}

/// Highlights the code given by the `ra_fixture` argument, renders the
/// result as HTML, and compares it with the HTML file given as `snapshot`.
/// Note that the `snapshot` file is overwritten by the rendered HTML.
fn check_highlighting(ra_fixture: &str, snapshot: &str, rainbow: bool) {
    let (analysis, file_id) = single_file(ra_fixture);
    let dst_file = project_dir().join(snapshot);
    let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap();
    let expected_html = &read_text(&dst_file);
    fs::write(dst_file, &actual_html).unwrap();
    assert_eq_text!(expected_html, actual_html);
}

#[test]
fn test_unsafe_highlighting() {
    let (analysis, file_id) = single_file(
        r#"
unsafe fn unsafe_fn() {}

struct HasUnsafeFn;

impl HasUnsafeFn {
    unsafe fn unsafe_method(&self) {}
}

fn main() {
    let x = &5 as *usize;
    unsafe {
        unsafe_fn();
        HasUnsafeFn.unsafe_method();
        let y = *x;
    }
}
"#
        .trim(),
    );
    let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlight_unsafe.html");
    let actual_html = &analysis.highlight_as_html(file_id, false).unwrap();
    let expected_html = &read_text(&dst_file);
    fs::write(dst_file, &actual_html).unwrap();
    assert_eq_text!(expected_html, actual_html);
}
<commit_msg>Fix typo in test<commit_after>use std::fs;

use test_utils::{assert_eq_text, project_dir, read_text};

use crate::{mock_analysis::single_file, FileRange, TextRange};

#[test]
fn test_highlighting() {
    check_highlighting(
        r#"
#[derive(Clone, Debug)]
struct Foo {
    pub x: i32,
    pub y: i32,
}

trait Bar {
    fn bar(&self) -> i32;
}

impl Bar for Foo {
    fn bar(&self) -> i32 {
        self.x
    }
}

static mut STATIC_MUT: i32 = 0;

fn foo<'a, T>() -> T {
    foo::<'a, i32>()
}

macro_rules! def_fn {
    ($($tt:tt)*) => {$($tt)*}
}

def_fn! {
    fn bar() -> u32 {
        100
    }
}

macro_rules! noop {
    ($expr:expr) => {
        $expr
    }
}

// comment
fn main() {
    println!("Hello, {}!", 92);

    let mut vec = Vec::new();
    if true {
        let x = 92;
        vec.push(Foo { x, y: 1 });
    }
    unsafe {
        vec.set_len(0);
        STATIC_MUT = 1;
    }

    for e in vec {
        // Do nothing
    }

    noop!(noop!(1));

    let mut x = 42;
    let y = &mut x;
    let z = &y;

    let Foo { x: z, y } = Foo { x: z, y };

    y;
}

enum Option<T> {
    Some(T),
    None,
}
use Option::*;

impl<T> Option<T> {
    fn and<U>(self, other: Option<U>) -> Option<(T, U)> {
        match other {
            None => unimplemented!(),
            Nope => Nope,
        }
    }
}
"#
        .trim(),
        "crates/ra_ide/src/snapshots/highlighting.html",
        false,
    );
}

#[test]
fn test_rainbow_highlighting() {
    check_highlighting(
        r#"
fn main() {
    let hello = "hello";
    let x = hello.to_string();
    let y = hello.to_string();

    let x = "other color please!";
    let y = x.to_string();
}

fn bar() {
    let mut hello = "hello";
}
"#
        .trim(),
        "crates/ra_ide/src/snapshots/rainbow_highlighting.html",
        true,
    );
}

#[test]
fn accidentally_quadratic() {
    let file = project_dir().join("crates/ra_syntax/test_data/accidentally_quadratic");
    let src = fs::read_to_string(file).unwrap();

    let (analysis, file_id) = single_file(&src);

    // let t = std::time::Instant::now();
    let _ = analysis.highlight(file_id).unwrap();
    // eprintln!("elapsed: {:?}", t.elapsed());
}

#[test]
fn test_ranges() {
    let (analysis, file_id) = single_file(
        r#"
#[derive(Clone, Debug)]
struct Foo {
    pub x: i32,
    pub y: i32,
}
"#,
    );

    // The "x"
    let highlights = &analysis
        .highlight_range(FileRange { file_id, range: TextRange::at(45.into(), 1.into()) })
        .unwrap();

    assert_eq!(&highlights[0].highlight.to_string(), "field.declaration");
}

#[test]
fn test_flattening() {
    check_highlighting(
        r##"
fn fixture(ra_fixture: &str) {}

fn main() {
    fixture(r#"
        trait Foo {
            fn foo() {
                println!("2 + 2 = {}", 4);
            }
        }"#
    );
}"##
        .trim(),
        "crates/ra_ide/src/snapshots/highlight_injection.html",
        false,
    );
}

#[test]
fn ranges_sorted() {
    let (analysis, file_id) = single_file(
        r#"
#[foo(bar = "bar")]
macro_rules! test {}
}"#
        .trim(),
    );
    let _ = analysis.highlight(file_id).unwrap();
}

#[test]
fn test_string_highlighting() {
    // The format string detection is based on macro-expansion,
    // thus, we have to copy the macro definition from `std`
    check_highlighting(
        r#"
macro_rules! println {
    ($($arg:tt)*) => ({
        $crate::io::_print($crate::format_args_nl!($($arg)*));
    })
}
#[rustc_builtin_macro]
macro_rules! format_args_nl {
    ($fmt:expr) => {{ /* compiler built-in */ }};
    ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
}

fn main() {
    // from https://doc.rust-lang.org/std/fmt/index.html
    println!("Hello");                 // => "Hello"
    println!("Hello, {}!", "world");   // => "Hello, world!"
    println!("The number is {}", 1);   // => "The number is 1"
    println!("{:?}", (3, 4));          // => "(3, 4)"
    println!("{value}", value=4);      // => "4"
    println!("{} {}", 1, 2);           // => "1 2"
    println!("{:04}", 42);             // => "0042" with leading zerosV
    println!("{1} {} {0} {}", 1, 2);   // => "2 1 1 2"
    println!("{argument}", argument = "test");   // => "test"
    println!("{name} {}", 1, name = 2);          // => "2 1"
    println!("{a} {c} {b}", a="a", b='b', c=3);  // => "a 3 b"
    println!("{{{}}}", 2);                       // => "{2}"
    println!("Hello {:5}!", "x");
    println!("Hello {:1$}!", "x", 5);
    println!("Hello {1:0$}!", 5, "x");
    println!("Hello {:width$}!", "x", width = 5);
    println!("Hello {:<5}!", "x");
    println!("Hello {:-<5}!", "x");
    println!("Hello {:^5}!", "x");
    println!("Hello {:>5}!", "x");
    println!("Hello {:+}!", 5);
    println!("{:#x}!", 27);
    println!("Hello {:05}!", 5);
    println!("Hello {:05}!", -5);
    println!("{:#010x}!", 27);
    println!("Hello {0} is {1:.5}", "x", 0.01);
    println!("Hello {1} is {2:.0$}", 5, "x", 0.01);
    println!("Hello {0} is {2:.1$}", "x", 5, 0.01);
    println!("Hello {} is {:.*}",    "x", 5, 0.01);
    println!("Hello {} is {2:.*}",   "x", 5, 0.01);
    println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01);
    println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56);
    println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56");
    println!("{}, `{name:>8.*}` has 3 right-aligned characters", "Hello", 3, name="1234.56");
    println!("Hello {{}}");
    println!("{{ Hello");

    println!(r"Hello, {}!", "world");

    // escape sequences
    println!("Hello\nWorld");
    println!("\u{48}\x65\x6C\x6C\x6F World");

    println!("{\x41}", A = 92);
    println!("{ничоси}", ничоси = 92);
}"#
        .trim(),
        "crates/ra_ide/src/snapshots/highlight_strings.html",
        false,
    );
}

#[test]
fn test_unsafe_highlighting() {
    check_highlighting(
        r#"
unsafe fn unsafe_fn() {}

struct HasUnsafeFn;

impl HasUnsafeFn {
    unsafe fn unsafe_method(&self) {}
}

fn main() {
    let x = &5 as *const usize;
    unsafe {
        unsafe_fn();
        HasUnsafeFn.unsafe_method();
        let y = *(x);
        let z = -x;
    }
}
"#
        .trim(),
        "crates/ra_ide/src/snapshots/highlight_unsafe.html",
        false,
    );
}

#[test]
fn test_highlight_doctest() {
    check_highlighting(
        r#"
/// ```
/// let _ = "early doctests should not go boom";
/// ```
struct Foo {
    bar: bool,
}

impl Foo {
    pub const bar: bool = true;

    /// Constructs a new `Foo`.
    ///
    /// # Examples
    ///
    /// ```
    /// # #![allow(unused_mut)]
    /// let mut foo: Foo = Foo::new();
    /// ```
    pub const fn new() -> Foo {
        Foo { bar: true }
    }

    /// `bar` method on `Foo`.
    ///
    /// # Examples
    ///
    /// ```
    /// use x::y;
    ///
    /// let foo = Foo::new();
    ///
    /// // calls bar on foo
    /// assert!(foo.bar());
    ///
    /// let bar = foo.bar || Foo::bar;
    ///
    /// /* multi-line
    ///        comment */
    ///
    /// let multi_line_string = "Foo
    ///   bar
    ///          ";
    ///
    /// ```
    ///
    /// ```rust,no_run
    /// let foobar = Foo::new().bar();
    /// ```
    ///
    /// ```sh
    /// echo 1
    /// ```
    pub fn foo(&self) -> bool {
        true
    }
}

/// ```
/// noop!(1);
/// ```
macro_rules! noop {
    ($expr:expr) => {
        $expr
    }
}
"#
        .trim(),
        "crates/ra_ide/src/snapshots/highlight_doctest.html",
        false,
    );
}

/// Highlights the code given by the `ra_fixture` argument, renders the
/// result as HTML, and compares it with the HTML file given as `snapshot`.
/// Note that the `snapshot` file is overwritten by the rendered HTML.
fn check_highlighting(ra_fixture: &str, snapshot: &str, rainbow: bool) {
    let (analysis, file_id) = single_file(ra_fixture);
    let dst_file = project_dir().join(snapshot);
    let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap();
    let expected_html = &read_text(&dst_file);
    fs::write(dst_file, &actual_html).unwrap();
    assert_eq_text!(expected_html, actual_html);
}

#[test]
fn test_unsafe_highlighting() {
    let (analysis, file_id) = single_file(
        r#"
unsafe fn unsafe_fn() {}

struct HasUnsafeFn;

impl HasUnsafeFn {
    unsafe fn unsafe_method(&self) {}
}

fn main() {
    let x = &5 as *const usize;
    unsafe {
        unsafe_fn();
        HasUnsafeFn.unsafe_method();
        let y = *x;
    }
}
"#
        .trim(),
    );
    let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlight_unsafe.html");
    let actual_html = &analysis.highlight_as_html(file_id, false).unwrap();
    let expected_html = &read_text(&dst_file);
    fs::write(dst_file, &actual_html).unwrap();
    assert_eq_text!(expected_html, actual_html);
}
<|endoftext|>


<commit_before>// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

//! Represents an address in the guest's memory space.

use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use std::ops::{Add, BitAnd, BitOr, Sub};

/// Simple helper trait used to store a raw address value.
pub trait AddressValue {
    /// Type of the address raw value.
    type V: Copy
        + PartialEq
        + Eq
        + PartialOrd
        + Ord
        + Add<Output = Self::V>
        + Sub<Output = Self::V>
        + BitAnd<Output = Self::V>
        + BitOr<Output = Self::V>;
}

/// Trait to represent an address within an address space.
///
/// To simplify the design and implementation, assume the same raw data type (AddressValue::V)
/// could be used to store address, size and offset for the address space. Thus the Address trait
/// could be used to manage address, size and offset. On the other hand, type aliases may be
/// defined to improve code readability.
///
/// One design rule is applied to the Address trait that operators (+, -, &, | etc) are not
/// supported and it forces clients to explicitly invoke corresponding methods. But there are
/// always exceptions:
///     Address (BitAnd|BitOr) AddressValue are supported.
pub trait Address:
    AddressValue
    + Sized
    + Default
    + Copy
    + Eq
    + PartialEq
    + Ord
    + PartialOrd
    + BitAnd<<Self as AddressValue>::V, Output = Self>
    + BitOr<<Self as AddressValue>::V, Output = Self>
{
    /// Get the raw value of the address.
    fn raw_value(&self) -> Self::V;

    /// Returns the bitwise and of the address with the given mask.
    fn mask(&self, mask: Self::V) -> Self::V {
        self.raw_value() & mask
    }

    /// Returns the offset from this address to the given base address.
    /// Only use this when `base` is guaranteed not to overflow.
    fn unchecked_offset_from(&self, base: Self) -> Self::V {
        self.raw_value() - base.raw_value()
    }

    /// Returns the result of the add or None if there is overflow.
    fn checked_add(&self, other: Self::V) -> Option<Self>;

    /// Returns the result of the base address + the size.
    /// Only use this when `offset` is guaranteed not to overflow.
    fn unchecked_add(&self, offset: Self::V) -> Self;

    /// Returns the result of the subtraction or None if there is underflow.
    fn checked_sub(&self, other: Self::V) -> Option<Self>;
}

/// Represents an Address in the guest's memory.
#[derive(Clone, Copy, Debug)]
pub struct GuestAddress(pub usize);

impl AddressValue for GuestAddress {
    type V = usize;
}

impl Address for GuestAddress {
    /// Returns the address as a `Self::V` offset from 0x0.
    /// Use this when a raw number is needed to pass to the kernel.
    fn raw_value(&self) -> Self::V {
        self.0
    }

    /// Returns the result of the add or None if there is overflow.
    fn checked_add(&self, other: Self::V) -> Option<GuestAddress> {
        self.0.checked_add(other).map(GuestAddress)
    }

    /// Returns the result of the base address + the size.
    /// Only use this when `offset` is guaranteed not to overflow.
    fn unchecked_add(&self, offset: Self::V) -> GuestAddress {
        GuestAddress(self.0 + offset)
    }

    /// Returns the result of the subtraction of None if there is underflow.
    fn checked_sub(&self, other: Self::V) -> Option<GuestAddress> {
        self.0.checked_sub(other).map(GuestAddress)
    }
}

impl Default for GuestAddress {
    fn default() -> GuestAddress {
        GuestAddress(0)
    }
}

impl BitAnd<<GuestAddress as AddressValue>::V> for GuestAddress {
    type Output = GuestAddress;

    fn bitand(self, other: <GuestAddress as AddressValue>::V) -> GuestAddress {
        GuestAddress(self.0 & other)
    }
}

impl BitOr<<GuestAddress as AddressValue>::V> for GuestAddress {
    type Output = GuestAddress;

    fn bitor(self, other: <GuestAddress as AddressValue>::V) -> GuestAddress {
        GuestAddress(self.0 | other)
    }
}

impl PartialEq for GuestAddress {
    fn eq(&self, other: &GuestAddress) -> bool {
        self.0 == other.0
    }
}
impl Eq for GuestAddress {}

impl Ord for GuestAddress {
    fn cmp(&self, other: &GuestAddress) -> Ordering {
        self.0.cmp(&other.0)
    }
}

impl PartialOrd for GuestAddress {
    fn partial_cmp(&self, other: &GuestAddress) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

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

    #[test]
    fn equals() {
        let a = GuestAddress(0x300);
        let b = GuestAddress(0x300);
        let c = GuestAddress(0x301);
        assert_eq!(a, GuestAddress(a.raw_value()));
        assert_eq!(a, b);
        assert_eq!(b, a);
        assert_ne!(a, c);
        assert_ne!(c, a);
    }

    #[test]
    fn cmp() {
        for i in 1..10 {
            for j in 1..10 {
                assert_eq!(i < j, GuestAddress(i) < GuestAddress(j));
                assert_eq!(i > j, GuestAddress(i) > GuestAddress(j));
            }
        }
    }

    #[test]
    fn add_sub() {
        let a = GuestAddress(0x50);
        let b = GuestAddress(0x60);
        assert_eq!(Some(GuestAddress(0xb0)), a.checked_add(0x60));
        assert_eq!(0x10, b.unchecked_offset_from(a));
    }

    #[test]
    fn checked_add_overflow() {
        let a = GuestAddress(0xffff_ffff_ffff_ff55);
        assert_eq!(Some(GuestAddress(0xffff_ffff_ffff_ff57)), a.checked_add(2));
        assert!(a.checked_add(0xf0).is_none());
    }

    #[test]
    fn checked_sub_underflow() {
        let a = GuestAddress(0xff);
        assert_eq!(Some(GuestAddress(0x0f)), a.checked_sub(0xf0));
        assert!(a.checked_sub(0xffff).is_none());
    }
}
<commit_msg>[GuestAddress] add unit tests<commit_after>// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

//! Represents an address in the guest's memory space.

use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use std::ops::{Add, BitAnd, BitOr, Sub};

/// Simple helper trait used to store a raw address value.
pub trait AddressValue {
    /// Type of the address raw value.
    type V: Copy
        + PartialEq
        + Eq
        + PartialOrd
        + Ord
        + Add<Output = Self::V>
        + Sub<Output = Self::V>
        + BitAnd<Output = Self::V>
        + BitOr<Output = Self::V>;
}

/// Trait to represent an address within an address space.
///
/// To simplify the design and implementation, assume the same raw data type (AddressValue::V)
/// could be used to store address, size and offset for the address space. Thus the Address trait
/// could be used to manage address, size and offset. On the other hand, type aliases may be
/// defined to improve code readability.
///
/// One design rule is applied to the Address trait that operators (+, -, &, | etc) are not
/// supported and it forces clients to explicitly invoke corresponding methods. But there are
/// always exceptions:
///     Address (BitAnd|BitOr) AddressValue are supported.
pub trait Address:
    AddressValue
    + Sized
    + Default
    + Copy
    + Eq
    + PartialEq
    + Ord
    + PartialOrd
    + BitAnd<<Self as AddressValue>::V, Output = Self>
    + BitOr<<Self as AddressValue>::V, Output = Self>
{
    /// Get the raw value of the address.
    fn raw_value(&self) -> Self::V;

    /// Returns the offset from this address to the given base address.
    /// Only use this when `base` is guaranteed not to overflow.
    fn unchecked_offset_from(&self, base: Self) -> Self::V {
        self.raw_value() - base.raw_value()
    }

    /// Returns the result of the add or None if there is overflow.
    fn checked_add(&self, other: Self::V) -> Option<Self>;

    /// Returns the result of the base address + the size.
    /// Only use this when `offset` is guaranteed not to overflow.
    fn unchecked_add(&self, offset: Self::V) -> Self;

    /// Returns the result of the subtraction or None if there is underflow.
    fn checked_sub(&self, other: Self::V) -> Option<Self>;
}

/// Represents an Address in the guest's memory.
#[derive(Clone, Copy, Debug)]
pub struct GuestAddress(pub usize);

impl AddressValue for GuestAddress {
    type V = usize;
}

impl Address for GuestAddress {
    /// Returns the address as a `Self::V` offset from 0x0.
    /// Use this when a raw number is needed to pass to the kernel.
    fn raw_value(&self) -> Self::V {
        self.0
    }

    /// Returns the result of the add or None if there is overflow.
    fn checked_add(&self, other: Self::V) -> Option<GuestAddress> {
        self.0.checked_add(other).map(GuestAddress)
    }

    /// Returns the result of the base address + the size.
    /// Only use this when `offset` is guaranteed not to overflow.
    fn unchecked_add(&self, offset: Self::V) -> GuestAddress {
        GuestAddress(self.0 + offset)
    }

    /// Returns the result of the subtraction of None if there is underflow.
    fn checked_sub(&self, other: Self::V) -> Option<GuestAddress> {
        self.0.checked_sub(other).map(GuestAddress)
    }
}

impl Default for GuestAddress {
    fn default() -> GuestAddress {
        GuestAddress(0)
    }
}

impl BitAnd<<GuestAddress as AddressValue>::V> for GuestAddress {
    type Output = GuestAddress;

    fn bitand(self, other: <GuestAddress as AddressValue>::V) -> GuestAddress {
        GuestAddress(self.0 & other)
    }
}

impl BitOr<<GuestAddress as AddressValue>::V> for GuestAddress {
    type Output = GuestAddress;

    fn bitor(self, other: <GuestAddress as AddressValue>::V) -> GuestAddress {
        GuestAddress(self.0 | other)
    }
}

impl PartialEq for GuestAddress {
    fn eq(&self, other: &GuestAddress) -> bool {
        self.0 == other.0
    }
}
impl Eq for GuestAddress {}

impl Ord for GuestAddress {
    fn cmp(&self, other: &GuestAddress) -> Ordering {
        self.0.cmp(&other.0)
    }
}

impl PartialOrd for GuestAddress {
    fn partial_cmp(&self, other: &GuestAddress) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

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

    #[test]
    fn equals() {
        let a = GuestAddress(0x300);
        let b = GuestAddress(0x300);
        let c = GuestAddress(0x301);
        assert_eq!(a, GuestAddress(a.raw_value()));
        assert_eq!(a, b);
        assert_eq!(b, a);
        assert_ne!(a, c);
        assert_ne!(c, a);
    }

    #[test]
    fn cmp() {
        for i in 1..10 {
            for j in 1..10 {
                assert_eq!(i < j, GuestAddress(i) < GuestAddress(j));
                assert_eq!(i > j, GuestAddress(i) > GuestAddress(j));
            }
        }
    }

    #[test]
    fn add_sub() {
        let a = GuestAddress(0x50);
        let b = GuestAddress(0x60);
        assert_eq!(Some(GuestAddress(0xb0)), a.checked_add(0x60));
        assert_eq!(0x10, b.unchecked_offset_from(a));
    }

    #[test]
    fn checked_add_overflow() {
        let a = GuestAddress(0xffff_ffff_ffff_ff55);
        assert_eq!(Some(GuestAddress(0xffff_ffff_ffff_ff57)), a.checked_add(2));
        assert!(a.checked_add(0xf0).is_none());
    }

    #[test]
    fn checked_sub_underflow() {
        let a = GuestAddress(0xff);
        assert_eq!(Some(GuestAddress(0x0f)), a.checked_sub(0xf0));
        assert!(a.checked_sub(0xffff).is_none());
    }

    #[test]
    fn default() {
        assert_eq!(GuestAddress::default(), GuestAddress(0));
    }

    #[test]
    fn and() {
        let a = GuestAddress(0x00);
        let b = GuestAddress(0xff);
        assert_eq!(a & b.raw_value(), a);
    }

    #[test]
    fn or() {
        let a = GuestAddress(0x00);
        let b = GuestAddress(0xff);
        assert_eq!(a | b.raw_value(), b);
    }
}
<|endoftext|>


<commit_before>use std::cell::{Cell, RefCell};
use std::ptr;

use cairo::{self, ImageSurface, MatrixTrait, PatternTrait};

use allowed_url::AllowedUrl;
use aspect_ratio::AspectRatio;
use attributes::Attribute;
use defs::Href;
use drawing_ctx::DrawingCtx;
use error::RenderingError;
use handle::{self, RsvgHandle};
use node::{CascadedValues, NodeResult, NodeTrait, RsvgNode};
use parsers::parse;
use property_bag::PropertyBag;
use surface_utils::shared_surface::{SharedImageSurface, SurfaceType};

use super::bounds::BoundsBuilder;
use super::context::{FilterContext, FilterOutput, FilterResult, IRect};
use super::{Filter, FilterError, Primitive};

/// The `feImage` filter primitive.
pub struct Image {
    base: Primitive,
    aspect: Cell<AspectRatio>,
    href: RefCell<Option<String>>,

    // Storing this here seems hack-ish... It's required by rsvg_cairo_surface_new_from_href(). The
    // <image> element calls it in set_atts() but I don't think it belongs there.
    handle: Cell<*const RsvgHandle>,
}

impl Image {
    /// Constructs a new `Image` with empty properties.
    #[inline]
    pub fn new() -> Image {
        Image {
            base: Primitive::new::<Self>(),
            aspect: Cell::new(AspectRatio::default()),
            href: RefCell::new(None),

            handle: Cell::new(ptr::null()),
        }
    }

    /// Renders the filter if the source is an existing node.
    fn render_node(
        &self,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx<'_>,
        bounds: IRect,
        href: &Href,
    ) -> Result<ImageSurface, FilterError> {
        let url = match *href {
            Href::WithFragment(ref f) => format!("{}#{}", f.uri().unwrap_or(""), f.fragment()),
            _ => unreachable!(),
        };

        let acquired_drawable = draw_ctx
            .get_acquired_href(&url)
            .ok_or(FilterError::InvalidInput)?;
        let drawable = acquired_drawable.get();

        let surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        draw_ctx.get_cairo_context().set_matrix(ctx.paffine());

        let node_being_filtered_values = ctx.get_computed_values_from_node_being_filtered();

        let cascaded = CascadedValues::new_from_values(&drawable, node_being_filtered_values);

        draw_ctx
            .draw_node_on_surface(
                &drawable,
                &cascaded,
                &surface,
                f64::from(ctx.source_graphic().width()),
                f64::from(ctx.source_graphic().height()),
            )
            .map_err(|e| {
                if let RenderingError::Cairo(status) = e {
                    FilterError::CairoError(status)
                } else {
                    // FIXME: this is just a dummy value; we should probably have a way to indicate
                    // an error in the underlying drawing process.
                    FilterError::CairoError(cairo::Status::InvalidStatus)
                }
            })?;

        // Clip the output to bounds.
        let output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        let cr = cairo::Context::new(&output_surface);
        cr.rectangle(
            f64::from(bounds.x0),
            f64::from(bounds.y0),
            f64::from(bounds.x1 - bounds.x0),
            f64::from(bounds.y1 - bounds.y0),
        );
        cr.clip();
        cr.set_source_surface(&surface, 0f64, 0f64);
        cr.paint();

        Ok(output_surface)
    }

    /// Renders the filter if the source is an external image.
    fn render_external_image(
        &self,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx<'_>,
        bounds_builder: BoundsBuilder<'_>,
        href: &Href,
    ) -> Result<ImageSurface, FilterError> {
        let url = if let Href::PlainUri(ref url) = *href {
            url
        } else {
            unreachable!();
        };

        let aurl = AllowedUrl::from_href(url, handle::get_base_url(self.handle.get()).as_ref())
            .map_err(|_| FilterError::InvalidInput)?;

        // FIXME: translate the error better here
        let surface = handle::load_image_to_surface(self.handle.get() as *mut _, &aurl)
            .map_err(|_| FilterError::InvalidInput)?;

        let output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        // TODO: this goes through a f64->i32->f64 conversion.
        let render_bounds = bounds_builder.into_irect_without_clipping(draw_ctx);
        let aspect = self.aspect.get();
        let (x, y, w, h) = aspect.compute(
            f64::from(surface.get_width()),
            f64::from(surface.get_height()),
            f64::from(render_bounds.x0),
            f64::from(render_bounds.y0),
            f64::from(render_bounds.x1 - render_bounds.x0),
            f64::from(render_bounds.y1 - render_bounds.y0),
        );

        if w != 0f64 && h != 0f64 {
            let ptn = cairo::SurfacePattern::create(&surface);
            let mut matrix = cairo::Matrix::new(
                w / f64::from(surface.get_width()),
                0f64,
                0f64,
                h / f64::from(surface.get_height()),
                x,
                y,
            );
            matrix.invert();
            ptn.set_matrix(matrix);

            let bounds = bounds_builder.into_irect(draw_ctx);
            let cr = cairo::Context::new(&output_surface);
            cr.rectangle(
                f64::from(bounds.x0),
                f64::from(bounds.y0),
                f64::from(bounds.x1 - bounds.x0),
                f64::from(bounds.y1 - bounds.y0),
            );
            cr.clip();
            cr.set_source(&cairo::Pattern::SurfacePattern(ptn));
            cr.paint();
        }

        Ok(output_surface)
    }
}

impl NodeTrait for Image {
    fn set_atts(
        &self,
        node: &RsvgNode,
        handle: *const RsvgHandle,
        pbag: &PropertyBag<'_>,
    ) -> NodeResult {
        self.base.set_atts(node, handle, pbag)?;

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::PreserveAspectRatio => {
                    self.aspect.set(parse("preserveAspectRatio", value, ())?)
                }

                // "path" is used by some older Adobe Illustrator versions
                Attribute::XlinkHref | Attribute::Path => {
                    drop(self.href.replace(Some(value.to_string())))
                }
                _ => (),
            }
        }

        self.handle.set(handle);

        Ok(())
    }
}

impl Filter for Image {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx<'_>,
    ) -> Result<FilterResult, FilterError> {
        let href_str = self.href.borrow();
        let href_str = href_str.as_ref().ok_or(FilterError::InvalidInput)?;

        let bounds_builder = self.base.get_bounds(ctx);
        let bounds = bounds_builder.into_irect(draw_ctx);

        let href = Href::parse(href_str).map_err(|_| FilterError::InvalidInput)?;

        let output_surface = match href {
            Href::PlainUri(_) => {
                self.render_external_image(ctx, draw_ctx, bounds_builder, &href)?
            }
            Href::WithFragment(_) => self.render_node(ctx, draw_ctx, bounds, &href)?,
        };

        Ok(FilterResult {
            name: self.base.result.borrow().clone(),
            output: FilterOutput {
                surface: SharedImageSurface::new(output_surface, SurfaceType::SRgb)?,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        false
    }
}
<commit_msg>filters/image.rs: Use the fragment directly in the case where it is needed<commit_after>use std::cell::{Cell, RefCell};
use std::ptr;

use cairo::{self, ImageSurface, MatrixTrait, PatternTrait};

use allowed_url::AllowedUrl;
use aspect_ratio::AspectRatio;
use attributes::Attribute;
use defs::{Fragment, Href};
use drawing_ctx::DrawingCtx;
use error::RenderingError;
use handle::{self, RsvgHandle};
use node::{CascadedValues, NodeResult, NodeTrait, RsvgNode};
use parsers::parse;
use property_bag::PropertyBag;
use surface_utils::shared_surface::{SharedImageSurface, SurfaceType};

use super::bounds::BoundsBuilder;
use super::context::{FilterContext, FilterOutput, FilterResult, IRect};
use super::{Filter, FilterError, Primitive};

/// The `feImage` filter primitive.
pub struct Image {
    base: Primitive,
    aspect: Cell<AspectRatio>,
    href: RefCell<Option<String>>,

    // Storing this here seems hack-ish... It's required by rsvg_cairo_surface_new_from_href(). The
    // <image> element calls it in set_atts() but I don't think it belongs there.
    handle: Cell<*const RsvgHandle>,
}

impl Image {
    /// Constructs a new `Image` with empty properties.
    #[inline]
    pub fn new() -> Image {
        Image {
            base: Primitive::new::<Self>(),
            aspect: Cell::new(AspectRatio::default()),
            href: RefCell::new(None),

            handle: Cell::new(ptr::null()),
        }
    }

    /// Renders the filter if the source is an existing node.
    fn render_node(
        &self,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx<'_>,
        bounds: IRect,
        fragment: &Fragment,
    ) -> Result<ImageSurface, FilterError> {
        let acquired_drawable = draw_ctx
            .get_acquired_node(fragment)
            .ok_or(FilterError::InvalidInput)?;
        let drawable = acquired_drawable.get();

        let surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        draw_ctx.get_cairo_context().set_matrix(ctx.paffine());

        let node_being_filtered_values = ctx.get_computed_values_from_node_being_filtered();

        let cascaded = CascadedValues::new_from_values(&drawable, node_being_filtered_values);

        draw_ctx
            .draw_node_on_surface(
                &drawable,
                &cascaded,
                &surface,
                f64::from(ctx.source_graphic().width()),
                f64::from(ctx.source_graphic().height()),
            )
            .map_err(|e| {
                if let RenderingError::Cairo(status) = e {
                    FilterError::CairoError(status)
                } else {
                    // FIXME: this is just a dummy value; we should probably have a way to indicate
                    // an error in the underlying drawing process.
                    FilterError::CairoError(cairo::Status::InvalidStatus)
                }
            })?;

        // Clip the output to bounds.
        let output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        let cr = cairo::Context::new(&output_surface);
        cr.rectangle(
            f64::from(bounds.x0),
            f64::from(bounds.y0),
            f64::from(bounds.x1 - bounds.x0),
            f64::from(bounds.y1 - bounds.y0),
        );
        cr.clip();
        cr.set_source_surface(&surface, 0f64, 0f64);
        cr.paint();

        Ok(output_surface)
    }

    /// Renders the filter if the source is an external image.
    fn render_external_image(
        &self,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx<'_>,
        bounds_builder: BoundsBuilder<'_>,
        href: &Href,
    ) -> Result<ImageSurface, FilterError> {
        let url = if let Href::PlainUri(ref url) = *href {
            url
        } else {
            unreachable!();
        };

        let aurl = AllowedUrl::from_href(url, handle::get_base_url(self.handle.get()).as_ref())
            .map_err(|_| FilterError::InvalidInput)?;

        // FIXME: translate the error better here
        let surface = handle::load_image_to_surface(self.handle.get() as *mut _, &aurl)
            .map_err(|_| FilterError::InvalidInput)?;

        let output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        // TODO: this goes through a f64->i32->f64 conversion.
        let render_bounds = bounds_builder.into_irect_without_clipping(draw_ctx);
        let aspect = self.aspect.get();
        let (x, y, w, h) = aspect.compute(
            f64::from(surface.get_width()),
            f64::from(surface.get_height()),
            f64::from(render_bounds.x0),
            f64::from(render_bounds.y0),
            f64::from(render_bounds.x1 - render_bounds.x0),
            f64::from(render_bounds.y1 - render_bounds.y0),
        );

        if w != 0f64 && h != 0f64 {
            let ptn = cairo::SurfacePattern::create(&surface);
            let mut matrix = cairo::Matrix::new(
                w / f64::from(surface.get_width()),
                0f64,
                0f64,
                h / f64::from(surface.get_height()),
                x,
                y,
            );
            matrix.invert();
            ptn.set_matrix(matrix);

            let bounds = bounds_builder.into_irect(draw_ctx);
            let cr = cairo::Context::new(&output_surface);
            cr.rectangle(
                f64::from(bounds.x0),
                f64::from(bounds.y0),
                f64::from(bounds.x1 - bounds.x0),
                f64::from(bounds.y1 - bounds.y0),
            );
            cr.clip();
            cr.set_source(&cairo::Pattern::SurfacePattern(ptn));
            cr.paint();
        }

        Ok(output_surface)
    }
}

impl NodeTrait for Image {
    fn set_atts(
        &self,
        node: &RsvgNode,
        handle: *const RsvgHandle,
        pbag: &PropertyBag<'_>,
    ) -> NodeResult {
        self.base.set_atts(node, handle, pbag)?;

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::PreserveAspectRatio => {
                    self.aspect.set(parse("preserveAspectRatio", value, ())?)
                }

                // "path" is used by some older Adobe Illustrator versions
                Attribute::XlinkHref | Attribute::Path => {
                    drop(self.href.replace(Some(value.to_string())))
                }
                _ => (),
            }
        }

        self.handle.set(handle);

        Ok(())
    }
}

impl Filter for Image {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx<'_>,
    ) -> Result<FilterResult, FilterError> {
        let href_str = self.href.borrow();
        let href_str = href_str.as_ref().ok_or(FilterError::InvalidInput)?;

        let bounds_builder = self.base.get_bounds(ctx);
        let bounds = bounds_builder.into_irect(draw_ctx);

        let href = Href::parse(href_str).map_err(|_| FilterError::InvalidInput)?;

        let output_surface = match href {
            Href::PlainUri(_) => {
                self.render_external_image(ctx, draw_ctx, bounds_builder, &href)?
            }
            Href::WithFragment(frag) => self.render_node(ctx, draw_ctx, bounds, &frag)?,
        };

        Ok(FilterResult {
            name: self.base.result.borrow().clone(),
            output: FilterOutput {
                surface: SharedImageSurface::new(output_surface, SurfaceType::SRgb)?,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        false
    }
}
<|endoftext|>


<commit_before>use std::cmp;
use std::path::Path;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::thread;

use super::time::{Duration, SteadyTime};

extern crate chip8vm;
use self::chip8vm::vm::{Chip8, CPU_CLOCK, TIMERS_CLOCK};
use self::chip8vm::display::{Display, DISPLAY_WIDTH, DISPLAY_HEIGHT};
use self::chip8vm::keypad::{Keystate};
use super::input;

/// Structure facilitating the configuration of a 'Chip8Application'.
/// The configuration functions (e.g. 'w_title') work with moved 'self' values
/// to allow chaining them inside the Chip8Application::new function call.
pub struct Chip8Config {
    /// The title of the emulator window.
    pub window_title   : &'static str,
    /// The desired width for the emulator window.
    /// NB : this is just a hint, the application may resize to reach a proper
    /// aspect ratio.
    pub window_width   : u16,
    /// The desired height for the emulator window.
    /// NB : this is just a hint, the application may resize to reach a proper
    /// aspect ratio.
    pub window_height  : u16,
    /// The keyboard configuration. QWERTY by default.
    pub keypad_binding : input::KeyboardBinding,
    /// The virtual machine's desired CPU clock in Hz (cycles per second).
    pub vm_cpu_clock   : u32,
}

/// Macro to avoid boilerplate setter code.
macro_rules! config_set_param {
    ($setter_name: ident, $param_name: ident, $param_type: ty) => (
        pub fn $setter_name(mut self, $param_name: $param_type)
            -> Chip8Config {
            self.$param_name = $param_name; self
        }
    )
}

impl Chip8Config {
    /// Create and return the default set of options.
    pub fn new() -> Chip8Config {
        Chip8Config {
            window_title   : "",
            window_width   : 64,
            window_height  : 32,
            keypad_binding : input::KeyboardBinding::QWERTY,
            vm_cpu_clock   : CPU_CLOCK
        }
    }

    config_set_param!(w_title, window_title, &'static str);
    config_set_param!(w_width, window_width, u16);
    config_set_param!(w_height, window_height, u16);
    config_set_param!(key_binds, keypad_binding, input::KeyboardBinding);
    config_set_param!(vm_cpu_clock, vm_cpu_clock, u32);
}

/// A command for the Chip8 virtual machine.
/// Allows the UI (more specifically the Chip8Emulator's backend) to feed
/// orders and information to the virtual machine's thread.
pub enum Chip8VMCommand {
    /// Set the emulation state (running for true, paused for false).
    UpdateRunStatus(bool),
    /// Communicate an update in the status of the key at the given index.
    UpdateKeyStatus(usize, Keystate),
    /// Reset the virtual machine to its default state.
    Reset,
    /// Shutdown the virtual machine.
    Quit,
}

/// A command for the Chip8 emulator's UI.
/// Allows the virtual machine to communicate with the Chip8Emulator's thread.
pub enum Chip8UICommand {
    /// Signal whether the emulator should emit a sound or not (true whenever
    /// the VM's sound timer is not zero).
    UpdateBeepingStatus(bool),
    /// A drawing command for the UI, communicating the information needed to
    /// do so. As of now, the 'Display' structure is pretty much that so we can
    /// affort to pass a copy of it.
    /// Should be called only when needed (display flagged dirty).
    UpdateDisplay(Display),
    /// Signal that the emulation is finished, emitted either after a
    /// 'Chip8VMCommand::Quit' signal was received or when the virtual machine
    /// finished the execution of its loaded program.
    Finished,
}

/// Trait that any CHIP 8 emulator backend must implement.
/// The backend is free to implement its 'run' loop however it wants to
/// but has to respect as completely as it can the 'Chip8Config' it is given.
pub trait Chip8EmulatorBackend {
    /// Start the UI loop with the given configuration and the provided
    /// thread channels.
    fn exec(&mut self, config: &Chip8Config,
            tx: Sender<Chip8VMCommand>, rx: Receiver<Chip8UICommand>);
}

/// The backend-agnostic CHIP 8 emulator application.
/// Communication between the virtual machine's emulation loop and the
/// backend's UI loop is done with 2 channels using respectively
/// 'Chip8VMCommand' and 'Chip8UICommand'.
pub struct Chip8Emulator<'a> {
    /// The 'Chip8Config' instance holding the application's configuration.
    config  : Chip8Config,
    /// Pointer to the heap-allocated backend responsible for running the
    /// actual UI loop in the main thread.
    backend : Box<Chip8EmulatorBackend + 'a>,
}

impl<'a> Chip8Emulator<'a> {
    /// Create and return a new Chip8Emulator, with the given 'Chip8Config'.
    pub fn new(config: Chip8Config, backend: Box<Chip8EmulatorBackend + 'a>)
        -> Chip8Emulator<'a> {
        Chip8Emulator {
            config  : config,
            backend : backend,
        }
    }

    /// Run the emulator application after loading the given ROM.
    /// Return true if all went well, false otherwise.
    /// TODO : more flexible run function (maybe a LoadRomCommand ?)
    pub fn run_rom(&mut self, rom_filepath: &Path) -> bool {
        // VM creation and ROM loading
        let mut vm = Chip8::new();
        info!("loading the ROM file \"{}\"...", rom_filepath.display());
        let oerror = vm.load(rom_filepath);
        if oerror.is_none() {
            info!("successfully loaded the ROM file.");
        } else {
            error!("loading error : {}", oerror.unwrap());
            return false;
        }

        // Communication channels
        let (tx_ui, rx_ui) = channel::<Chip8UICommand>();
        let (tx_vm, rx_vm) = channel::<Chip8VMCommand>();

        // VM loop, in a secondary thread
        let cpu_clock = self.config.vm_cpu_clock;
        thread::spawn(move || {
            // VM thread moved to an external function for better clarity
            exec_vm(&mut vm, cpu_clock, tx_ui, rx_vm);
        });

        // UI loop, in the emulator's thread (should be the main thread)
        self.backend.exec(&self.config, tx_vm, rx_ui);

        true
    }
}

/// Emulation loop simulating the CHIP 8 virtual machine and communicating back
/// to the emulator's backend implementation by feeding Chip8UI
pub fn exec_vm(vm: &mut Chip8, cpu_clock: u32,
               tx: Sender<Chip8UICommand>, rx: Receiver<Chip8VMCommand>) {
    use self::Chip8VMCommand::*;
    use self::Chip8UICommand::*;

    info!("starting the virtual machine thread with a CPU clock of {} Hz",
        cpu_clock);

    // time handling is in nanoseconds
    let mut t             = SteadyTime::now();
    let mut last_t_cpu    = SteadyTime::now();
    let mut last_t_timers = t;
    let timers_step = Duration::nanoseconds(10i64.pow(9)
                                            / (TIMERS_CLOCK as i64));
    let cpu_step    = Duration::nanoseconds(10i64.pow(9) / (cpu_clock as i64));

    // VM state
    let mut running         = true;
    let mut beeping         = false;
    let mut waiting_for_key = false;
    // avoid triggering multiple 'wait for key' instructions at once
    // especially with a high CPU clock
    let mut wait_for_key_last_pressed = 0xFF;

    'vm: loop {
        // Command from the UI
        match rx.try_recv() { // non-blocking receiving function
            Ok(vm_command) => match vm_command {
                UpdateRunStatus(run)          => running = run,
                UpdateKeyStatus(index, state) => {
                    match state {
                        Keystate::Pressed  => {
                            if waiting_for_key &&
                                (index != wait_for_key_last_pressed) {
                                vm.end_wait_for_key(index);
                                wait_for_key_last_pressed = index;
                            } else {
                                vm.keypad.set_key_state(index, state);
                            }
                        },
                        Keystate::Released => {
                            wait_for_key_last_pressed = 0xFF;
                            if !waiting_for_key {
                                vm.keypad.set_key_state(index, state);
                            }
                        },
                    }
                },
                Reset                         => vm.reset(),
                Quit                          => {
                    running = false;
                    info!("terminating the virtual machine thread...");
                    tx.send(Finished).unwrap();
                    break 'vm;
                },
            },
            _              => {},
        }

        // CPU
        t = SteadyTime::now();
        if t - last_t_cpu >= cpu_step {
            last_t_cpu = t;
            if running && !waiting_for_key {
                vm.emulate_cycle();
                if vm.display.dirty {
                    let display = vm.display.clone();
                    tx.send(UpdateDisplay(display)).unwrap();
                    vm.display.dirty = false;
                }
            }
            waiting_for_key = vm.is_waiting_for_key();
        }

        // Timers
        t = SteadyTime::now(); // this may be overkill
        if t - last_t_timers >= timers_step {
            last_t_timers = t;
            if running {
                if vm.delay_timer > 0 {
                    vm.delay_timer -= 1;
                }
                if vm.sound_timer > 0 {
                    vm.sound_timer -= 1;
                    if beeping != (vm.sound_timer > 0) {
                        beeping = !beeping;
                        tx.send(UpdateBeepingStatus(beeping)).unwrap();
                    }
                }
            }
        }

        // avoid overloading the CPU
        // this will prevent reaching very high CPU clock these are
        // bug-prone and unpractible really
    }
}

/// Return the best (pixel_scale, width, height) combination with the given
pub fn get_display_size(w_width: u16, w_height: u16) -> (u16, u16, u16) {
    let scale_w = w_width / (DISPLAY_WIDTH as u16);
    let scale_h = w_height / (DISPLAY_HEIGHT as u16);
    let scale = cmp::min(scale_w, scale_h);

    // adjust to the smallest scale and recompute the window dimensions
    (scale, scale * (DISPLAY_WIDTH as u16), scale * (DISPLAY_HEIGHT as u16))
}
<commit_msg>removed deprecated std::sleep_ms<commit_after>use std::cmp;
use std::path::Path;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::thread;

use super::time::{Duration, SteadyTime};

extern crate chip8vm;
use self::chip8vm::vm::{Chip8, CPU_CLOCK, TIMERS_CLOCK};
use self::chip8vm::display::{Display, DISPLAY_WIDTH, DISPLAY_HEIGHT};
use self::chip8vm::keypad::{Keystate};
use super::input;

/// Structure facilitating the configuration of a 'Chip8Application'.
/// The configuration functions (e.g. 'w_title') work with moved 'self' values
/// to allow chaining them inside the Chip8Application::new function call.
pub struct Chip8Config {
    /// The title of the emulator window.
    pub window_title   : &'static str,
    /// The desired width for the emulator window.
    /// NB : this is just a hint, the application may resize to reach a proper
    /// aspect ratio.
    pub window_width   : u16,
    /// The desired height for the emulator window.
    /// NB : this is just a hint, the application may resize to reach a proper
    /// aspect ratio.
    pub window_height  : u16,
    /// The keyboard configuration. QWERTY by default.
    pub keypad_binding : input::KeyboardBinding,
    /// The virtual machine's desired CPU clock in Hz (cycles per second).
    pub vm_cpu_clock   : u32,
}

/// Macro to avoid boilerplate setter code.
macro_rules! config_set_param {
    ($setter_name: ident, $param_name: ident, $param_type: ty) => (
        pub fn $setter_name(mut self, $param_name: $param_type)
            -> Chip8Config {
            self.$param_name = $param_name; self
        }
    )
}

impl Chip8Config {
    /// Create and return the default set of options.
    pub fn new() -> Chip8Config {
        Chip8Config {
            window_title   : "",
            window_width   : 64,
            window_height  : 32,
            keypad_binding : input::KeyboardBinding::QWERTY,
            vm_cpu_clock   : CPU_CLOCK
        }
    }

    config_set_param!(w_title, window_title, &'static str);
    config_set_param!(w_width, window_width, u16);
    config_set_param!(w_height, window_height, u16);
    config_set_param!(key_binds, keypad_binding, input::KeyboardBinding);
    config_set_param!(vm_cpu_clock, vm_cpu_clock, u32);
}

/// A command for the Chip8 virtual machine.
/// Allows the UI (more specifically the Chip8Emulator's backend) to feed
/// orders and information to the virtual machine's thread.
pub enum Chip8VMCommand {
    /// Set the emulation state (running for true, paused for false).
    UpdateRunStatus(bool),
    /// Communicate an update in the status of the key at the given index.
    UpdateKeyStatus(usize, Keystate),
    /// Reset the virtual machine to its default state.
    Reset,
    /// Shutdown the virtual machine.
    Quit,
}

/// A command for the Chip8 emulator's UI.
/// Allows the virtual machine to communicate with the Chip8Emulator's thread.
pub enum Chip8UICommand {
    /// Signal whether the emulator should emit a sound or not (true whenever
    /// the VM's sound timer is not zero).
    UpdateBeepingStatus(bool),
    /// A drawing command for the UI, communicating the information needed to
    /// do so. As of now, the 'Display' structure is pretty much that so we can
    /// affort to pass a copy of it.
    /// Should be called only when needed (display flagged dirty).
    UpdateDisplay(Display),
    /// Signal that the emulation is finished, emitted either after a
    /// 'Chip8VMCommand::Quit' signal was received or when the virtual machine
    /// finished the execution of its loaded program.
    Finished,
}

/// Trait that any CHIP 8 emulator backend must implement.
/// The backend is free to implement its 'run' loop however it wants to
/// but has to respect as completely as it can the 'Chip8Config' it is given.
pub trait Chip8EmulatorBackend {
    /// Start the UI loop with the given configuration and the provided
    /// thread channels.
    fn exec(&mut self, config: &Chip8Config,
            tx: Sender<Chip8VMCommand>, rx: Receiver<Chip8UICommand>);
}

/// The backend-agnostic CHIP 8 emulator application.
/// Communication between the virtual machine's emulation loop and the
/// backend's UI loop is done with 2 channels using respectively
/// 'Chip8VMCommand' and 'Chip8UICommand'.
pub struct Chip8Emulator<'a> {
    /// The 'Chip8Config' instance holding the application's configuration.
    config  : Chip8Config,
    /// Pointer to the heap-allocated backend responsible for running the
    /// actual UI loop in the main thread.
    backend : Box<Chip8EmulatorBackend + 'a>,
}

impl<'a> Chip8Emulator<'a> {
    /// Create and return a new Chip8Emulator, with the given 'Chip8Config'.
    pub fn new(config: Chip8Config, backend: Box<Chip8EmulatorBackend + 'a>)
        -> Chip8Emulator<'a> {
        Chip8Emulator {
            config  : config,
            backend : backend,
        }
    }

    /// Run the emulator application after loading the given ROM.
    /// Return true if all went well, false otherwise.
    /// TODO : more flexible run function (maybe a LoadRomCommand ?)
    pub fn run_rom(&mut self, rom_filepath: &Path) -> bool {
        // VM creation and ROM loading
        let mut vm = Chip8::new();
        info!("loading the ROM file \"{}\"...", rom_filepath.display());
        let oerror = vm.load(rom_filepath);
        if oerror.is_none() {
            info!("successfully loaded the ROM file.");
        } else {
            error!("loading error : {}", oerror.unwrap());
            return false;
        }

        // Communication channels
        let (tx_ui, rx_ui) = channel::<Chip8UICommand>();
        let (tx_vm, rx_vm) = channel::<Chip8VMCommand>();

        // VM loop, in a secondary thread
        let cpu_clock = self.config.vm_cpu_clock;
        thread::spawn(move || {
            // VM thread moved to an external function for better clarity
            exec_vm(&mut vm, cpu_clock, tx_ui, rx_vm);
        });

        // UI loop, in the emulator's thread (should be the main thread)
        self.backend.exec(&self.config, tx_vm, rx_ui);

        true
    }
}

/// Emulation loop simulating the CHIP 8 virtual machine and communicating back
/// to the emulator's backend implementation by feeding Chip8UI
pub fn exec_vm(vm: &mut Chip8, cpu_clock: u32,
               tx: Sender<Chip8UICommand>, rx: Receiver<Chip8VMCommand>) {
    use self::Chip8VMCommand::*;
    use self::Chip8UICommand::*;

    info!("starting the virtual machine thread with a CPU clock of {} Hz",
        cpu_clock);

    // time handling is in nanoseconds
    let mut t             = SteadyTime::now();
    let mut last_t_cpu    = SteadyTime::now();
    let mut last_t_timers = t;
    let timers_step = Duration::nanoseconds(10i64.pow(9)
                                            / (TIMERS_CLOCK as i64));
    let cpu_step    = Duration::nanoseconds(10i64.pow(9) / (cpu_clock as i64));

    // VM state
    let mut running         = true;
    let mut beeping         = false;
    let mut waiting_for_key = false;
    // avoid triggering multiple 'wait for key' instructions at once
    // especially with a high CPU clock
    let mut wait_for_key_last_pressed = 0xFF;

    'vm: loop {
        // Command from the UI
        match rx.try_recv() { // non-blocking receiving function
            Ok(vm_command) => match vm_command {
                UpdateRunStatus(run)          => running = run,
                UpdateKeyStatus(index, state) => {
                    match state {
                        Keystate::Pressed  => {
                            if waiting_for_key &&
                                (index != wait_for_key_last_pressed) {
                                vm.end_wait_for_key(index);
                                wait_for_key_last_pressed = index;
                            } else {
                                vm.keypad.set_key_state(index, state);
                            }
                        },
                        Keystate::Released => {
                            wait_for_key_last_pressed = 0xFF;
                            if !waiting_for_key {
                                vm.keypad.set_key_state(index, state);
                            }
                        },
                    }
                },
                Reset                         => vm.reset(),
                Quit                          => {
                    running = false;
                    info!("terminating the virtual machine thread...");
                    tx.send(Finished).unwrap();
                    break 'vm;
                },
            },
            _              => {},
        }

        // CPU
        t = SteadyTime::now();
        if t - last_t_cpu >= cpu_step {
            last_t_cpu = t;
            if running && !waiting_for_key {
                vm.emulate_cycle();
                if vm.display.dirty {
                    let display = vm.display.clone();
                    tx.send(UpdateDisplay(display)).unwrap();
                    vm.display.dirty = false;
                }
            }
            waiting_for_key = vm.is_waiting_for_key();
        }

        // Timers
        t = SteadyTime::now(); // this may be overkill
        if t - last_t_timers >= timers_step {
            last_t_timers = t;
            if running {
                if vm.delay_timer > 0 {
                    vm.delay_timer -= 1;
                }
                if vm.sound_timer > 0 {
                    vm.sound_timer -= 1;
                    if beeping != (vm.sound_timer > 0) {
                        beeping = !beeping;
                        tx.send(UpdateBeepingStatus(beeping)).unwrap();
                    }
                }
            }
        }

        // avoid overloading the CPU
        // this will prevent reaching very high CPU clock these are
        // bug-prone and unpractible really
        thread::sleep(::std::time::Duration::from_millis(1));
    }
}

/// Return the best (pixel_scale, width, height) combination with the given
pub fn get_display_size(w_width: u16, w_height: u16) -> (u16, u16, u16) {
    let scale_w = w_width / (DISPLAY_WIDTH as u16);
    let scale_h = w_height / (DISPLAY_HEIGHT as u16);
    let scale = cmp::min(scale_w, scale_h);

    // adjust to the smallest scale and recompute the window dimensions
    (scale, scale * (DISPLAY_WIDTH as u16), scale * (DISPLAY_HEIGHT as u16))
}
<|endoftext|>


<commit_before>
use postgres::{
    Rows,
    Connection,
    Statement
};

use postgres::Result as PostgresResult;
use postgres::types::ToSql;
use deuterium::{SqlContext, AsPostgresValue, QueryToSql};

pub type PostgresPool = ::r2d2::Pool<
    Connection,
    ::r2d2_postgres::Error,
    ::r2d2_postgres::PostgresPoolManager,
    ::r2d2::NoopErrorHandler>;

pub type PostgresPooledConnection<'a> = ::r2d2::PooledConnection<
    'a,
    ::postgres::Connection,
    ::r2d2_postgres::Error,
    ::r2d2_postgres::PostgresPoolManager,
    ::r2d2::NoopErrorHandler
>;

pub fn setup(cn_str: &str, pool_size: uint) -> PostgresPool {
    let manager = ::r2d2_postgres::PostgresPoolManager::new(cn_str, ::postgres::NoSsl);
    let config = ::r2d2::Config {
        pool_size: pool_size,
        test_on_check_out: true,
        ..::std::default::Default::default()
    };

    let handler = ::r2d2::NoopErrorHandler;
    ::r2d2::Pool::new(config, manager, handler).unwrap()
}

pub struct PostgresAdapter;

impl PostgresAdapter {
    pub fn prepare_query<'conn>(query: &QueryToSql, cn: &'conn Connection) -> (SqlContext, PostgresResult<Statement<'conn>>){
        let mut ctx = SqlContext::new(box ::deuterium::sql::adapter::PostgreSqlAdapter);
        let sql = query.to_final_sql(&mut ctx);

        (ctx, cn.prepare(sql.as_slice()))
    }

    pub fn prepare_params<'a>(
            ext_params: &[&'a ToSql],
            ctx_params: &'a[Box<AsPostgresValue + Send + Sync>]
        ) -> Vec<&'a ToSql + 'a> {

        let mut final_params = vec![];

        for param in ext_params.iter() {
            final_params.push(*param);
        }

        for param in ctx_params.iter() {
            final_params.push(param.as_postgres_value());
        }

        final_params
    }

    pub fn query<'conn, 'a>(stm: &'conn Statement<'conn>, params: &[&'a ToSql], ctx_params: &'a[Box<AsPostgresValue + Send + Sync>]) -> PostgresResult<Rows<'conn>> {
        stm.query(PostgresAdapter::prepare_params(params, ctx_params).as_slice())
    }

    pub fn execute<'conn, 'a>(stm: &'conn Statement<'conn>, params: &[&'a ToSql], ctx_params: &'a[Box<AsPostgresValue + Send + Sync>]) -> PostgresResult<uint> {
        stm.execute(PostgresAdapter::prepare_params(params, ctx_params).as_slice())
    }
}

pub trait FromRow {
    fn from_row<T, L>(query: &::deuterium::SelectQuery<T, L, Self>, row: &::postgres::Row) -> Self;
}

pub fn from_row<T, L, M: FromRow>(query: &::deuterium::SelectQuery<T, L, M>, row: &::postgres::Row) -> M {
    FromRow::from_row(query, row)
}

#[macro_export]
macro_rules! unwrap_or_report_sql_error(
    () => ()
)

#[macro_export]
macro_rules! to_sql_string_pg(
    ($query:expr) => ({
        let mut ctx = ::deuterium::SqlContext::new(box ::deuterium::sql::adapter::PostgreSqlAdapter);
        $query.to_final_sql(&mut ctx)
    })
)

#[macro_export]
macro_rules! query_pg(
    ($query:expr, $cn:expr, $params:expr, $rows:ident, $blk:block) => ({
        let (ctx, maybe_stm) = ::deuterium_orm::adapter::postgres::PostgresAdapter::prepare_query($query, $cn);
        let stm = match maybe_stm {
            Ok(stm) => stm,
            Err(e) => panic!("SQL query `{}` panicked at {}:{} with error `{}`",
                to_sql_string_pg!($query), file!(), line!(), e
            )
        };

        let $rows = ::deuterium_orm::adapter::postgres::PostgresAdapter::query(&stm, $params, ctx.data());

        let $rows = match $rows {
            Ok($rows) => $rows,
            Err(e) => panic!("SQL query `{}` panicked at {}:{} with error `{}`",
                to_sql_string_pg!($query), file!(), line!(), e
            ),
        };

        $blk
    });
)

#[macro_export]
macro_rules! query_models_iter(
    ($query:expr, $cn:expr, $params:expr) => (
        query_pg!($query, $cn, $params, rows, {
            rows.map(|row| {
                ::deuterium_orm::adapter::postgres::from_row($query, &row)
            })
        })
    )
)

fn into_vec() {

}

#[macro_export]
macro_rules! query_models(
    ($query:expr, $cn:expr, $params:expr) => (
        query_pg!($query, $cn, $params, rows, {
            let vec: Vec<_> = rows.map(|row| {
                ::deuterium_orm::adapter::postgres::from_row($query, &row)
            }).collect();
            vec
        })
    )
)

#[macro_export]
macro_rules! query_model(
    ($query:expr, $cn:expr, $params:expr) => (
        query_pg!($query, $cn, $params, rows, {
            rows.take(1).next().map(|row| {
                ::deuterium_orm::adapter::postgres::from_row($query, &row)
            })
        })
    )
)

#[macro_export]
macro_rules! exec_pg_safe(
    ($query:expr, $cn:expr, $params:expr) => ({
        let (ctx, maybe_stm) = ::deuterium_orm::adapter::postgres::PostgresAdapter::prepare_query($query, $cn);
        let stm = maybe_stm.unwrap();
        ::deuterium_orm::adapter::postgres::PostgresAdapter::execute(&stm, $params, ctx.data())
    })
)

#[macro_export]
macro_rules! exec_pg(
    ($query:expr, $cn:expr, $params:expr) => ({
        match exec_pg_safe!($query, $cn, $params) {
            Ok(res) => res,
            Err(e) => panic!("SQL query `{}` panicked at {}:{} with error `{}`",
                to_sql_string_pg!($query), file!(), line!(), e
            )
        }
    })
)

#[macro_export]
macro_rules! try_pg(
    ($e:expr) => (
        match $e {
            Ok(ok) => ok,
            Err(err) => return Err(::postgres::Error::PgStreamError(err))
        }
    )
)

#[macro_export]
macro_rules! deuterium_enum(
    ($en:ty) => (
        impl ::postgres::types::FromSql for $en {
            fn from_sql(_ty: &::postgres::types::Type, raw: &Option<Vec<u8>>) -> ::postgres::Result<$en> {
                match raw {
                    &Some(ref buf) => {
                        let mut reader = ::std::io::BufReader::new(buf[]);
                        Ok(::std::num::FromPrimitive::from_u8(try_pg!(reader.read_u8())).unwrap())
                    },
                    &None => {
                        Err(::postgres::Error::PgBadData)
                    }
                }

            }
        }

        impl ::deuterium::ToSql for $en {
            fn to_sql(&self, ctx: &mut ::deuterium::SqlContext) -> String {
                let i = self.clone() as i16;
                i.to_predicate_value(ctx)
            }
        }

        impl ::deuterium::UntypedExpression for $en {
            fn expression_as_sql(&self) -> &ToSql {
                self
            }

            fn upcast_expression(&self) -> RcExpression {
                let i = self.clone() as i16;
                ::std::sync::Arc::new(box i as ::deuterium::BoxedExpression)
            }
        }

        impl ::deuterium::ToExpression<$en> for $en {}
        impl ::deuterium::ToExpression<i16> for $en {}
        impl ::deuterium::ToExpression<()> for $en {}

        impl ::deuterium::ToPredicateValue for $en {
            fn to_predicate_value(&self, ctx: &mut SqlContext) -> String {
                let i = self.clone() as i16;
                ctx.hold(box i)
            }
        }
    )
)<commit_msg>refactor: remove unused function<commit_after>
use postgres::{
    Rows,
    Connection,
    Statement
};

use postgres::Result as PostgresResult;
use postgres::types::ToSql;
use deuterium::{SqlContext, AsPostgresValue, QueryToSql};

pub type PostgresPool = ::r2d2::Pool<
    Connection,
    ::r2d2_postgres::Error,
    ::r2d2_postgres::PostgresPoolManager,
    ::r2d2::NoopErrorHandler>;

pub type PostgresPooledConnection<'a> = ::r2d2::PooledConnection<
    'a,
    ::postgres::Connection,
    ::r2d2_postgres::Error,
    ::r2d2_postgres::PostgresPoolManager,
    ::r2d2::NoopErrorHandler
>;

pub fn setup(cn_str: &str, pool_size: uint) -> PostgresPool {
    let manager = ::r2d2_postgres::PostgresPoolManager::new(cn_str, ::postgres::NoSsl);
    let config = ::r2d2::Config {
        pool_size: pool_size,
        test_on_check_out: true,
        ..::std::default::Default::default()
    };

    let handler = ::r2d2::NoopErrorHandler;
    ::r2d2::Pool::new(config, manager, handler).unwrap()
}

pub struct PostgresAdapter;

impl PostgresAdapter {
    pub fn prepare_query<'conn>(query: &QueryToSql, cn: &'conn Connection) -> (SqlContext, PostgresResult<Statement<'conn>>){
        let mut ctx = SqlContext::new(box ::deuterium::sql::adapter::PostgreSqlAdapter);
        let sql = query.to_final_sql(&mut ctx);

        (ctx, cn.prepare(sql.as_slice()))
    }

    pub fn prepare_params<'a>(
            ext_params: &[&'a ToSql],
            ctx_params: &'a[Box<AsPostgresValue + Send + Sync>]
        ) -> Vec<&'a ToSql + 'a> {

        let mut final_params = vec![];

        for param in ext_params.iter() {
            final_params.push(*param);
        }

        for param in ctx_params.iter() {
            final_params.push(param.as_postgres_value());
        }

        final_params
    }

    pub fn query<'conn, 'a>(stm: &'conn Statement<'conn>, params: &[&'a ToSql], ctx_params: &'a[Box<AsPostgresValue + Send + Sync>]) -> PostgresResult<Rows<'conn>> {
        stm.query(PostgresAdapter::prepare_params(params, ctx_params).as_slice())
    }

    pub fn execute<'conn, 'a>(stm: &'conn Statement<'conn>, params: &[&'a ToSql], ctx_params: &'a[Box<AsPostgresValue + Send + Sync>]) -> PostgresResult<uint> {
        stm.execute(PostgresAdapter::prepare_params(params, ctx_params).as_slice())
    }
}

pub trait FromRow {
    fn from_row<T, L>(query: &::deuterium::SelectQuery<T, L, Self>, row: &::postgres::Row) -> Self;
}

pub fn from_row<T, L, M: FromRow>(query: &::deuterium::SelectQuery<T, L, M>, row: &::postgres::Row) -> M {
    FromRow::from_row(query, row)
}

#[macro_export]
macro_rules! unwrap_or_report_sql_error(
    () => ()
)

#[macro_export]
macro_rules! to_sql_string_pg(
    ($query:expr) => ({
        let mut ctx = ::deuterium::SqlContext::new(box ::deuterium::sql::adapter::PostgreSqlAdapter);
        $query.to_final_sql(&mut ctx)
    })
)

#[macro_export]
macro_rules! query_pg(
    ($query:expr, $cn:expr, $params:expr, $rows:ident, $blk:block) => ({
        let (ctx, maybe_stm) = ::deuterium_orm::adapter::postgres::PostgresAdapter::prepare_query($query, $cn);
        let stm = match maybe_stm {
            Ok(stm) => stm,
            Err(e) => panic!("SQL query `{}` panicked at {}:{} with error `{}`",
                to_sql_string_pg!($query), file!(), line!(), e
            )
        };

        let $rows = ::deuterium_orm::adapter::postgres::PostgresAdapter::query(&stm, $params, ctx.data());

        let $rows = match $rows {
            Ok($rows) => $rows,
            Err(e) => panic!("SQL query `{}` panicked at {}:{} with error `{}`",
                to_sql_string_pg!($query), file!(), line!(), e
            ),
        };

        $blk
    });
)

#[macro_export]
macro_rules! query_models_iter(
    ($query:expr, $cn:expr, $params:expr) => (
        query_pg!($query, $cn, $params, rows, {
            rows.map(|row| {
                ::deuterium_orm::adapter::postgres::from_row($query, &row)
            })
        })
    )
)

#[macro_export]
macro_rules! query_models(
    ($query:expr, $cn:expr, $params:expr) => (
        query_pg!($query, $cn, $params, rows, {
            let vec: Vec<_> = rows.map(|row| {
                ::deuterium_orm::adapter::postgres::from_row($query, &row)
            }).collect();
            vec
        })
    )
)

#[macro_export]
macro_rules! query_model(
    ($query:expr, $cn:expr, $params:expr) => (
        query_pg!($query, $cn, $params, rows, {
            rows.take(1).next().map(|row| {
                ::deuterium_orm::adapter::postgres::from_row($query, &row)
            })
        })
    )
)

#[macro_export]
macro_rules! exec_pg_safe(
    ($query:expr, $cn:expr, $params:expr) => ({
        let (ctx, maybe_stm) = ::deuterium_orm::adapter::postgres::PostgresAdapter::prepare_query($query, $cn);
        let stm = maybe_stm.unwrap();
        ::deuterium_orm::adapter::postgres::PostgresAdapter::execute(&stm, $params, ctx.data())
    })
)

#[macro_export]
macro_rules! exec_pg(
    ($query:expr, $cn:expr, $params:expr) => ({
        match exec_pg_safe!($query, $cn, $params) {
            Ok(res) => res,
            Err(e) => panic!("SQL query `{}` panicked at {}:{} with error `{}`",
                to_sql_string_pg!($query), file!(), line!(), e
            )
        }
    })
)

#[macro_export]
macro_rules! try_pg(
    ($e:expr) => (
        match $e {
            Ok(ok) => ok,
            Err(err) => return Err(::postgres::Error::PgStreamError(err))
        }
    )
)

#[macro_export]
macro_rules! deuterium_enum(
    ($en:ty) => (
        impl ::postgres::types::FromSql for $en {
            fn from_sql(_ty: &::postgres::types::Type, raw: &Option<Vec<u8>>) -> ::postgres::Result<$en> {
                match raw {
                    &Some(ref buf) => {
                        let mut reader = ::std::io::BufReader::new(buf[]);
                        Ok(::std::num::FromPrimitive::from_u8(try_pg!(reader.read_u8())).unwrap())
                    },
                    &None => {
                        Err(::postgres::Error::PgBadData)
                    }
                }

            }
        }

        impl ::deuterium::ToSql for $en {
            fn to_sql(&self, ctx: &mut ::deuterium::SqlContext) -> String {
                let i = self.clone() as i16;
                i.to_predicate_value(ctx)
            }
        }

        impl ::deuterium::UntypedExpression for $en {
            fn expression_as_sql(&self) -> &ToSql {
                self
            }

            fn upcast_expression(&self) -> RcExpression {
                let i = self.clone() as i16;
                ::std::sync::Arc::new(box i as ::deuterium::BoxedExpression)
            }
        }

        impl ::deuterium::ToExpression<$en> for $en {}
        impl ::deuterium::ToExpression<i16> for $en {}
        impl ::deuterium::ToExpression<()> for $en {}

        impl ::deuterium::ToPredicateValue for $en {
            fn to_predicate_value(&self, ctx: &mut SqlContext) -> String {
                let i = self.clone() as i16;
                ctx.hold(box i)
            }
        }
    )
)<|endoftext|>


<commit_before>// The Computer Language Benchmarks Game
// http://benchmarksgame.alioth.debian.org/
//
// contributed by the Rust Project Developers
// contributed by TeXitoi

extern crate arena;

use std::iter::range_step;
use std::thread::Thread;
use arena::TypedArena;

enum Tree<'a> {
    Nil,
    Node(&'a Tree<'a>, &'a Tree<'a>, i32)
}

fn item_check(t: &Tree) -> i32 {
    match *t {
        Tree::Nil => 0,
        Tree::Node(l, r, i) => i + item_check(l) - item_check(r)
    }
}

fn bottom_up_tree<'r>(arena: &'r TypedArena<Tree<'r>>, item: i32, depth: i32)
                  -> &'r Tree<'r> {
    if depth > 0 {
        arena.alloc(Tree::Node(bottom_up_tree(arena, 2 * item - 1, depth - 1),
                               bottom_up_tree(arena, 2 * item, depth - 1),
                               item))
    } else {
        arena.alloc(Tree::Nil)
    }
}

fn main() {
    let n = std::os::args().get(1).and_then(|n| n.parse()).unwrap_or(10);
    let min_depth = 4;
    let max_depth = if min_depth + 2 > n {min_depth + 2} else {n};

    {
        let arena = TypedArena::new();
        let depth = max_depth + 1;
        let tree = bottom_up_tree(&arena, 0, depth);

        println!("stretch tree of depth {}\t check: {}",
                 depth, item_check(tree));
    }

    let long_lived_arena = TypedArena::new();
    let long_lived_tree = bottom_up_tree(&long_lived_arena, 0, max_depth);

    let messages = range_step(min_depth, max_depth + 1, 2).map(|depth| {
            use std::num::Int;
            let iterations = 2.pow((max_depth - depth + min_depth) as usize);
            Thread::scoped(move|| {
                let mut chk = 0;
                for i in 1 .. iterations + 1 {
                    let arena = TypedArena::new();
                    let a = bottom_up_tree(&arena, i, depth);
                    let b = bottom_up_tree(&arena, -i, depth);
                    chk += item_check(a) + item_check(b);
                }
                format!("{}\t trees of depth {}\t check: {}",
                        iterations * 2, depth, chk)
            })
        }).collect::<Vec<_>>();

    for message in messages.into_iter() {
        println!("{}", message.join().ok().unwrap());
    }

    println!("long lived tree of depth {}\t check: {}",
             max_depth, item_check(long_lived_tree));
}
<commit_msg>improve binary-tree (by a lot!)<commit_after>// The Computer Language Benchmarks Game
// http://benchmarksgame.alioth.debian.org/
//
// contributed by the Rust Project Developers
// contributed by TeXitoi

extern crate arena;

use std::iter::range_step;
use std::thread::Thread;
use arena::TypedArena;

struct Tree<'a> {
    l: Option<&'a Tree<'a>>,
    r: Option<&'a Tree<'a>>,
    i: i32
}

fn item_check(t: &Option<&Tree>) -> i32 {
    match *t {
        None => 0,
        Some(&Tree { ref l, ref r, i }) => i + item_check(l) - item_check(r)
    }
}

fn bottom_up_tree<'r>(arena: &'r TypedArena<Tree<'r>>, item: i32, depth: i32)
                  -> Option<&'r Tree<'r>> {
    if depth > 0 {
        let t: &Tree<'r> = arena.alloc(Tree {
            l: bottom_up_tree(arena, 2 * item - 1, depth - 1),
            r: bottom_up_tree(arena, 2 * item, depth - 1),
            i: item
        });
        Some(t)
    } else {
        None
    }
}

fn main() {
    let n = std::os::args().get(1).and_then(|n| n.parse()).unwrap_or(10);
    let min_depth = 4;
    let max_depth = if min_depth + 2 > n {min_depth + 2} else {n};

    {
        let arena = TypedArena::new();
        let depth = max_depth + 1;
        let tree = bottom_up_tree(&arena, 0, depth);

        println!("stretch tree of depth {}\t check: {}",
                 depth, item_check(&tree));
    }

    let long_lived_arena = TypedArena::new();
    let long_lived_tree = bottom_up_tree(&long_lived_arena, 0, max_depth);

    let messages = range_step(min_depth, max_depth + 1, 2).map(|depth| {
            use std::num::Int;
            let iterations = 2.pow((max_depth - depth + min_depth) as usize);
            Thread::scoped(move|| {
                let mut chk = 0;
                for i in 1 .. iterations + 1 {
                    let arena = TypedArena::new();
                    let a = bottom_up_tree(&arena, i, depth);
                    let b = bottom_up_tree(&arena, -i, depth);
                    chk += item_check(&a) + item_check(&b);
                }
                format!("{}\t trees of depth {}\t check: {}",
                        iterations * 2, depth, chk)
            })
        }).collect::<Vec<_>>();

    for message in messages.into_iter() {
        println!("{}", message.join().ok().unwrap());
    }

    println!("long lived tree of depth {}\t check: {}",
             max_depth, item_check(&long_lived_tree));
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::fs;
use std::io;
use std::path::Path;
use std::slice::{Iter, IterMut};

use serde_json as json;

use crate::res;
use crate::task::{self, Task};

use crate::error::{BuildError, ErrorKind, ResultExt};

/// A rule in the build description. A build description is simply a list of
/// rules.
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct Rule {
    /// Inputs to the task.
    #[serde(default)]
    pub inputs: res::Set,

    /// Outputs from the task.
    #[serde(default)]
    pub outputs: res::Set,

    /// The sequence of tasks to execute.
    pub tasks: task::List,
}

#[derive(Debug, PartialEq)]
pub struct Rules(Vec<Rule>);

impl Rules {
    pub fn new(mut rules: Vec<Rule>) -> Rules {
        // Add known inputs and outputs so the user doesn't have to.
        for r in &mut rules {
            r.tasks.known_inputs(&mut r.inputs);
            r.tasks.known_outputs(&mut r.outputs);
        }

        Rules(rules)
    }

    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Rules, BuildError> {
        let path = path.as_ref();

        let f = fs::File::open(path)
            .with_context(|_| {
                format!("Could not open file '{}'", path.display())
            })
            .context(ErrorKind::ParsingRules)?;

        let rules = Self::from_reader(io::BufReader::new(f))
            .with_context(|_| {
                format!("Failed parsing json from '{}'", path.display())
            })
            .context(ErrorKind::ParsingRules)?;

        Ok(rules)
    }

    fn from_reader<R>(reader: R) -> Result<Rules, json::error::Error>
    where
        R: io::Read,
    {
        Ok(Self::new(json::from_reader(reader)?))
    }

    #[cfg(test)]
    pub fn from_str(s: &str) -> Result<Rules, json::error::Error> {
        Ok(Self::new(json::from_str(s)?))
    }

    pub fn iter(&self) -> Iter<'_, Rule> {
        self.0.iter()
    }

    pub fn iter_mut(&mut self) -> IterMut<'_, Rule> {
        self.0.iter_mut()
    }
}

impl IntoIterator for Rules {
    type Item = Rule;
    type IntoIter = ::std::vec::IntoIter<Rule>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::res::File;
    use crate::task::Command;
    use std::path::PathBuf;

    #[test]
    fn test_loading() {
        let data = r#"[{
            "inputs": [{"file": "foo.c"}, {"file": "foo.h"}],
            "outputs": [{"file": "foo.o"}],
            "tasks": [
                {
                    "command": {
                        "program": "gcc",
                        "args": ["foo.c"]
                    }
                }
            ]
        }]"#;

        let rules = Rules::from_str(&data).unwrap();

        let inputs =
            vec![File::from("foo.c").into(), File::from("foo.h").into()];

        let outputs = vec![File::from("foo.o").into()];
        let tasks = vec![Command::new(
            PathBuf::from("gcc"),
            vec!["foo.c".into()].into_iter().collect(),
        )
        .into()];

        assert_eq!(
            rules,
            Rules::new(vec![Rule {
                inputs: inputs.into_iter().collect(),
                outputs: outputs.into_iter().collect(),
                tasks: tasks.into(),
            }])
        );
    }
}
<commit_msg>Error on misspelled Rules fields<commit_after>// Copyright (c) 2017 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::fs;
use std::io;
use std::path::Path;
use std::slice::{Iter, IterMut};

use serde_json as json;

use crate::res;
use crate::task::{self, Task};

use crate::error::{BuildError, ErrorKind, ResultExt};

/// A rule in the build description. A build description is simply a list of
/// rules.
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct Rule {
    /// Inputs to the task.
    #[serde(default)]
    pub inputs: res::Set,

    /// Outputs from the task.
    #[serde(default)]
    pub outputs: res::Set,

    /// The sequence of tasks to execute.
    pub tasks: task::List,
}

#[derive(Debug, PartialEq)]
pub struct Rules(Vec<Rule>);

impl Rules {
    pub fn new(mut rules: Vec<Rule>) -> Rules {
        // Add known inputs and outputs so the user doesn't have to.
        for r in &mut rules {
            r.tasks.known_inputs(&mut r.inputs);
            r.tasks.known_outputs(&mut r.outputs);
        }

        Rules(rules)
    }

    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Rules, BuildError> {
        let path = path.as_ref();

        let f = fs::File::open(path)
            .with_context(|_| {
                format!("Could not open file '{}'", path.display())
            })
            .context(ErrorKind::ParsingRules)?;

        let rules = Self::from_reader(io::BufReader::new(f))
            .with_context(|_| {
                format!("Failed parsing json from '{}'", path.display())
            })
            .context(ErrorKind::ParsingRules)?;

        Ok(rules)
    }

    fn from_reader<R>(reader: R) -> Result<Rules, json::error::Error>
    where
        R: io::Read,
    {
        Ok(Self::new(json::from_reader(reader)?))
    }

    #[cfg(test)]
    pub fn from_str(s: &str) -> Result<Rules, json::error::Error> {
        Ok(Self::new(json::from_str(s)?))
    }

    pub fn iter(&self) -> Iter<'_, Rule> {
        self.0.iter()
    }

    pub fn iter_mut(&mut self) -> IterMut<'_, Rule> {
        self.0.iter_mut()
    }
}

impl IntoIterator for Rules {
    type Item = Rule;
    type IntoIter = ::std::vec::IntoIter<Rule>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::res::File;
    use crate::task::Command;
    use std::path::PathBuf;

    #[test]
    fn test_loading() {
        let data = r#"[{
            "inputs": [{"file": "foo.c"}, {"file": "foo.h"}],
            "outputs": [{"file": "foo.o"}],
            "tasks": [
                {
                    "command": {
                        "program": "gcc",
                        "args": ["foo.c"]
                    }
                }
            ]
        }]"#;

        let rules = Rules::from_str(&data).unwrap();

        let inputs =
            vec![File::from("foo.c").into(), File::from("foo.h").into()];

        let outputs = vec![File::from("foo.o").into()];
        let tasks = vec![Command::new(
            PathBuf::from("gcc"),
            vec!["foo.c".into()].into_iter().collect(),
        )
        .into()];

        assert_eq!(
            rules,
            Rules::new(vec![Rule {
                inputs: inputs.into_iter().collect(),
                outputs: outputs.into_iter().collect(),
                tasks: tasks.into(),
            }])
        );
    }
}
<|endoftext|>