<commit_before>extern crate double;

trait Dependency: Clone {
    fn profit(&self, revenue: u32, costs: u32) -> i32;
}

macro_rules! mock_trait {
    ( $mock_name:ident, $($method:ident($retval:ty)($($arg_type:ty),*))* ) => (
        #[derive(Debug, Clone)]
        struct $mock_name {
            $(
                $method: double::Mock<(($($arg_type),*)), $retval>
            )*
        }

        impl Default for $mock_name {
            fn default() -> Self {
                $mock_name {
                    $(
                        $method: double::Mock::default(),
                    )*
                }
            }
        }
    );
}

macro_rules! mock_method {
    ( $method:ident($retval:ty)($($arg_name:ident: $arg_type:ty),*) ) => (
        fn $method(&self, $($arg_name: $arg_type),*) -> $retval {
            self.$method.call(($($arg_name),*))
        }
    )
}

mock_trait!(MockDependency, profit(i32)(u32, u32));

impl Dependency for MockDependency {
    mock_method!(profit(i32)(revenue: u32, costs: u32));

    /*fn profit(&self, revenue: u32, costs: u32) -> i32 {
        self.profit.call((revenue, costs))
    }*/
}

fn main() {
    // Test individual return values
    let mock = MockDependency::default();
    mock.profit.return_value(42);
    mock.profit.return_value_for((0, 0), 9001);

    let value = mock.profit(10, 20);
    assert_eq!(42, value);
    mock.profit.has_calls_exactly_in_order(vec!((10, 20)));

    let value = mock.profit(0, 0);
    assert_eq!(9001, value);
    mock.profit.has_calls_exactly_in_order(vec!((10, 20), (0, 0)));

    // Test sequence of return values
    mock.profit.return_values(vec!(1, 2, 3));
    assert_eq!(1, mock.profit.call((1, 2)));
    assert_eq!(2, mock.profit.call((2, 4)));
    assert_eq!(3, mock.profit.call((3, 6)));
    assert_eq!(42, mock.profit.call((4, 8)));
}
<commit_msg>Add macro support for mutable and immutable mock methods<commit_after>extern crate double;

trait Dependency: Clone {
    fn profit(&self, revenue: u32, costs: u32) -> i32;
}

trait Greeter: Clone {
    fn greet<S: AsRef<str>>(&mut self, name: S);
}

macro_rules! mock_trait {
    ( $mock_name:ident, $($method:ident($retval:ty)($($arg_type:ty),*))* ) => (
        #[derive(Debug, Clone)]
        struct $mock_name {
            $(
                $method: double::Mock<(($($arg_type),*)), $retval>
            )*
        }

        impl Default for $mock_name {
            fn default() -> Self {
                $mock_name {
                    $(
                        $method: double::Mock::default(),
                    )*
                }
            }
        }
    );
}

macro_rules! mock_method {
    ( $method:ident($retval:ty)(&self, $($arg_name:ident: $arg_type:ty),*) ) => (
        fn $method(&self, $($arg_name: $arg_type),*) -> $retval {
            self.$method.call(($($arg_name),*))
        }
    );
    ( $method:ident($retval:ty)(&mut self, $($arg_name:ident: $arg_type:ty),*) ) => (
        fn $method(&mut self, $($arg_name: $arg_type),*) -> $retval {
            self.$method.call(($($arg_name),*))
        }
    )
}

mock_trait!(MockDependency, profit(i32)(u32, u32));
impl Dependency for MockDependency {
    mock_method!(profit(i32)(&self, revenue: u32, costs: u32));
}

mock_trait(MockGreeter, greet(())(String));

fn main() {
    // Test individual return values
    let mock = MockDependency::default();
    mock.profit.return_value(42);
    mock.profit.return_value_for((0, 0), 9001);

    let value = mock.profit(10, 20);
    assert_eq!(42, value);
    mock.profit.has_calls_exactly_in_order(vec!((10, 20)));

    let value = mock.profit(0, 0);
    assert_eq!(9001, value);
    mock.profit.has_calls_exactly_in_order(vec!((10, 20), (0, 0)));

    // Test sequence of return values
    mock.profit.return_values(vec!(1, 2, 3));
    assert_eq!(1, mock.profit.call((1, 2)));
    assert_eq!(2, mock.profit.call((2, 4)));
    assert_eq!(3, mock.profit.call((3, 6)));
    assert_eq!(42, mock.profit.call((4, 8)));
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, The Radare Project. All rights reserved.
// See the COPYING file at the top-level directory of this distribution.
// Licensed under the BSD 3-Clause License:
// <http://opensource.org/licenses/BSD-3-Clause>
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Enumerations and structs to represent instructions.
//! Shared by the SSA representation and the intermediate representation of the
//! ESIL parser.

use std::fmt;

pub type Address = u64;
pub type WidthSpec = u16;

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
// New address struct
pub struct MAddress {
    pub address: u64,
    pub offset: u64,
}

impl MAddress {
    pub fn new(address: u64, offset: u64) -> MAddress {
        MAddress {
            address: address,
            offset: offset,
        }
    }

    pub fn invalid_address() -> MAddress {
        MAddress {
            address: u64::max_value(),
            offset: u64::max_value(),
        }
    }
}

impl fmt::UpperHex for MAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:#08X}.{:04}", self.address, self.offset)
    }
}

impl fmt::Display for MAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:X}", self)
    }
}

impl From<u64> for MAddress {
    fn from(other: u64) -> MAddress {
        MAddress {
            address: other,
            offset: 0,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MArity {
    Zero,
    Unary,
    Binary,
    Ternary,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MOpcode {
    OpAdd,
    OpSub,
    OpMul,
    OpDiv,
    OpMod,
    OpAnd,
    OpOr,
    OpXor,
    OpNot,
    OpEq,
    OpCmp,
    OpGt,
    OpLt,
    OpLsl,
    OpLsr,
    OpIf,
    OpJmp,
    OpCJmp,
    OpCall,
    OpLoad,
    OpStore,
    OpNarrow(WidthSpec),
    OpWiden(WidthSpec),
    OpConst(u64),
    OpNop,
    OpInvalid,
    // If - Then - Else
    OpITE,
}

impl MOpcode {
    pub fn is_binary(&self) -> bool {
        self.arity() == MArity::Binary
    }

    pub fn is_unary(&self) -> bool {
        self.arity() == MArity::Unary
    }

    pub fn arity(&self) -> MArity {
        self.info().1
    }

    pub fn to_string(&self) -> String {
        self.info().0
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            MOpcode::OpAdd |
            MOpcode::OpMul |
            MOpcode::OpAnd |
            MOpcode::OpOr |
            MOpcode::OpXor |
            MOpcode::OpCmp |
            MOpcode::OpGt |
            MOpcode::OpLt => true,
            _ => false,
        }
    }

    pub fn has_sideeffects(&self) -> bool {
        match *self {
            MOpcode::OpStore |
            MOpcode::OpJmp |
            MOpcode::OpCJmp |
            MOpcode::OpCall |
            MOpcode::OpITE => true,
            _ => false,
        }
    }

    pub fn allowed_in_ssa(&self) -> bool {
        match *self {
            MOpcode::OpJmp |
            MOpcode::OpCJmp |
            MOpcode::OpNop |
            MOpcode::OpITE |
            MOpcode::OpInvalid => false,
            _ => true,
        }
    }

    fn info(&self) -> (String, MArity) {
        match *self {
            MOpcode::OpAdd => ("OpAdd".to_owned(), MArity::Binary),
            MOpcode::OpSub => ("OpSub".to_owned(), MArity::Binary),
            MOpcode::OpMul => ("OpMul".to_owned(), MArity::Binary),
            MOpcode::OpDiv => ("OpDiv".to_owned(), MArity::Binary),
            MOpcode::OpMod => ("OpMod".to_owned(), MArity::Binary),
            MOpcode::OpAnd => ("OpAnd".to_owned(), MArity::Binary),
            MOpcode::OpOr => ("OpOr".to_owned(), MArity::Binary),
            MOpcode::OpXor => ("OpXor".to_owned(), MArity::Binary),
            MOpcode::OpNot => ("OpNot".to_owned(), MArity::Unary),
            MOpcode::OpEq => ("OpEq".to_owned(), MArity::Binary),
            MOpcode::OpCmp => ("OpCmp".to_owned(), MArity::Binary),
            MOpcode::OpGt => ("OpGt".to_owned(), MArity::Binary),
            MOpcode::OpLt => ("OpLt".to_owned(), MArity::Binary),
            MOpcode::OpLsl => ("OpLsl".to_owned(), MArity::Binary),
            MOpcode::OpLsr => ("OpLsr".to_owned(), MArity::Binary),
            MOpcode::OpIf => ("OpIf".to_owned(), MArity::Unary),
            MOpcode::OpLoad => ("OpLoad".to_owned(), MArity::Binary),
            MOpcode::OpStore => ("OpStore".to_owned(), MArity::Ternary),
            MOpcode::OpNarrow(_) => ("OpNarrow".to_owned(), MArity::Unary),
            MOpcode::OpWiden(_) => ("OpWiden".to_owned(), MArity::Unary),
            MOpcode::OpJmp => ("OpJmp".to_owned(), MArity::Unary),
            MOpcode::OpCJmp => ("OpJmpIf".to_owned(), MArity::Binary),
            MOpcode::OpCall => ("OpCall".to_owned(), MArity::Unary),
            MOpcode::OpConst(c) => (format!("OpCost({})", c), MArity::Zero),
            MOpcode::OpNop => ("OpNop".to_owned(), MArity::Zero),
            MOpcode::OpInvalid => ("OpInvalid".to_owned(), MArity::Zero),
            MOpcode::OpITE => ("ITE".to_owned(), MArity::Ternary),
        }
    }
}

impl fmt::Display for MOpcode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}
<commit_msg>Seems there are many limited in ternary OpStore<commit_after>// Copyright (c) 2015, The Radare Project. All rights reserved.
// See the COPYING file at the top-level directory of this distribution.
// Licensed under the BSD 3-Clause License:
// <http://opensource.org/licenses/BSD-3-Clause>
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Enumerations and structs to represent instructions.
//! Shared by the SSA representation and the intermediate representation of the
//! ESIL parser.

use std::fmt;

pub type Address = u64;
pub type WidthSpec = u16;

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
// New address struct
pub struct MAddress {
    pub address: u64,
    pub offset: u64,
}

impl MAddress {
    pub fn new(address: u64, offset: u64) -> MAddress {
        MAddress {
            address: address,
            offset: offset,
        }
    }

    pub fn invalid_address() -> MAddress {
        MAddress {
            address: u64::max_value(),
            offset: u64::max_value(),
        }
    }
}

impl fmt::UpperHex for MAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:#08X}.{:04}", self.address, self.offset)
    }
}

impl fmt::Display for MAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:X}", self)
    }
}

impl From<u64> for MAddress {
    fn from(other: u64) -> MAddress {
        MAddress {
            address: other,
            offset: 0,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MArity {
    Zero,
    Unary,
    Binary,
    Ternary,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum MOpcode {
    OpAdd,
    OpSub,
    OpMul,
    OpDiv,
    OpMod,
    OpAnd,
    OpOr,
    OpXor,
    OpNot,
    OpEq,
    OpCmp,
    OpGt,
    OpLt,
    OpLsl,
    OpLsr,
    OpIf,
    OpJmp,
    OpCJmp,
    OpCall,
    OpLoad,
    OpStore,
    OpNarrow(WidthSpec),
    OpWiden(WidthSpec),
    OpConst(u64),
    OpNop,
    OpInvalid,
    // If - Then - Else
    OpITE,
}

impl MOpcode {
    pub fn is_binary(&self) -> bool {
        self.arity() == MArity::Binary
    }

    pub fn is_unary(&self) -> bool {
        self.arity() == MArity::Unary
    }

    pub fn arity(&self) -> MArity {
        self.info().1
    }

    pub fn to_string(&self) -> String {
        self.info().0
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            MOpcode::OpAdd |
            MOpcode::OpMul |
            MOpcode::OpAnd |
            MOpcode::OpOr |
            MOpcode::OpXor |
            MOpcode::OpCmp |
            MOpcode::OpGt |
            MOpcode::OpLt => true,
            _ => false,
        }
    }

    pub fn has_sideeffects(&self) -> bool {
        match *self {
            MOpcode::OpStore |
            MOpcode::OpJmp |
            MOpcode::OpCJmp |
            MOpcode::OpCall |
            MOpcode::OpITE => true,
            _ => false,
        }
    }

    pub fn allowed_in_ssa(&self) -> bool {
        match *self {
            MOpcode::OpJmp |
            MOpcode::OpCJmp |
            MOpcode::OpNop |
            MOpcode::OpITE |
            MOpcode::OpInvalid => false,
            _ => true,
        }
    }

    fn info(&self) -> (String, MArity) {
        match *self {
            MOpcode::OpAdd => ("OpAdd".to_owned(), MArity::Binary),
            MOpcode::OpSub => ("OpSub".to_owned(), MArity::Binary),
            MOpcode::OpMul => ("OpMul".to_owned(), MArity::Binary),
            MOpcode::OpDiv => ("OpDiv".to_owned(), MArity::Binary),
            MOpcode::OpMod => ("OpMod".to_owned(), MArity::Binary),
            MOpcode::OpAnd => ("OpAnd".to_owned(), MArity::Binary),
            MOpcode::OpOr => ("OpOr".to_owned(), MArity::Binary),
            MOpcode::OpXor => ("OpXor".to_owned(), MArity::Binary),
            MOpcode::OpNot => ("OpNot".to_owned(), MArity::Unary),
            MOpcode::OpEq => ("OpEq".to_owned(), MArity::Binary),
            MOpcode::OpCmp => ("OpCmp".to_owned(), MArity::Binary),
            MOpcode::OpGt => ("OpGt".to_owned(), MArity::Binary),
            MOpcode::OpLt => ("OpLt".to_owned(), MArity::Binary),
            MOpcode::OpLsl => ("OpLsl".to_owned(), MArity::Binary),
            MOpcode::OpLsr => ("OpLsr".to_owned(), MArity::Binary),
            MOpcode::OpIf => ("OpIf".to_owned(), MArity::Unary),
            MOpcode::OpLoad => ("OpLoad".to_owned(), MArity::Binary),
            MOpcode::OpStore => ("OpStore".to_owned(), MArity::Binary),
            MOpcode::OpNarrow(_) => ("OpNarrow".to_owned(), MArity::Unary),
            MOpcode::OpWiden(_) => ("OpWiden".to_owned(), MArity::Unary),
            MOpcode::OpJmp => ("OpJmp".to_owned(), MArity::Unary),
            MOpcode::OpCJmp => ("OpJmpIf".to_owned(), MArity::Binary),
            MOpcode::OpCall => ("OpCall".to_owned(), MArity::Unary),
            MOpcode::OpConst(c) => (format!("OpCost({})", c), MArity::Zero),
            MOpcode::OpNop => ("OpNop".to_owned(), MArity::Zero),
            MOpcode::OpInvalid => ("OpInvalid".to_owned(), MArity::Zero),
            MOpcode::OpITE => ("ITE".to_owned(), MArity::Ternary),
        }
    }
}

impl fmt::Display for MOpcode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Gilad Naaman
//
// 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.

/// Macro to create a local `base_ptr` raw pointer of the given type, avoiding UB as
/// much as is possible currently.
#[cfg(memoffset_maybe_uninit)]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__let_base_ptr {
    ($name:ident, $type:path) => {
        // No UB here, and the pointer does not dangle, either.
        // But we have to make sure that `uninit` lives long enough,
        // so it has to be in the same scope as `$name`. That's why
        // `let_base_ptr` declares a variable (several, actually)
        // instad of returning one.
        let uninit = $crate::mem::MaybeUninit::<$type>::uninit();
        let $name = uninit.as_ptr();
    };
}
#[cfg(not(memoffset_maybe_uninit))]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__let_base_ptr {
    ($name:ident, $type:path) => {
        // No UB right here, but we will later dereference this pointer to
        // offset into a field, and that is UB when the pointer is dangling.
        let $name = $crate::mem::align_of::<$type>() as *const $type;
    };
}

/// Deref-coercion protection macro.
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__field_check {
    ($type:path, $field:tt) => {
        // Make sure the field actually exists. This line ensures that a
        // compile-time error is generated if $field is accessed through a
        // Deref impl.
        let $type { $field: _, .. };
    };
}

/// Calculates the offset of the specified field from the start of the struct.
///
/// ## Examples
/// ```
/// #[macro_use]
/// extern crate memoffset;
///
/// #[repr(C, packed)]
/// struct Foo {
///     a: u32,
///     b: u64,
///     c: [u8; 5]
/// }
///
/// fn main() {
///     assert_eq!(offset_of!(Foo, a), 0);
///     assert_eq!(offset_of!(Foo, b), 4);
/// }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! offset_of {
    ($parent:path, $field:tt) => {{
        _memoffset__field_check!($parent, $field);

        // Get a base pointer.
        _memoffset__let_base_ptr!(base_ptr, $parent);
        // Get the field address. This is UB because we are creating a reference to
        // the uninitialized field.
        // Crucially, we know that this will not trigger a deref coercion because
        // of the `field_check!` we did above.
        #[allow(unused_unsafe)] // for when the macro is used in an unsafe block
        let field_ptr = unsafe { &(*base_ptr).$field as *const _ };
        let offset = (field_ptr as usize) - (base_ptr as usize);
        offset
    }};
}

#[cfg(test)]
mod tests {
    #[test]
    fn offset_simple() {
        #[repr(C)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!(offset_of!(Foo, a), 0);
        assert_eq!(offset_of!(Foo, b), 4);
        assert_eq!(offset_of!(Foo, c), 8);
    }

    #[test]
    #[cfg(not(miri))] // this creates unaligned references
    fn offset_simple_packed() {
        #[repr(C, packed)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!(offset_of!(Foo, a), 0);
        assert_eq!(offset_of!(Foo, b), 4);
        assert_eq!(offset_of!(Foo, c), 6);
    }

    #[test]
    fn tuple_struct() {
        #[repr(C)]
        struct Tup(i32, i32);

        assert_eq!(offset_of!(Tup, 0), 0);
        assert_eq!(offset_of!(Tup, 1), 4);
    }

    #[test]
    fn path() {
        mod sub {
            #[repr(C)]
            pub struct Foo {
                pub x: u32,
            }
        }

        assert_eq!(offset_of!(sub::Foo, x), 0);
    }
}
<commit_msg>allow clippy lint<commit_after>// Copyright (c) 2017 Gilad Naaman
//
// 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.

/// Macro to create a local `base_ptr` raw pointer of the given type, avoiding UB as
/// much as is possible currently.
#[cfg(memoffset_maybe_uninit)]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__let_base_ptr {
    ($name:ident, $type:path) => {
        // No UB here, and the pointer does not dangle, either.
        // But we have to make sure that `uninit` lives long enough,
        // so it has to be in the same scope as `$name`. That's why
        // `let_base_ptr` declares a variable (several, actually)
        // instad of returning one.
        let uninit = $crate::mem::MaybeUninit::<$type>::uninit();
        let $name = uninit.as_ptr();
    };
}
#[cfg(not(memoffset_maybe_uninit))]
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__let_base_ptr {
    ($name:ident, $type:path) => {
        // No UB right here, but we will later dereference this pointer to
        // offset into a field, and that is UB when the pointer is dangling.
        let $name = $crate::mem::align_of::<$type>() as *const $type;
    };
}

/// Deref-coercion protection macro.
#[macro_export]
#[doc(hidden)]
macro_rules! _memoffset__field_check {
    ($type:path, $field:tt) => {
        // Make sure the field actually exists. This line ensures that a
        // compile-time error is generated if $field is accessed through a
        // Deref impl.
        #[allow(clippy::unneeded_field_pattern)]
        let $type { $field: _, .. };
    };
}

/// Calculates the offset of the specified field from the start of the struct.
///
/// ## Examples
/// ```
/// #[macro_use]
/// extern crate memoffset;
///
/// #[repr(C, packed)]
/// struct Foo {
///     a: u32,
///     b: u64,
///     c: [u8; 5]
/// }
///
/// fn main() {
///     assert_eq!(offset_of!(Foo, a), 0);
///     assert_eq!(offset_of!(Foo, b), 4);
/// }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! offset_of {
    ($parent:path, $field:tt) => {{
        _memoffset__field_check!($parent, $field);

        // Get a base pointer.
        _memoffset__let_base_ptr!(base_ptr, $parent);
        // Get the field address. This is UB because we are creating a reference to
        // the uninitialized field.
        // Crucially, we know that this will not trigger a deref coercion because
        // of the `field_check!` we did above.
        #[allow(unused_unsafe)] // for when the macro is used in an unsafe block
        let field_ptr = unsafe { &(*base_ptr).$field as *const _ };
        let offset = (field_ptr as usize) - (base_ptr as usize);
        offset
    }};
}

#[cfg(test)]
mod tests {
    #[test]
    fn offset_simple() {
        #[repr(C)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!(offset_of!(Foo, a), 0);
        assert_eq!(offset_of!(Foo, b), 4);
        assert_eq!(offset_of!(Foo, c), 8);
    }

    #[test]
    #[cfg(not(miri))] // this creates unaligned references
    fn offset_simple_packed() {
        #[repr(C, packed)]
        struct Foo {
            a: u32,
            b: [u8; 2],
            c: i64,
        }

        assert_eq!(offset_of!(Foo, a), 0);
        assert_eq!(offset_of!(Foo, b), 4);
        assert_eq!(offset_of!(Foo, c), 6);
    }

    #[test]
    fn tuple_struct() {
        #[repr(C)]
        struct Tup(i32, i32);

        assert_eq!(offset_of!(Tup, 0), 0);
        assert_eq!(offset_of!(Tup, 1), 4);
    }

    #[test]
    fn path() {
        mod sub {
            #[repr(C)]
            pub struct Foo {
                pub x: u32,
            }
        }

        assert_eq!(offset_of!(sub::Foo, x), 0);
    }
}
<|endoftext|>


<commit_before>//! The oldest module, the data module stores all the data needed to collect.
pub mod bktree;
pub mod ipc;

use super::config;
use bktree::BKTree;

use id3::Tag;
use libp2p_core::PeerId;
use std::{
    fs::{self, DirEntry, Permissions}, // directory
    io,                                // reading files
    path::{Path, PathBuf},
    sync::Arc,
};
use tree_magic;

static TOLERANCE: usize = 5;
static TIME_TOLERANCE_SEC: usize = 4;

#[allow(dead_code)]
/// # File info
/// All info on a audio files
/// (let's see how info we need,
/// its size vs necessary info)
struct FileInfo {
    path: PathBuf,
    size: u64,
    permissions: Permissions,
}

struct AudioInfo {
    duration: u32,
    album: String,
}

/// # Album information
/// General info
struct InfoAlbum {
    reference_path: Vec<FileInfo>,
}

#[allow(dead_code)]
struct Worker {
    /// identify them.
    peer_id: PeerId,
    max_threads: usize,
}

/// # Worker
/// the worker is supposed to be running on different machines
/// with one server and many clients
impl Worker {
    /// # Just new
    /// To identify how to comment
    /// # Arguments
    /// * 'id' - the identification (each will create an own hash)
    /// * 'max_threads' - how many threads can the worker create
    pub fn new(peer_id: PeerId, max_threads: usize) -> Worker {
        Worker {
            peer_id: peer_id,
            max_threads: max_threads,
        }
    }
}

pub struct Collection {
    /// This collection contains all data
    who: Worker,
    bk_tree: BKTree<String, Box<AudioInfo>>,
    stats: Stats,
}
/// Only some statistics
pub struct FilesStat {
    pub analyzed: u32,
    pub faulty: u32,
    pub searched: u32,
    pub other: u32,
}

impl FilesStat {
    /// Adds stats from one to the other,
    /// used for combining different thread
    /// results.
    fn add(&mut self, other: &FilesStat) {
        self.analyzed += other.analyzed;
        self.faulty += other.faulty;
        self.searched += other.searched;
        self.other += other.other;
    }
}

struct Stats {
    files: FilesStat,
    threads: usize,
}

type FileFn = dyn Fn(&mut Collection, &DirEntry, &mut FilesStat) -> io::Result<()>;

impl Collection {
    /// Sets up the whole collection that books all threads.
    pub fn new(peer_id: &PeerId, num_threads: usize) -> Collection {
        Collection {
            who: Worker::new(peer_id.clone(), num_threads),
            bk_tree: BKTree::new(),
            stats: Stats {
                files: FilesStat {
                    analyzed: 0,
                    faulty: 0,
                    searched: 0,
                    other: 0,
                },
                threads: num_threads,
            },
        }
    }

    /// The function that runs from a certain path
    pub fn visit_path(&mut self, dir: &Path, cb: &FileFn) -> io::Result<FilesStat> {
        let mut file_stats = FilesStat {
            analyzed: 0,
            faulty: 0,
            searched: 0,
            other: 0,
        };

        if dir.is_dir() {
            for entry in fs::read_dir(dir)? {
                let mut loop_file_stats = &mut file_stats;

                let entry = entry?;
                let path = entry.path();
                if path.is_dir() {
                    let file_stats_loop = self.visit_path(&path, cb)?;
                    loop_file_stats.add(&file_stats_loop);
                } else {
                    cb(self, &entry, &mut loop_file_stats).or_else(|io_error| {
                        warn!("{:?}", io_error);
                        Err(io_error)
                    })?
                }
            }
        }
        Ok(file_stats)
    }

    /// the function to check all files separately
    pub fn visit_files(
        col: &mut Collection,
        cb: &DirEntry,
        file_stats: &mut FilesStat,
    ) -> io::Result<()> {
        // count stats
        col.stats.files.searched += 1;
        file_stats.searched += 1;

        let filetype = tree_magic::from_filepath(&cb.path());
        let prefix = filetype.split("/").nth(0);
        match prefix {
            Some("audio") => {
                if let Some(suffix) = filetype.split("/").last() {
                    if config::data::IGNORE_AUDIO_FORMATS
                        .iter()
                        .any(|&s| s == suffix)
                    {
                        col.stats.files.other += 1;
                        file_stats.other += 1;
                        Ok(())
                    } else {
                        col.visit_audio_files(&cb.path(), file_stats).or_else(|_| {
                            col.stats.files.faulty += 1;
                            file_stats.faulty += 1;
                            error!("ts: {:?}", filetype);
                            Err(io::Error::new(io::ErrorKind::Other, "unknown audio file!"))
                        })
                    }
                } else {
                    col.stats.files.faulty += 1;
                    file_stats.faulty += 1;
                    Ok(())
                }
            }
            // FIXME: video in taglib holds also oga which are audio indeed ...
            Some("text") | Some("application") | Some("image") | Some("video") => Ok(()),
            _ => {
                error!("[{:?}]{:?}", prefix, cb.path());
                col.stats.files.other += 1;
                file_stats.other += 1;
                Ok(())
            }
        }
    }

    /// Check the file and retrieve the meta-data info
    fn visit_audio_files(&mut self, cb: &Path, file_stats: &mut FilesStat) -> Result<(), ()> {
        Tag::read_from_path(cb.to_str().unwrap())
            .and_then(|tag| {
                let artist = tag.artist().unwrap_or("");
                let title = tag.title().unwrap_or("");
                let duration = tag.duration().unwrap_or(0);
                let album = tag.album().unwrap_or("");

                self.stats.files.analyzed += 1;
                file_stats.analyzed += 1;

                let path_buffer = cb.to_path_buf();

                let metadata = fs::metadata(cb).unwrap();
                let filesize = metadata.len();
                let permissions = metadata.permissions();

                let possible_entry = FileInfo {
                    path: path_buffer,
                    size: filesize,
                    permissions: permissions,
                };

                // artist + song name is key for bktree
                let key = [artist, title].join(" ");

                let (vec_k, vec_c) = self.bk_tree.find(&key, TOLERANCE);
                if !vec_c.is_empty() {
                    let mut vec_similar = vec![];
                    for (index, similar) in vec_k.iter().enumerate() {
                        let time_distance = similar.duration as i32 - duration as i32;
                        if time_distance.abs() < TIME_TOLERANCE_SEC as i32 {
                            vec_similar.push(vec_c[index]);
                        }
                    }
                    if !vec_similar.is_empty() {
                        trace!(
                            "close: {:?} to {:?}, {} similar",
                            &vec_similar,
                            &key,
                            &vec_k.len()
                        );
                    }
                }

                // todo: decide when to not add and insert then
                self.bk_tree.insert(
                    key.clone(),
                    Box::new(AudioInfo {
                        duration,
                        album: album.to_string(),
                    }),
                );
                Ok(())
            })
            .or_else(|_| {
                self.stats.files.faulty += 1;
                file_stats.faulty += 1;
                Ok(())
            })
    }

    pub fn print_stats(&self) {
        let output_string = format!(
            "This client's id     : {id:}\n\
             pathes/threads       : {nr_pathes:>width$}\n\
             ----------------------     \n\
             analyzed files       : {files_analyzed:>width$}\n\
             searched files       : {files_searched:>width$}\n\
             irrelevant files     : {files_irrelevant:>width$}\n\
             faulty files         : {files_faulty:>width$}\n",
            id = self.who.peer_id.to_string().to_uppercase(),
            nr_pathes = self.stats.threads,
            files_analyzed = self.stats.files.analyzed,
            files_searched = self.stats.files.searched,
            files_irrelevant = self.stats.files.other,
            files_faulty = self.stats.files.faulty, // awesome, really
            width = 5
        );

        info!("{}", output_string);
    }
}
<commit_msg>[collection] removing unnecessary information<commit_after>//! The oldest module, the data module stores all the data needed to collect.
pub mod bktree;
pub mod ipc;

use super::config;
use bktree::BKTree;

use id3::Tag;
use libp2p_core::PeerId;
use std::{
    fs::{self, DirEntry, Permissions}, // directory
    io,                                // reading files
    path::{Path, PathBuf},
    sync::Arc,
};
use tree_magic;

static TOLERANCE: usize = 5;
static TIME_TOLERANCE_SEC: usize = 4;

struct AudioInfo {
    duration: u32,
    album: String,
}

#[allow(dead_code)]
struct Worker {
    /// identify them.
    peer_id: PeerId,
    max_threads: usize,
}

/// # Worker
/// the worker is supposed to be running on different machines
/// with one server and many clients
impl Worker {
    /// # Just new
    /// To identify how to comment
    /// # Arguments
    /// * 'id' - the identification (each will create an own hash)
    /// * 'max_threads' - how many threads can the worker create
    pub fn new(peer_id: PeerId, max_threads: usize) -> Worker {
        Worker {
            peer_id: peer_id,
            max_threads: max_threads,
        }
    }
}

pub struct Collection {
    /// This collection contains all data
    who: Worker,
    bk_tree: BKTree<String, Box<AudioInfo>>,
    stats: Stats,
}
/// Only some statistics
pub struct FilesStat {
    pub analyzed: u32,
    pub faulty: u32,
    pub searched: u32,
    pub other: u32,
}

impl FilesStat {
    /// Adds stats from one to the other,
    /// used for combining different thread
    /// results.
    fn add(&mut self, other: &FilesStat) {
        self.analyzed += other.analyzed;
        self.faulty += other.faulty;
        self.searched += other.searched;
        self.other += other.other;
    }
}

struct Stats {
    files: FilesStat,
    threads: usize,
}

type FileFn = dyn Fn(&mut Collection, &DirEntry, &mut FilesStat) -> io::Result<()>;

impl Collection {
    /// Sets up the whole collection that books all threads.
    pub fn new(peer_id: &PeerId, num_threads: usize) -> Collection {
        Collection {
            who: Worker::new(peer_id.clone(), num_threads),
            bk_tree: BKTree::new(),
            stats: Stats {
                files: FilesStat {
                    analyzed: 0,
                    faulty: 0,
                    searched: 0,
                    other: 0,
                },
                threads: num_threads,
            },
        }
    }

    /// The function that runs from a certain path
    pub fn visit_path(&mut self, dir: &Path, cb: &FileFn) -> io::Result<FilesStat> {
        let mut file_stats = FilesStat {
            analyzed: 0,
            faulty: 0,
            searched: 0,
            other: 0,
        };

        if dir.is_dir() {
            for entry in fs::read_dir(dir)? {
                let mut loop_file_stats = &mut file_stats;

                let entry = entry?;
                let path = entry.path();
                if path.is_dir() {
                    let file_stats_loop = self.visit_path(&path, cb)?;
                    loop_file_stats.add(&file_stats_loop);
                } else {
                    cb(self, &entry, &mut loop_file_stats).or_else(|io_error| {
                        warn!("{:?}", io_error);
                        Err(io_error)
                    })?
                }
            }
        }
        Ok(file_stats)
    }

    /// the function to check all files separately
    pub fn visit_files(
        col: &mut Collection,
        cb: &DirEntry,
        file_stats: &mut FilesStat,
    ) -> io::Result<()> {
        // count stats
        col.stats.files.searched += 1;
        file_stats.searched += 1;

        let filetype = tree_magic::from_filepath(&cb.path());
        let prefix = filetype.split("/").nth(0);
        match prefix {
            Some("audio") => {
                if let Some(suffix) = filetype.split("/").last() {
                    if config::data::IGNORE_AUDIO_FORMATS
                        .iter()
                        .any(|&s| s == suffix)
                    {
                        col.stats.files.other += 1;
                        file_stats.other += 1;
                        Ok(())
                    } else {
                        col.visit_audio_files(&cb.path(), file_stats).or_else(|_| {
                            col.stats.files.faulty += 1;
                            file_stats.faulty += 1;
                            error!("ts: {:?}", filetype);
                            Err(io::Error::new(io::ErrorKind::Other, "unknown audio file!"))
                        })
                    }
                } else {
                    col.stats.files.faulty += 1;
                    file_stats.faulty += 1;
                    Ok(())
                }
            }
            // FIXME: video in taglib holds also oga which are audio indeed ...
            Some("text") | Some("application") | Some("image") | Some("video") => Ok(()),
            _ => {
                error!("[{:?}]{:?}", prefix, cb.path());
                col.stats.files.other += 1;
                file_stats.other += 1;
                Ok(())
            }
        }
    }

    /// Check the file and retrieve the meta-data info
    fn visit_audio_files(&mut self, cb: &Path, file_stats: &mut FilesStat) -> Result<(), ()> {
        Tag::read_from_path(cb.to_str().unwrap())
            .and_then(|tag| {
                let artist = tag.artist().unwrap_or("");
                let title = tag.title().unwrap_or("");
                let duration = tag.duration().unwrap_or(0);
                let album = tag.album().unwrap_or("");

                self.stats.files.analyzed += 1;
                file_stats.analyzed += 1;

                // artist + song name is key for bktree
                let key = [artist, title].join(" ");

                let (vec_k, vec_c) = self.bk_tree.find(&key, TOLERANCE);
                if !vec_c.is_empty() {
                    let mut vec_similar = vec![];
                    for (index, similar) in vec_k.iter().enumerate() {
                        let time_distance = similar.duration as i32 - duration as i32;
                        if time_distance.abs() < TIME_TOLERANCE_SEC as i32 {
                            vec_similar.push(vec_c[index]);
                        }
                    }
                    if !vec_similar.is_empty() {
                        trace!(
                            "close: {:?} to {:?}, {} similar",
                            &vec_similar,
                            &key,
                            &vec_k.len()
                        );
                    }
                }

                // todo: decide when to not add and insert then
                self.bk_tree.insert(
                    key.clone(),
                    Box::new(AudioInfo {
                        duration,
                        album: album.to_string(),
                    }),
                );
                Ok(())
            })
            .or_else(|_| {
                self.stats.files.faulty += 1;
                file_stats.faulty += 1;
                Ok(())
            })
    }

    pub fn print_stats(&self) {
        let output_string = format!(
            "This client's id     : {id:}\n\
             pathes/threads       : {nr_pathes:>width$}\n\
             ----------------------     \n\
             analyzed files       : {files_analyzed:>width$}\n\
             searched files       : {files_searched:>width$}\n\
             irrelevant files     : {files_irrelevant:>width$}\n\
             faulty files         : {files_faulty:>width$}\n",
            id = self.who.peer_id.to_string().to_uppercase(),
            nr_pathes = self.stats.threads,
            files_analyzed = self.stats.files.analyzed,
            files_searched = self.stats.files.searched,
            files_irrelevant = self.stats.files.other,
            files_faulty = self.stats.files.faulty, // awesome, really
            width = 5
        );

        info!("{}", output_string);
    }
}
<|endoftext|>


<commit_before>use std::io::{File, BufferedReader};
use error::{CTResult, CTDatabaseError, CTSyntaxError};
use error::CTError::{DatabaseError, SyntaxError};
use token::Token;
use token::TokenKind::Elem;

#[derive(Show)]
pub struct ElemData {
    short_name: String,
    long_name: String,
    mass: f64,
    atomic_num: u16,
}

pub struct ElemDatabase {
    db: BufferedReader<File>,
}

impl ElemDatabase {
    pub fn open(path: &str) -> CTResult<ElemDatabase> {
        match File::open(&Path::new(path)) {
            Ok(db_file) => Ok(ElemDatabase { db: BufferedReader::new(db_file) }),
            Err(_) => Err(DatabaseError(CTDatabaseError {
                desc: format!("Could not open database file. Expected at: {:?}", path)
            })),
        }
    }

    pub fn get_elem_data(&mut self, elem: &Token) -> CTResult<ElemData> {
        let mut line_iter = self.db.lines();
        let short_name = match elem.tok {
            Elem(ref name) => name.as_slice(),
            _ => unreachable!(),
        };
        // TODO: Make this cleaner, and avoid returns
        loop {
            match line_iter.next() {
                Some(Ok(ref line)) if line.starts_with(short_name) => return decode_line(line),
                Some(Err(_)) => return Err(DatabaseError(CTDatabaseError {
                    desc: "Error reading the database".to_string()
                })),
                None => return Err(SyntaxError(CTSyntaxError {
                    desc: format!("Could not find element: {:?}", short_name),
                    pos: elem.pos,
                    len: elem.len,
                })),
                _ => (),
            }
        }
    }
}

pub fn decode_line(line: &String) -> CTResult<ElemData> {
    let data: Vec<&str> = line.trim().split(';').collect();
    if data.len() < 4 {
        Err(DatabaseError(CTDatabaseError {
            desc: "Missing field in database".to_string()
        }))
    } else {
        let mass = data[1].parse::<f64>();
        let atomic_num = data[3].parse::<u16>();
        if let (Some(m), Some(an)) = (mass, atomic_num) {
            Ok(ElemData {
                short_name: data[0].to_string(),
                long_name: data[2].to_string(),
                mass: m,
                atomic_num: an,
            })
        } else {
            Err(DatabaseError(CTDatabaseError {
                desc: "Field in database corrupted".to_string()
            }))
        }
    }
}<commit_msg>Make ElemData derive PartialEq<commit_after>use std::io::{File, BufferedReader};
use error::{CTResult, CTDatabaseError, CTSyntaxError};
use error::CTError::{DatabaseError, SyntaxError};
use token::Token;
use token::TokenKind::Elem;

#[derive(Show, PartialEq)]
pub struct ElemData {
    short_name: String,
    long_name: String,
    mass: f64,
    atomic_num: u16,
}

pub struct ElemDatabase {
    db: BufferedReader<File>,
}

impl ElemDatabase {
    pub fn open(path: &str) -> CTResult<ElemDatabase> {
        match File::open(&Path::new(path)) {
            Ok(db_file) => Ok(ElemDatabase { db: BufferedReader::new(db_file) }),
            Err(_) => Err(DatabaseError(CTDatabaseError {
                desc: format!("Could not open database file. Expected at: {:?}", path)
            })),
        }
    }

    pub fn get_elem_data(&mut self, elem: &Token) -> CTResult<ElemData> {
        let mut line_iter = self.db.lines();
        let short_name = match elem.tok {
            Elem(ref name) => name.as_slice(),
            _ => unreachable!(),
        };
        // TODO: Make this cleaner, and avoid returns
        loop {
            match line_iter.next() {
                Some(Ok(ref line)) if line.starts_with(short_name) => return decode_line(line),
                Some(Err(_)) => return Err(DatabaseError(CTDatabaseError {
                    desc: "Error reading the database".to_string()
                })),
                None => return Err(SyntaxError(CTSyntaxError {
                    desc: format!("Could not find element: {:?}", short_name),
                    pos: elem.pos,
                    len: elem.len,
                })),
                _ => (),
            }
        }
    }
}

pub fn decode_line(line: &String) -> CTResult<ElemData> {
    let data: Vec<&str> = line.trim().split(';').collect();
    if data.len() < 4 {
        Err(DatabaseError(CTDatabaseError {
            desc: "Missing field in database".to_string()
        }))
    } else {
        let mass = data[1].parse::<f64>();
        let atomic_num = data[3].parse::<u16>();
        if let (Some(m), Some(an)) = (mass, atomic_num) {
            Ok(ElemData {
                short_name: data[0].to_string(),
                long_name: data[2].to_string(),
                mass: m,
                atomic_num: an,
            })
        } else {
            Err(DatabaseError(CTDatabaseError {
                desc: "Field in database corrupted".to_string()
            }))
        }
    }
}<|endoftext|>


<commit_before>use {Byte, Chunk, SChunks};
use client::GetResponse;
use hyper::client::Client;
use hyper::error::Error;
use hyper::header::{ByteRangeSpec, Headers, Range};
use std::cmp::min;
use std::io::Read;
use std::thread;

/// Represents a range between two Byte types
#[derive(Debug, PartialEq)]
struct RangeBytes(Byte, Byte);

/// Function to get the current chunk length, based on the chunk index.
fn get_chunk_length(chunk_index: u64,
                    content_length: Byte,
                    global_chunk_length: Byte)
                    -> Option<RangeBytes> {

    if content_length == 0 || global_chunk_length == 0 {
        return None;
    }

    let b_range: Byte = chunk_index * global_chunk_length;

    if b_range >= (content_length - 1) {
        return None;
    }

    let e_range: Byte = min(content_length - 1,
                            ((chunk_index + 1) * global_chunk_length) - 1);

    Some(RangeBytes(b_range, e_range))

}

/// Function to get the HTTP header to send to the file server, for a chunk (specified by its index)
fn get_header_from_index(chunk_index: u64,
                         content_length: Byte,
                         global_chunk_length: Byte)
                         -> Option<(Headers, Byte)> {

    match get_chunk_length(chunk_index, content_length, global_chunk_length) {
        Some(range) => {
            let mut header = Headers::new();
            header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(range.0, range.1)]));
            Some((header, range.1 - range.0))
        }
        None => None,
    }

}

/// Function to get from the server the content of a chunk.
/// This function returns a Result type - Byte if the content of the header is accessible, an Error type otherwise.
fn download_a_chunk(http_client: &Client,
                    http_header: Headers,
                    chunk_vector: &mut Chunk,
                    url: &str)
                    -> Result<Byte, Error> {

    match http_client.get_http_response_using_headers(url, http_header) {
        Ok(mut body) => {
            match body.read_to_end(chunk_vector) {
                Ok(nb_bytes) => Ok(nb_bytes as u64),
                Err(_) => Ok(0u64),
            }
        }
        Err(http_error) => Err(http_error),
    }

}

/// Function to download each chunk of a remote content (given by its URL).
/// This function takes as parameters:
/// * the remote content length,
/// * a mutable reference to share between threads, which contains each chunk,
/// * the number of chunks that contains the remote content,
/// * the URL of the remote content server.
pub fn download_chunks(content_length: u64,
                       downloaded_chunks: &SChunks,
                       nb_chunks: u64,
                       url: &str) {

    // let mut downloaded_chunks: Arc<Mutex<Chunks>> =
    //     Arc::new(Mutex::new(Chunks::with_capacity(nb_chunks as usize)));
    let global_chunk_length: u64 = (content_length / nb_chunks) + 1;
    let mut jobs = vec![];

    for chunk_index in 0..nb_chunks {

        let (http_header, chunk_length) =
            get_header_from_index(chunk_index, content_length, global_chunk_length).unwrap();
        let mut chunk_content = Chunk::with_capacity(chunk_length as usize);
        let hyper_client = Client::new();
        let url_clone = String::from(url);
        let clone_chunks = downloaded_chunks.clone();

        jobs.push(thread::spawn(move || {
            match download_a_chunk(&hyper_client, http_header, &mut chunk_content, &url_clone) {
                Ok(bytes_written) => {
                    if bytes_written > 0 {
                        let mut shared_clone_chunks = clone_chunks.lock().unwrap();
                        shared_clone_chunks.insert(chunk_index as usize, chunk_content);
                    } else {
                        panic!("The downloaded chunk {} is empty", chunk_index);
                    }
                }
                Err(error) => {
                    panic!("Canno't download the chunk {}, due to error {}",
                           chunk_index,
                           error);
                }
            }
        }));
    }

    for child in jobs {
        let _ = child.join();
    }

}

#[cfg(test)]
mod test_chunk_length {

    use super::get_chunk_length;
    use super::RangeBytes;

    #[test]
    fn wrong_content_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 15, 0));
    }

    #[test]
    fn wrong_global_chunk_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 15));
    }

    #[test]
    fn wrong_length_parameters_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 0));
    }

    #[test]
    fn get_the_first_range_in_chunk() {
        assert_eq!(Some(RangeBytes(0, 249)), get_chunk_length(0, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_chunk() {
        assert_eq!(Some(RangeBytes(750, 999)), get_chunk_length(3, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_shorten_chunk() {
        assert_eq!(Some(RangeBytes(750, 997)), get_chunk_length(3, 998, 250));
    }

    #[test]
    fn wrong_index_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(4, 1000, 250));
    }

}

#[cfg(test)]
mod test_header {

    use super::get_header_from_index;
    use hyper::header::{ByteRangeSpec, Headers, Range};

    #[test]
    fn wrong_chunk_length_should_return_none() {
        assert_eq!(None, get_header_from_index(0, 0, 0));
    }

    #[test]
    fn good_chunk_length_should_return_a_good_header() {
        let mut test_header = Headers::new();
        test_header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(750, 997)]));
        assert_eq!(Some((test_header, 247)), get_header_from_index(3, 998, 250));
    }

}<commit_msg>Functional bahaviour to join threads<commit_after>use {Byte, Chunk, SChunks};
use client::GetResponse;
use hyper::client::Client;
use hyper::error::Error;
use hyper::header::{ByteRangeSpec, Headers, Range};
use std::cmp::min;
use std::io::Read;
use std::thread;

/// Represents a range between two Byte types
#[derive(Debug, PartialEq)]
struct RangeBytes(Byte, Byte);

/// Function to get the current chunk length, based on the chunk index.
fn get_chunk_length(chunk_index: u64,
                    content_length: Byte,
                    global_chunk_length: Byte)
                    -> Option<RangeBytes> {

    if content_length == 0 || global_chunk_length == 0 {
        return None;
    }

    let b_range: Byte = chunk_index * global_chunk_length;

    if b_range >= (content_length - 1) {
        return None;
    }

    let e_range: Byte = min(content_length - 1,
                            ((chunk_index + 1) * global_chunk_length) - 1);

    Some(RangeBytes(b_range, e_range))

}

/// Function to get the HTTP header to send to the file server, for a chunk (specified by its index)
fn get_header_from_index(chunk_index: u64,
                         content_length: Byte,
                         global_chunk_length: Byte)
                         -> Option<(Headers, Byte)> {

    match get_chunk_length(chunk_index, content_length, global_chunk_length) {
        Some(range) => {
            let mut header = Headers::new();
            header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(range.0, range.1)]));
            Some((header, range.1 - range.0))
        }
        None => None,
    }

}

/// Function to get from the server the content of a chunk.
/// This function returns a Result type - Byte if the content of the header is accessible, an Error type otherwise.
fn download_a_chunk(http_client: &Client,
                    http_header: Headers,
                    chunk_vector: &mut Chunk,
                    url: &str)
                    -> Result<Byte, Error> {

    match http_client.get_http_response_using_headers(url, http_header) {
        Ok(mut body) => {
            match body.read_to_end(chunk_vector) {
                Ok(nb_bytes) => Ok(nb_bytes as u64),
                Err(_) => Ok(0u64),
            }
        }
        Err(http_error) => Err(http_error),
    }

}

/// Function to download each chunk of a remote content (given by its URL).
/// This function takes as parameters:
/// * the remote content length,
/// * a mutable reference to share between threads, which contains each chunk,
/// * the number of chunks that contains the remote content,
/// * the URL of the remote content server.
pub fn download_chunks(content_length: u64,
                       downloaded_chunks: &SChunks,
                       nb_chunks: u64,
                       url: &str) {

    // let mut downloaded_chunks: Arc<Mutex<Chunks>> =
    //     Arc::new(Mutex::new(Chunks::with_capacity(nb_chunks as usize)));
    let global_chunk_length: u64 = (content_length / nb_chunks) + 1;
    let mut jobs = vec![];

    for chunk_index in 0..nb_chunks {

        let (http_header, chunk_length) =
            get_header_from_index(chunk_index, content_length, global_chunk_length).unwrap();
        let mut chunk_content = Chunk::with_capacity(chunk_length as usize);
        let hyper_client = Client::new();
        let url_clone = String::from(url);
        let clone_chunks = downloaded_chunks.clone();

        jobs.push(thread::spawn(move || {
            match download_a_chunk(&hyper_client, http_header, &mut chunk_content, &url_clone) {
                Ok(bytes_written) => {
                    if bytes_written > 0 {
                        let mut shared_clone_chunks = clone_chunks.lock().unwrap();
                        shared_clone_chunks.insert(chunk_index as usize, chunk_content);
                    } else {
                        panic!("The downloaded chunk {} is empty", chunk_index);
                    }
                }
                Err(error) => {
                    panic!("Canno't download the chunk {}, due to error {}",
                           chunk_index,
                           error);
                }
            }
        }));
    }

    jobs.into_iter().map(|child| { child.join() });

}

#[cfg(test)]
mod test_chunk_length {

    use super::get_chunk_length;
    use super::RangeBytes;

    #[test]
    fn wrong_content_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 15, 0));
    }

    #[test]
    fn wrong_global_chunk_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 15));
    }

    #[test]
    fn wrong_length_parameters_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 0));
    }

    #[test]
    fn get_the_first_range_in_chunk() {
        assert_eq!(Some(RangeBytes(0, 249)), get_chunk_length(0, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_chunk() {
        assert_eq!(Some(RangeBytes(750, 999)), get_chunk_length(3, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_shorten_chunk() {
        assert_eq!(Some(RangeBytes(750, 997)), get_chunk_length(3, 998, 250));
    }

    #[test]
    fn wrong_index_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(4, 1000, 250));
    }

}

#[cfg(test)]
mod test_header {

    use super::get_header_from_index;
    use hyper::header::{ByteRangeSpec, Headers, Range};

    #[test]
    fn wrong_chunk_length_should_return_none() {
        assert_eq!(None, get_header_from_index(0, 0, 0));
    }

    #[test]
    fn good_chunk_length_should_return_a_good_header() {
        let mut test_header = Headers::new();
        test_header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(750, 997)]));
        assert_eq!(Some((test_header, 247)), get_header_from_index(3, 998, 250));
    }

}<|endoftext|>


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

use libc::{self, c_char, c_void};
use std::ffi::CStr;

pub fn error_message(ptr: *const c_char) -> String {
    let cstr = unsafe { CStr::from_ptr(ptr as *const _) };
    let s = String::from_utf8_lossy(cstr.to_bytes()).into();
    unsafe {
        libc::free(ptr as *mut c_void);
    }
    s
}

macro_rules! ffi_try {
    ( $($function:ident)::*( $( $arg:expr ),* ) ) => ({
        let mut err: *mut ::libc::c_char = ::std::ptr::null_mut();
        let result = $($function)::*($($arg),*, &mut err);
        if !err.is_null() {
            return Err(Error::new($crate::ffi_util::error_message(err)));
        }
        result
    })
}
<commit_msg>Fix compile failed in stable/beta<commit_after>// Copyright 2016 Alex Regueiro
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use libc::{self, c_char, c_void};
use std::ffi::CStr;

pub fn error_message(ptr: *const c_char) -> String {
    let cstr = unsafe { CStr::from_ptr(ptr as *const _) };
    let s = String::from_utf8_lossy(cstr.to_bytes()).into_owned();
    unsafe {
        libc::free(ptr as *mut c_void);
    }
    s
}

macro_rules! ffi_try {
    ( $($function:ident)::*( $( $arg:expr ),* ) ) => ({
        let mut err: *mut ::libc::c_char = ::std::ptr::null_mut();
        let result = $($function)::*($($arg),*, &mut err);
        if !err.is_null() {
            return Err(Error::new($crate::ffi_util::error_message(err)));
        }
        result
    })
}
<|endoftext|>


<commit_before>///  Specifies how to render the junction of two lines when stroking.
///
/// The default line join style is CAIRO_LINE_JOIN_MITER.
///
/// CAIRO_LINE_JOIN_MITER
/// 	use a sharp (angled) corner, see cairo_set_miter_limit() (Since 1.0)
///
/// CAIRO_LINE_JOIN_ROUND
/// 	use a rounded join, the center of the circle is the joint point (Since 1.0)
///
/// CAIRO_LINE_JOIN_BEVEL
///	use a cut-off join, the join is cut off at half the line width from the joint point (Since 1.0)
///
/// Since 1.0
#[repr(i32)]
pub enum LineJoin {
  Miter = 0,
  Round = 1,
  Bevel = 2
}
<commit_msg>Copied Cairo documentation for line join<commit_after>//! Descirbe how to render the junction of two lines

///  Specifies how to render the junction of two lines when stroking.
///
/// The default line join style is CAIRO_LINE_JOIN_MITER.
///
/// Since 1.0
#[repr(i32)]
pub enum LineJoin {
  /// use a sharp (angled) corner, see cairo_set_miter_limit() (Since 1.0)
  Miter = 0,
  /// use a rounded join, the center of the circle is the joint point (Since 1.0)
  Round = 1,
  /// use a cut-off join, the join is cut off at half the line width from the joint point (Since 1.0)
  Bevel = 2
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;
use std::collections::HashMap;
use std::str::FromStr;
use toml::Value;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum GStatus {
    Manual,     //already generated
    Generate,
    Comment,
    Ignore,
}

impl Default for GStatus {
    fn default() -> GStatus { GStatus::Ignore }
}

impl FromStr for GStatus {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "manual" => Ok(GStatus::Manual),
            "generate" => Ok(GStatus::Generate),
            "comment" => Ok(GStatus::Comment),
            "ignore" => Ok(GStatus::Ignore),
            _ => Err("Wrong object status".into())
        }
    }
}

/// Info about GObject descendant
#[derive(Clone, Debug)]
pub struct GObject {
    pub name: String,
    pub status: GStatus,
}

impl Default for GObject {
    fn default() -> GObject {
        GObject {
            name: "Default".into(),
            status: Default::default(),
        }
    }
}

//TODO: ?change to HashMap<String, GStatus>
pub type GObjects =  HashMap<String, GObject>;

pub fn parse_toml(toml_objects: &Value) -> GObjects {
    let mut objects = GObjects::new();
    for toml_object in toml_objects.as_slice().unwrap() {
        let gobject = parse_object(toml_object);
        objects.insert(gobject.name.clone(), gobject);
    }
    objects
}

fn parse_object(toml_object: &Value) -> GObject {
    let name = toml_object.lookup("name").expect("Object name not defined")
        .as_str().unwrap().into();

    let status = match toml_object.lookup("status") {
        Some(value) => GStatus::from_str(value.as_str().unwrap()).unwrap_or(Default::default()),
        None => Default::default(),
    };
    GObject { name: name, status: status }
}

pub fn parse_status_shorthands(objects: &mut GObjects, toml: &Value) {
    use self::GStatus::*;
    for &status in [Ignore].iter() {
        parse_status_shorthand(objects, status, toml);
    }
}

fn parse_status_shorthand(objects: &mut GObjects, status: GStatus, toml: &Value) {
    let name = format!("options.{:?}", status).to_ascii_lowercase();
    toml.lookup(&name).map(|a| a.as_slice().unwrap())
        .map(|a| for name_ in a.iter().map(|s| s.as_str().unwrap()) {
        match objects.get(name_) {
            None => {
                objects.insert(name_.into(), GObject {
                    name: name_.into(),
                    status: GStatus::Ignore,
                });
            },
            Some(_) => panic!("Bad name in {}: {} already defined", name, name_),
        }
    });
}
<commit_msg>Add shorthand for all GStatuses<commit_after>use std::ascii::AsciiExt;
use std::collections::HashMap;
use std::str::FromStr;
use toml::Value;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum GStatus {
    Manual,     //already generated
    Generate,
    Comment,
    Ignore,
}

impl Default for GStatus {
    fn default() -> GStatus { GStatus::Ignore }
}

impl FromStr for GStatus {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "manual" => Ok(GStatus::Manual),
            "generate" => Ok(GStatus::Generate),
            "comment" => Ok(GStatus::Comment),
            "ignore" => Ok(GStatus::Ignore),
            _ => Err("Wrong object status".into())
        }
    }
}

/// Info about GObject descendant
#[derive(Clone, Debug)]
pub struct GObject {
    pub name: String,
    pub status: GStatus,
}

impl Default for GObject {
    fn default() -> GObject {
        GObject {
            name: "Default".into(),
            status: Default::default(),
        }
    }
}

//TODO: ?change to HashMap<String, GStatus>
pub type GObjects =  HashMap<String, GObject>;

pub fn parse_toml(toml_objects: &Value) -> GObjects {
    let mut objects = GObjects::new();
    for toml_object in toml_objects.as_slice().unwrap() {
        let gobject = parse_object(toml_object);
        objects.insert(gobject.name.clone(), gobject);
    }
    objects
}

fn parse_object(toml_object: &Value) -> GObject {
    let name = toml_object.lookup("name").expect("Object name not defined")
        .as_str().unwrap().into();

    let status = match toml_object.lookup("status") {
        Some(value) => GStatus::from_str(value.as_str().unwrap()).unwrap_or(Default::default()),
        None => Default::default(),
    };
    GObject { name: name, status: status }
}

pub fn parse_status_shorthands(objects: &mut GObjects, toml: &Value) {
    use self::GStatus::*;
    for &status in [Manual, Generate, Comment, Ignore].iter() {
        parse_status_shorthand(objects, status, toml);
    }
}

fn parse_status_shorthand(objects: &mut GObjects, status: GStatus, toml: &Value) {
    let name = format!("options.{:?}", status).to_ascii_lowercase();
    toml.lookup(&name).map(|a| a.as_slice().unwrap())
        .map(|a| for name_ in a.iter().map(|s| s.as_str().unwrap()) {
        match objects.get(name_) {
            None => {
                objects.insert(name_.into(), GObject {
                    name: name_.into(),
                    status: GStatus::Ignore,
                });
            },
            Some(_) => panic!("Bad name in {}: {} already defined", name, name_),
        }
    });
}
<|endoftext|>


<commit_before>// Copyright 2016 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![allow(dead_code)]
#![allow(non_snake_case)]
grammar! bonsai2 {
  // #![show_api]

  program = spacing item+

  item
    = stmt_list
    / FN identifier LPAREN list_ident RPAREN LBRACE stmt_list RBRACE

  list_ident = identifier (COMMA identifier)* / ""

  stmt_list = stmt+

  stmt
    = PAR BARBAR? stmt_list (BARBAR stmt_list)* END
    / SPACE BARBAR? stmt_list (BARBAR stmt_list)* END
    / LET TRANSIENT? identifier (COLON java_ty)? IN spacetime EQ expr SEMI_COLON
    / LET identifier EQ identifier LEFT_ARROW expr SEMI_COLON
    / WHEN entailment LBRACE stmt_list RBRACE
    / PAUSE SEMI_COLON
    / TRAP identifier LBRACE stmt_list RBRACE
    / EXIT identifier SEMI_COLON
    / LOOP LBRACE stmt_list RBRACE
    / identifier LPAREN list_ident RPAREN SEMI_COLON
    / var LEFT_ARROW expr SEMI_COLON

  expr
    = java_expr
    / stream_var

  java_ty
    = identifier

  // We consider single identifier to be part of bonsai language.
  java_expr
    = NEW identifier LPAREN list_expr RPAREN
    / identifier (DOT identifier (LPAREN list_expr RPAREN)?)+
    / number
    / string_literal

  list_expr
    = expr (COMMA expr)*
    / ""

  entailment = stream_var ENTAILMENT expr

  stream_var = PRE* identifier (LBRACKET list_stream_var RBRACKET)?
  list_stream_var = stream_var (COMMA stream_var)*

  var = identifier (LBRACKET list_var RBRACKET)?
  list_var = var (COMMA var)*

  spacetime = WORLD_LINE / SINGLE_TIME / SINGLE_SPACE / identifier

  identifier = !digit !(keyword !ident_char) ident_char+ spacing -> (^) //> to_string
  ident_char = ["a-zA-Z0-9_"]

  number = digits -> (^) //> make_number
  digits = digit+ (UNDERSCORE* digit)* //> concat
  digit = ["0-9"]

  // TODO: proper escape mechanism
  string_literal = "\"" (!"\"" .)* "\"" -> (^)

  keyword
    = "let" / "fn" / "par" / "space" / "end" / "transient" / "pre" / "when"
    / "loop" / "pause" / "trap" / "exit" / "in" / "world_line"
    / "single_time" / "single_space" / "bot" / "top" / java_kw
  kw_tail = !ident_char spacing

  LET = "let" kw_tail
  FN = "fn" kw_tail
  PAR = "par" kw_tail
  SPACE = "space" kw_tail
  END = "end" kw_tail
  TRANSIENT = "transient" kw_tail //-> ()
  PRE = "pre" kw_tail
  WHEN = "when" kw_tail
  LOOP = "loop" kw_tail
  PAUSE = "pause" kw_tail
  TRAP = "trap" kw_tail
  EXIT = "exit" kw_tail
  IN = "in" kw_tail
  WORLD_LINE = "world_line" kw_tail
  SINGLE_TIME = "single_time" kw_tail
  SINGLE_SPACE = "single_space" kw_tail
  BOT = "bot" kw_tail
  TOP = "top" kw_tail

  UNDERSCORE = "_"
  DOTDOT = ".." spacing
  SEMI_COLON = ";" spacing
  COLON = ":" spacing
  EQ = "=" spacing
  COMMA = "," spacing
  DOT = "." spacing
  BARBAR = "||" spacing
  ENTAILMENT = "|=" spacing
  LEFT_ARROW = "<-" spacing
  BIND_OP = "=" spacing
  ADD_OP = "+" spacing
  SUB_OP = "-" spacing
  MUL_OP = "*" spacing
  LPAREN = "(" spacing
  RPAREN = ")" spacing
  LBRACKET = "[" spacing
  RBRACKET = "]" spacing
  LBRACE = "{" spacing
  RBRACE = "}" spacing

  spacing = [" \n\r\t"]* -> (^)

  // Java keyword
  java_kw = "new"
  NEW = "new" kw_tail

  // fn to_string(raw_text: Vec<char>) -> String {
  //   raw_text.into_iter().collect()
  // }
}

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

  #[test]
  fn test_grammar()
  {
    let state = bonsai2::recognize_program("
      let variables in world_line = new VarStore();
      let constraints in world_line = new ConstraintStore(variables);
      let consistent in single_time = new Consistent();

      fn first_fail_middle() {
        let var in single_space = new FirstFail();
        let val in single_space = new IntDomainMin();
        loop {
          when consistent |= Consistent.Unknown {
            let x in variables = var.getVariable(variables.vars());
            let mid:int in single_time = val.selectValue(variables[x]);
            space
            || constraints[variables] <- new ArithCons(x, \">\", mid);
            || constraints[variables] <- new ArithCons(x, \"<=\", mid);
            end
          }
          pause;
        }
      }

      fn model() {
        let queen1 = variables <- new IntDomain(0,1);
        let queen2 = variables <- new IntDomain(0,1);

        constraints[variables] <- new ArithCons(queen1, \"!=\", queen2);
        let fake in single_time = new Fake(pre pre queens1[pre queens, queen2], new Object());
      }

      fn propagation() {
        loop {
          consistent <- Solver.propagate(constraints, variables);
          pause;
        }
      }

      fn one_solution() {
        loop {
          when consistent |= Consistent.True {
            exit FoundSolution;
          }
          pause;
        }
      }

      fn engine() {
        trap FoundSolution {
          par
          || fail_first_middle();
          || propagation();
          || one_solution();
          end
        }
      }

     par
     || model();
     || engine();
     end
     ".into_state());
    let result = state.into_result();
    println!("{:?}", result);
    match result {
      Success(_) => (),
      Partial(_, _)
    | Failure(_) => assert!(false)
    };
  }
}
<commit_msg>[Grammar][AST] Plug the AST into the grammar.<commit_after>// Copyright 2016 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![allow(dead_code)]
#![allow(non_snake_case)]
grammar! bonsai2 {
  // #![show_api]

  pub type Program = Vec<Item>;

  pub enum Item {
    Statement(Stmt),
    Fn(Function)
  }

  pub type Block = Vec<Stmt>;
  pub type JavaTy = String;

  pub struct Function {
    name: String,
    params: Vec<String>,
    body: Block
  }

  pub enum Stmt {
    Par(Vec<Block>),
    Space(Vec<Block>),
    Let(LetDecl),
    LetInStore(String, String, Expr),
    When(EntailmentRel, Block),
    Pause,
    Trap(String, Block),
    Exit(String),
    Loop(Block),
    FnCall(String, Vec<String>),
    Tell(Var, Expr)
  }

  pub struct LetDecl {
    transient: bool,
    var: String,
    java_ty: Option<JavaTy>,
    spacetime: Spacetime,
    expr: Expr
  }

  pub struct EntailmentRel {
    left: StreamVar,
    right: Expr
  }

  pub struct Var {
    name: String,
    args: Vec<Var>
  }

  pub struct StreamVar {
    name: String,
    past: usize,
    args: Vec<StreamVar>
  }

  pub enum Spacetime {
    SingleSpace,
    SingleTime,
    WorldLine,
    Location(String)
  }

  pub enum Expr {
    JavaNew(String, Vec<Expr>),
    JavaObjectCall(String, Vec<JavaCall>),
    Number(u64),
    StringLiteral(String),
    Variable(StreamVar)
  }

  pub struct JavaCall {
    property: String, // can be an attribute or a method.
    args: Vec<Expr>
  }

  use std::str::FromStr;

  program = spacing item+

  item
    = stmt > make_stmt_item
    / FN identifier LPAREN list_ident RPAREN block > make_function_item

  fn make_stmt_item(stmt: Stmt) -> Item {
    Item::Statement(stmt)
  }

  fn make_function_item(name: String, params: Vec<String>, body: Block) -> Item {
    Item::Fn(Function {
      name: name,
      params: params,
      body: body
    })
  }

  list_ident
    = identifier (COMMA identifier)* > make_list_ident
    / "" > empty_ident_list

  fn make_list_ident(first: String, rest: Vec<String>) -> Vec<String> {
    extend_front(first, rest)
  }

  fn empty_ident_list() -> Vec<String> {
    vec![]
  }

  stmt_list = stmt+

  block = LBRACE stmt_list RBRACE

  stmt
    = PAR BARBAR? stmt_list (BARBAR stmt_list)* END > make_par
    / SPACE BARBAR? stmt_list (BARBAR stmt_list)* END > make_space
    / LET TRANSIENT? identifier (COLON java_ty)? IN spacetime EQ expr SEMI_COLON > make_let
    / LET identifier EQ identifier LEFT_ARROW expr SEMI_COLON > make_let_in_store
    / WHEN entailment block > make_when
    / PAUSE SEMI_COLON > make_pause
    / TRAP identifier block > make_trap
    / EXIT identifier SEMI_COLON > make_exit
    / LOOP block > make_loop
    / identifier LPAREN list_ident RPAREN SEMI_COLON > make_fn_call
    / var LEFT_ARROW expr SEMI_COLON > make_tell

  fn make_par(first: Block, rest: Vec<Block>) -> Stmt {
    Stmt::Par(extend_front(first, rest))
  }

  fn make_space(first: Block, rest: Vec<Block>) -> Stmt {
    Stmt::Space(extend_front(first, rest))
  }

  fn make_let(transient: Option<()>, var_name: String,
    java_ty: Option<JavaTy>, spacetime: Spacetime, expr: Expr) -> Stmt
  {
    let let_decl = LetDecl {
      transient: transient.is_some(),
      var: var_name,
      java_ty: java_ty,
      spacetime: spacetime,
      expr: expr
    };
    Stmt::Let(let_decl)
  }

  fn make_let_in_store(location: String, store: String, expr: Expr) -> Stmt {
    Stmt::LetInStore(location, store, expr)
  }

  fn make_when(entailment: EntailmentRel, body: Block) -> Stmt {
    Stmt::When(entailment, body)
  }

  fn make_pause() -> Stmt {
    Stmt::Pause
  }

  fn make_trap(name: String, block: Block) -> Stmt {
    Stmt::Trap(name, block)
  }

  fn make_exit(name: String) -> Stmt {
    Stmt::Exit(name)
  }

  fn make_loop(block: Block) -> Stmt {
    Stmt::Loop(block)
  }

  fn make_fn_call(fn_name: String, args: Vec<String>) -> Stmt {
    Stmt::FnCall(fn_name, args)
  }

  fn make_tell(var: Var, expr: Expr) -> Stmt {
    Stmt::Tell(var, expr)
  }

  expr
    = java_expr
    / stream_var > make_stream_var_expr

  fn make_stream_var_expr(var: StreamVar) -> Expr { Expr::Variable(var) }

  java_ty
    = identifier

  // We consider single identifier to be part of bonsai language.
  java_expr
    = NEW identifier LPAREN list_expr RPAREN > java_new
    / identifier java_call+ > java_object_calls
    / number > make_number_expr
    / string_literal > make_string_literal

  fn java_new(class_name: String, args: Vec<Expr>) -> Expr {
    Expr::JavaNew(class_name, args)
  }

  fn java_object_calls(object: String, calls: Vec<JavaCall>) -> Expr {
    Expr::JavaObjectCall(object, calls)
  }

  fn make_number_expr(n: u64) -> Expr { Expr::Number(n) }
  fn make_string_literal(lit: String) -> Expr { Expr::StringLiteral(lit) }

  java_call = DOT identifier (LPAREN list_expr RPAREN)? > make_java_call

  fn make_java_call(property: String, args: Option<Vec<Expr>>) -> JavaCall {
    JavaCall {
      property: property,
      args: args.unwrap_or(vec![])
    }
  }

  list_expr
    = expr (COMMA expr)* > make_list_expr
    / "" > empty_expr_list

  fn make_list_expr(first: Expr, rest: Vec<Expr>) -> Vec<Expr> {
    extend_front(first, rest)
  }

  fn empty_expr_list() -> Vec<Expr> {
    vec![]
  }

  entailment = stream_var ENTAILMENT expr > make_entailment_rel

  fn make_entailment_rel(left: StreamVar, right: Expr) -> EntailmentRel {
    EntailmentRel {
      left: left,
      right: right
    }
  }

  stream_var = PRE* identifier (LBRACKET list_stream_var RBRACKET)? > make_stream_var
  list_stream_var = stream_var (COMMA stream_var)* > concat_list_stream_var

  fn make_stream_var(past: Vec<()>, name: String, args: Option<Vec<StreamVar>>) -> StreamVar {
    StreamVar {
      name: name,
      past: past.len(),
      args: args.unwrap_or(vec![])
    }
  }

  fn concat_list_stream_var(first: StreamVar, rest: Vec<StreamVar>) -> Vec<StreamVar> {
    extend_front(first, rest)
  }

  var = identifier (LBRACKET list_var RBRACKET)? > make_var
  list_var = var (COMMA var)* > concat_list_var

  fn make_var(name: String, args: Option<Vec<Var>>) -> Var {
    Var {
      name: name,
      args: args.unwrap_or(vec![])
    }
  }

  fn concat_list_var(first: Var, rest: Vec<Var>) -> Vec<Var> {
    extend_front(first, rest)
  }

  spacetime
    = WORLD_LINE > world_line
    / SINGLE_TIME > single_time
    / SINGLE_SPACE > single_space
    / identifier > location_spacetime

  fn world_line() -> Spacetime { Spacetime::WorldLine }
  fn single_time() -> Spacetime { Spacetime::SingleTime }
  fn single_space() -> Spacetime { Spacetime::SingleSpace }
  fn location_spacetime(loc: String) -> Spacetime { Spacetime::Location(loc) }

  identifier = !digit !(keyword !ident_char) ident_char+ spacing > to_string
  ident_char = ["a-zA-Z0-9_"]

  number = digits > make_number
  digits = digit+ (UNDERSCORE* digit)* > concat
  digit = ["0-9"]

  // TODO: proper escape mechanism
  string_literal = "\"" (!"\"" .)* "\"" > to_string

  keyword
    = "let" / "fn" / "par" / "space" / "end" / "transient" / "pre" / "when"
    / "loop" / "pause" / "trap" / "exit" / "in" / "world_line"
    / "single_time" / "single_space" / "bot" / "top" / java_kw
  kw_tail = !ident_char spacing

  LET = "let" kw_tail
  FN = "fn" kw_tail
  PAR = "par" kw_tail
  SPACE = "space" kw_tail
  END = "end" kw_tail
  TRANSIENT = "transient" kw_tail -> ()
  PRE = "pre" kw_tail -> ()
  WHEN = "when" kw_tail
  LOOP = "loop" kw_tail
  PAUSE = "pause" kw_tail
  TRAP = "trap" kw_tail
  EXIT = "exit" kw_tail
  IN = "in" kw_tail
  WORLD_LINE = "world_line" kw_tail
  SINGLE_TIME = "single_time" kw_tail
  SINGLE_SPACE = "single_space" kw_tail
  BOT = "bot" kw_tail
  TOP = "top" kw_tail

  UNDERSCORE = "_"
  DOTDOT = ".." spacing
  SEMI_COLON = ";" spacing
  COLON = ":" spacing
  EQ = "=" spacing
  COMMA = "," spacing
  DOT = "." spacing
  BARBAR = "||" spacing
  ENTAILMENT = "|=" spacing
  LEFT_ARROW = "<-" spacing
  BIND_OP = "=" spacing
  ADD_OP = "+" spacing
  SUB_OP = "-" spacing
  MUL_OP = "*" spacing
  LPAREN = "(" spacing
  RPAREN = ")" spacing
  LBRACKET = "[" spacing
  RBRACKET = "]" spacing
  LBRACE = "{" spacing
  RBRACE = "}" spacing

  spacing = [" \n\r\t"]* -> (^)

  // Java keyword
  java_kw = "new"
  NEW = "new" kw_tail

  fn to_string(raw_text: Vec<char>) -> String {
    raw_text.into_iter().collect()
  }

  fn concat(mut x: Vec<char>, y: Vec<char>) -> Vec<char> {
    x.extend(y.into_iter());
    x
  }

  fn make_number(raw_number: Vec<char>) -> u64 {
    match u64::from_str(&*to_string(raw_number)).ok() {
      Some(x) => x,
      None => panic!("int literal is too large")
    }
  }

  fn extend_front<T>(first: T, rest: Vec<T>) -> Vec<T> {
    let mut r = vec![first];
    r.extend(rest.into_iter());
    r
  }
}

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

  #[test]
  fn test_grammar()
  {
    let state = bonsai2::recognize_program("
      let variables in world_line = new VarStore();
      let constraints in world_line = new ConstraintStore(variables);
      let consistent in single_time = new Consistent();

      fn first_fail_middle() {
        let var in single_space = new FirstFail();
        let val in single_space = new IntDomainMin();
        loop {
          when consistent |= Consistent.Unknown {
            let x in variables = var.getVariable(variables.vars());
            let mid:int in single_time = val.selectValue(variables[x]);
            space
            || constraints[variables] <- new ArithCons(x, \">\", mid);
            || constraints[variables] <- new ArithCons(x, \"<=\", mid);
            end
          }
          pause;
        }
      }

      fn model() {
        let queen1 = variables <- new IntDomain(0,1);
        let queen2 = variables <- new IntDomain(0,1);

        constraints[variables] <- new ArithCons(queen1, \"!=\", queen2);
        let fake in single_time = new Fake(pre pre queens1[pre queens, queen2], new Object());
      }

      fn propagation() {
        loop {
          consistent <- Solver.propagate(constraints, variables);
          pause;
        }
      }

      fn one_solution() {
        loop {
          when consistent |= Consistent.True {
            exit FoundSolution;
          }
          pause;
        }
      }

      fn engine() {
        trap FoundSolution {
          par
          || fail_first_middle();
          || propagation();
          || one_solution();
          end
        }
      }

     par
     || model();
     || engine();
     end
     ".into_state());
    let result = state.into_result();
    println!("{:?}", result);
    match result {
      Success(_) => (),
      Partial(_, _)
    | Failure(_) => assert!(false)
    };
  }
}
<|endoftext|>


<commit_before>/// FLASHCALW Driver for the SAM4L.

use helpers::*;
use core::mem;

use pm;

// Listing of the FLASHCALW register memory map.
// Section 14.10 of the datasheet
#[repr(C, packed)]
#[allow(dead_code)]
struct Registers {
    control:                          usize,
    command:                          usize,
    status:                           usize,
    parameter:                        usize,
    version:                          usize,
    general_purpose_fuse_register_hi: usize,
    general_purpose_fuse_register_lo: usize,
}

const FLASHCALW_BASE_ADDRS : *mut Registers = 0x400A0000 as *mut Registers;

// This is the pico cache registers...
// TODO: does this get it's own driver... yea....
/*
struct Picocache_Registers {
    picocache_control:                      usize,
    picocache_status:                       usize,
    picocache_maintenance_register_0:       usize,
    picocache_maintenance_register_1:       usize,
    picocache_montior_configuration:        usize,
    picocache_monitor_enable:               usize,
    picocache_monitor_control:              usize,
    picocache_monitor_status:               usize,
    version:                                usize
}
*/

// There are 18 recognized commands possible to command the flash
// Table 14-5.
#[derive(Clone, Copy)]
pub enum FlashCMD {
    NOP,
    WP,
    EP,
    CPB,
    LP,
    UP,
    EA,
    WGPB,
    EGPB,
    SSB,
    PGPFB,
    EAGPF,
    QPR,
    WUP,
    EUP,
    QPRUP,
    HSEN,
    HSDIS,
}

//The two Flash speeds
#[derive(Clone, Copy)]
pub enum Speed {
    Standard,
    HighSpeed
}

// The FLASHCALW controller
//TODO: finishing beefing up...
pub struct FLASHCALW {
    registers: *mut Registers,
    // might make these more specific
    ahb_clock: pm::Clock,
    hramc1_clock: pm::Clock,
    pb_clock: pm::Clock,
    //client: TakeCell...

}

//static instance for the board. Only one FLASHCALW needed / on board.
pub static mut flash_controller : FLASHCALW =
    FLASHCALW::new(FLASHCALW_BASE_ADDRS, pm::HSBClock::FLASHCALW,
        pm::HSBClock::FLASHCALW, pm::PBBClock::FLASHCALW);

// Few constants relating to module configuration.
const FLASH_PAGE_SIZE : usize = 512;
const FLASH_NB_OF_REGIONS : usize = 16;
const FLASHCALW_REGIONS : usize = FLASH_NB_OF_REGIONS;

// TODO: should export this to a board specific module or so... something that gives me size.
const FLASHCALW_SIZE : usize = 512;

impl FLASHCALW {
    const fn new(base_addr: *mut Registers, ahb_clk: pm::HSBClock,
    hramc1_clk: pm::HSBClock, pb_clk: pm::PBBClock) -> FLASHCALW {
        FLASHCALW {
            registers: base_addr,
            ahb_clock: pm::Clock::HSB(ahb_clk),
            hramc1_clock: pm::Clock::HSB(hramc1_clk),
            pb_clock: pm::Clock::HSB(pb_clk),
        }
    }

    /// FLASH properties.
    pub fn get_flash_size(&self) -> u32 {
        FLASHCALW_SIZE
    }

    pub fn get_page_count(&self) -> u32 {
        flashcalw_get_flash_size() / FLASH_PAGE_SIZE
    }

    pub fn get_page_count_per_region(&self) -> u32 {
        flashcalw_get_page_count() / FLASH_NB_OF_REGIONS
    }

    pub fn get_page_number(&self) -> u32 {
        1
        // DUMMY IMPLEMENTATION
    }

    // TODO: implement get_page_number().
    pub fn get_page_region(&self, page_number : i32) -> u32 {
        (if page_number >= 0
            { page_number }
        else
            { flashcalw_get_page_number() as i32 }
        / flashcalw_get_page_count_per_region())
    }

    pub fn get_region_first_page_number(&self, region : u32) -> u32 {
        region * flashcalw_get_page_count_per_region()
    }

    /// FLASHC Control
        //TODO:

    ///FLASHCALW Protection Mechanisms
    pub fn is_security_bit_active(&self) -> bool {
        //think about this more ( get a better design hmmm...)
        (self.registers.status & 0x16) == 1
    }

    pub fn set_security_bit(&self) {
        self.registers.status |=
    }

}

<commit_msg>implemented FLASHCALW protection mechanisms<commit_after>/// FLASHCALW Driver for the SAM4L.

use helpers::*;
use core::mem;

use pm;

// Listing of the FLASHCALW register memory map.
// Section 14.10 of the datasheet
#[repr(C, packed)]
#[allow(dead_code)]
struct Registers {
    control:                          usize,
    command:                          usize,
    status:                           usize,
    parameter:                        usize,
    version:                          usize,
    general_purpose_fuse_register_hi: usize,
    general_purpose_fuse_register_lo: usize,
}

const FLASHCALW_BASE_ADDRS : *mut Registers = 0x400A0000 as *mut Registers;

// This is the pico cache registers...
// TODO: does this get it's own driver... yea....
/*
struct Picocache_Registers {
    picocache_control:                      usize,
    picocache_status:                       usize,
    picocache_maintenance_register_0:       usize,
    picocache_maintenance_register_1:       usize,
    picocache_montior_configuration:        usize,
    picocache_monitor_enable:               usize,
    picocache_monitor_control:              usize,
    picocache_monitor_status:               usize,
    version:                                usize
}
*/

// There are 18 recognized commands possible to command the flash
// Table 14-5.
#[derive(Clone, Copy)]
pub enum FlashCMD {
    NOP,
    WP,
    EP,
    CPB,
    LP,
    UP,
    EA,
    WGPB,
    EGPB,
    SSB,
    PGPFB,
    EAGPF,
    QPR,
    WUP,
    EUP,
    QPRUP,
    HSEN,
    HSDIS,
}

//The two Flash speeds
#[derive(Clone, Copy)]
pub enum Speed {
    Standard,
    HighSpeed
}

// The FLASHCALW controller
//TODO: finishing beefing up...
pub struct FLASHCALW {
    registers: *mut Registers,
    // might make these more specific
    ahb_clock: pm::Clock,
    hramc1_clock: pm::Clock,
    pb_clock: pm::Clock,
    //client: TakeCell...

}

//static instance for the board. Only one FLASHCALW on chip.
pub static mut flash_controller : FLASHCALW =
    FLASHCALW::new(FLASHCALW_BASE_ADDRS, pm::HSBClock::FLASHCALW,
        pm::HSBClock::FLASHCALW, pm::PBBClock::FLASHCALW);

// Few constants relating to module configuration.
const FLASH_PAGE_SIZE : usize = 512;
const FLASH_NB_OF_REGIONS : usize = 16;
const FLASHCALW_REGIONS : usize = FLASH_NB_OF_REGIONS;

// a variable to hold the error statuses of all Flashcalw commands so far.
static mut flashcalw_error_status : u32 = 0;

//A few constants just for readability
const BIT_ON: u32 = 1;

// TODO: should export this to a chip specific module or so... something that gives me size.
//const FLASHCALW_SIZE : usize = 512; // instead I'll just read it straight from the table
                                      // which will be alloced only for a fxn call.

macro_rules! get_bit {
    ($w:expr) => (0x1u32 << $w);
}

impl FLASHCALW {
    const fn new(base_addr: *mut Registers, ahb_clk: pm::HSBClock,
    hramc1_clk: pm::HSBClock, pb_clk: pm::PBBClock) -> FLASHCALW {
        FLASHCALW {
            registers: base_addr,
            ahb_clock: pm::Clock::HSB(ahb_clk),
            hramc1_clock: pm::Clock::HSB(hramc1_clk),
            pb_clock: pm::Clock::HSB(pb_clk),
        }
    }

    /// FLASH properties.
    pub fn get_flash_size(&self) -> u32 {
        let flash_sizes = [4,
                           8,
                           16,
                           32,
                           48,
                           64,
                           96,
                           128,
                           192,
                           256,
                           384,
                           512,
                           768,
                           1024,
                           2048]
        flash_sizes[self.registers.parameter & 0xf]; // get the FSZ number and
                                                     // lookup in the table for the size.
        //FLASHCALW_SIZE
        //could also just read this from the flash...
    }

    pub fn get_page_count(&self) -> u32 {
        flashcalw_get_flash_size() / FLASH_PAGE_SIZE
    }

    pub fn get_page_count_per_region(&self) -> u32 {
        flashcalw_get_page_count() / FLASH_NB_OF_REGIONS
    }

    // TODO: implement get_page_number().
    pub fn get_page_region(&self, page_number : i32) -> u32 {
        (if page_number >= 0
            { page_number }
        else
            { flashcalw_get_page_number() as i32 }
        / flashcalw_get_page_count_per_region())
    }

    pub fn get_region_first_page_number(&self, region : u32) -> u32 {
        region * flashcalw_get_page_count_per_region()
    }

    /// FLASHC Control
        //TODO:

    ///Flashcalw status

    ///Flashcalw command control

    pub fn get_page_number(&self) -> u32 {
        1
        // DUMMY IMPLEMENTATION
    }

    pub issue_command(&self, command : FlashCMD, page_number : i32) {
        ; // TODO: implement
        //wait_until_ready(); // would be better to avoid busy waiting...
    }

    ///FLASHCALW Protection Mechanisms
    //Todo: write out bit positions?
    pub fn is_security_bit_active(&self) -> bool {
        (self.registers.status & get_bit!(4))
    }

    pub fn set_security_bit(&self) {
       /* let regs : &mut Registers = unsafe {mem::transmute(self.registers)};
        volatile_store(&mut regs.status, (regs.status | get_bit!(4))); */
        issue_command(SSB, -1);
    }

    pub fn is_page_region_locked(&self, page_number : u32) -> bool {
        is_region_locked(get_page_region(page_number))
    }

    pub fn is_region_locked(&self, region : u32) -> bool {
        self.registers.status & get_bit!(region + 16)
    }

    pub fn lock_page_region(&self, page_number : i32, lock : bool) {
        if(lock) {
            issue_command(LP, page_number);
        } else {
            issue_command(UP, page_number);
        }
    }

    pub fn lock_region(region : u32, lock : bool) {
        lock_page_region(get_region_first_page_number(region), lock);
    }

    pub fn lock_all_regions(lock : bool) {
        let mut error_status = 0;
        let mut num_regions = FLASHCALW_REGIONS;

        while(num_regions >= 0) {
            lock_region(num_regions, lock);
            unsafe {
                error_status |= flashcalw_error_status;
            }
            num_regions -= 1;
        }

        unsafe {
            flashcalw_error_status = error_status;
        }
    }
}

<|endoftext|>