<commit_before>//! This package contains just four macros, which enable the creation
//! of array references to portions of arrays or slices (or things
//! that can be sliced).
//!
//! # Examples
//!
//! Here is a simple example of slicing and dicing a slice into array
//! references with these macros.  Here we implement a simple
//! little-endian conversion from bytes to `u16`, and demonstrate code
//! that uses `array_ref!` to extract an array reference from a larger
//! array.  Note that the documentation for each macro also has an
//! example of its use.
//!
//! ```
//! #[macro_use]
//! extern crate arrayref;
//!
//! fn read_u16(bytes: &[u8; 2]) -> u16 {
//!      bytes[0] as u16 + ((bytes[1] as u16) << 8)
//! }
//! // ...
//! # fn main() {
//! let data = [0,1,2,3,4,0,6,7,8,9];
//! assert_eq!(256, read_u16(array_ref![data,0,2]));
//! assert_eq!(4, read_u16(array_ref![data,4,2]));
//! # }
//! ```
#![deny(warnings)]

/// You can use `array_ref` to generate an array reference to a subset
/// of a sliceable bit of data (which could be an array, or a slice,
/// or a Vec).
///
/// **Panics** if the slice is out of bounds.
///
/// ```
/// #[macro_use]
/// extern crate arrayref;
///
/// fn read_u16(bytes: &[u8; 2]) -> u16 {
///      bytes[0] as u16 + ((bytes[1] as u16) << 8)
/// }
/// // ...
/// # fn main() {
/// let data = [0,1,2,3,4,0,6,7,8,9];
/// assert_eq!(256, read_u16(array_ref![data,0,2]));
/// assert_eq!(4, read_u16(array_ref![data,4,2]));
/// # }
/// ```

#[macro_export]
macro_rules! array_ref {
    ($arr:expr, $offset:expr, $len:expr) => {{
        {
            #[inline]
            unsafe fn as_array<T>(slice: &[T]) -> &[T; $len] {
                &*(slice.as_ptr() as *const [_; $len])
            }
            let offset = $offset;
            let slice = & $arr[offset..offset + $len];
            unsafe {
                as_array(slice)
            }
        }
    }}
}

/// You can use `array_refs` to generate a series of array references
/// to an input array reference.  The idea is if you want to break an
/// array into a series of contiguous and non-overlapping arrays.
/// `array_refs` is a bit funny in that it insists on slicing up the
/// *entire* array.  This is intentional, as I find it handy to make
/// me ensure that my sub-arrays add up to the entire array.  This
/// macro will *never* panic, since the sizes are all checked at
/// compile time.
///
/// Note that unlike `array_ref!`, `array_refs` *requires* that the
/// first argument be an array reference.  The following arguments are
/// the lengths of each subarray you wish a reference to.  The total
/// of these arguments *must* equal the size of the array itself.
///
/// ```
/// #[macro_use]
/// extern crate arrayref;
///
/// fn read_u16(bytes: &[u8; 2]) -> u16 {
///      bytes[0] as u16 + ((bytes[1] as u16) << 8)
/// }
/// // ...
/// # fn main() {
/// let data = [0,1,2,3,4,0,6,7];
/// let (a,b,c) = array_refs![&data,2,2,4];
/// assert_eq!(read_u16(a), 256);
/// assert_eq!(read_u16(b), 3*256+2);
/// assert_eq!(*c, [4,0,6,7]);
/// # }
/// ```
#[macro_export]
macro_rules! array_refs {
    ( $arr:expr, $( $len:expr ),* ) => {{
        {
            #[inline]
            #[allow(unused_assignments)]
            unsafe fn as_arrays<T>(a: &[T; $( $len + )* 0 ]) -> ( $( &[T; $len], )* ) {
                let mut p = a.as_ptr();
                ( $( {
                    let aref = &*(p as *const [T; $len]);
                    p = p.offset($len as isize);
                    aref
                } ),* )
            }
            let input = $arr;
            unsafe {
                as_arrays(input)
            }
        }
    }}
}

/// You can use `mut_array_refs` to generate a series of mutable array
/// references to an input mutable array reference.  The idea is if
/// you want to break an array into a series of contiguous and
/// non-overlapping mutable array references.  Like `array_refs!`,
/// `mut_array_refs!` is a bit funny in that it insists on slicing up
/// the *entire* array.  This is intentional, as I find it handy to
/// make me ensure that my sub-arrays add up to the entire array.
/// This macro will *never* panic, since the sizes are all checked at
/// compile time.
///
/// Note that unlike `array_mut_ref!`, `mut_array_refs` *requires*
/// that the first argument be a mutable array reference.  The
/// following arguments are the lengths of each subarray you wish a
/// reference to.  The total of these arguments *must* equal the size
/// of the array itself.  Also note that this macro allows you to take
/// out multiple mutable references to a single object, which is both
/// weird and powerful.
///
/// ```
/// #[macro_use]
/// extern crate arrayref;
///
/// fn write_u16(bytes: &mut [u8; 2], num: u16) {
///      bytes[0] = num as u8;
///      bytes[1] = (num >> 8) as u8;
/// }
/// fn write_u32(bytes: &mut [u8; 4], num: u32) {
///      bytes[0] = num as u8;
///      bytes[1] = (num >> 8) as u8; // this is buggy to save space...
/// }
/// // ...
/// # fn main() {
/// let mut data = [0,1,2,3,4,0,6,7];
/// let (a,b,c) = mut_array_refs![&mut data,2,2,4];
/// // let's write out some nice prime numbers!
/// write_u16(a, 37);
/// write_u16(b, 73);
/// write_u32(c, 137); // approximate inverse of the fine structure constant!
/// # }
/// ```
#[macro_export]
macro_rules! mut_array_refs {
    ( $arr:expr, $( $len:expr ),* ) => {{
        {
            #[inline]
            #[allow(unused_assignments)]
            unsafe fn as_arrays<T>(a: &mut [T; $( $len + )* 0 ]) -> ( $( &mut [T; $len], )* ) {
                let mut p = a.as_mut_ptr();
                ( $( {
                    let aref = &mut *(p as *mut [T; $len]);
                    p = p.offset($len as isize);
                    aref
                } ),* )
            }
            let input = $arr;
            unsafe {
                as_arrays(input)
            }
        }
    }}
}

/// You can use `array_mut_ref` to generate a mutable array reference
/// to a subset of a sliceable bit of data (which could be an array,
/// or a slice, or a Vec).
///
/// **Panics** if the slice is out of bounds.
///
/// ```
/// #[macro_use]
/// extern crate arrayref;
///
/// fn write_u16(bytes: &mut [u8; 2], num: u16) {
///      bytes[0] = num as u8;
///      bytes[1] = (num >> 8) as u8;
/// }
/// // ...
/// # fn main() {
/// let mut data = [0,1,2,3,4,0,6,7,8,9];
/// write_u16(array_mut_ref![data,0,2], 1);
/// write_u16(array_mut_ref![data,2,2], 5);
/// assert_eq!(*array_ref![data,0,4], [1,0,5,0]);
/// *array_mut_ref![data,4,5] = [4,3,2,1,0];
/// assert_eq!(data, [1,0,5,0,4,3,2,1,0,9]);
/// # }
/// ```
#[macro_export]
macro_rules! array_mut_ref {
    ($arr:expr, $offset:expr, $len:expr) => {{
        {
            #[inline]
            unsafe fn as_array<T>(slice: &mut [T]) -> &mut [T; $len] {
                &mut *(slice.as_mut_ptr() as *mut [_; $len])
            }
            let offset = $offset;
            let slice = &mut $arr[offset..offset + $len];
            unsafe {
                as_array(slice)
            }
        }
    }}
}

#[cfg(test)]
mod test {

extern crate quickcheck;

// use super::*;

#[test]
#[should_panic]
fn checks_bounds() {
    let foo: [u8; 11] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    let bar = array_ref!(foo, 1, 11);
    println!("I am checking that I can dereference bar[0] = {}", bar[0]);
}

#[test]
fn simple_case_works() {
    fn check(expected: [u8; 3], actual: &[u8; 3]) {
        for (e, a) in (&expected).iter().zip(actual.iter()) {
            assert_eq!(e, a)
        }
    }
    let mut foo: [u8; 11] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    {
        let bar = array_ref!(foo, 2, 3);
        check([2, 3, 4], bar);
    }
    check([0, 1, 2], array_ref!(foo, 0, 3));
    fn zero2(x: &mut [u8; 2]) {
        x[0] = 0;
        x[1] = 0;
    }
    zero2(array_mut_ref!(foo, 8, 2));
    check([0, 0, 10], array_ref!(foo, 8, 3));
}

#[test]
fn check_array_ref_5() {
    fn f(data: Vec<u8>, offset: usize) -> quickcheck::TestResult {
        if data.len() < offset + 5 {
            return quickcheck::TestResult::discard();
        }
        let out = array_ref!(data, offset, 5);
        quickcheck::TestResult::from_bool(out.len() == 5)
    }
    quickcheck::quickcheck(f as fn(Vec<u8>, usize) -> quickcheck::TestResult);
}

#[test]
fn check_array_ref_out_of_bounds_5() {
    fn f(data: Vec<u8>, offset: usize) -> quickcheck::TestResult {
        if data.len() >= offset + 5 {
            return quickcheck::TestResult::discard();
        }
        quickcheck::TestResult::must_fail(move || {
            array_ref!(data, offset, 5);
        })
    }
    quickcheck::quickcheck(f as fn(Vec<u8>, usize) -> quickcheck::TestResult);
}

#[test]
fn check_array_mut_ref_7() {
    fn f(mut data: Vec<u8>, offset: usize) -> quickcheck::TestResult {
        if data.len() < offset + 7 {
            return quickcheck::TestResult::discard();
        }
        let out = array_mut_ref!(data, offset, 7);
        out[6] = 3;
        quickcheck::TestResult::from_bool(out.len() == 7)
    }
    quickcheck::quickcheck(f as fn(Vec<u8>, usize) -> quickcheck::TestResult);
}

#[test]
fn check_array_mut_ref_out_of_bounds_32() {
    fn f(mut data: Vec<u8>, offset: usize) -> quickcheck::TestResult {
        if data.len() >= offset + 32 {
            return quickcheck::TestResult::discard();
        }
        quickcheck::TestResult::must_fail(move || {
            array_mut_ref!(data, offset, 32);
        })
    }
    quickcheck::quickcheck(f as fn(Vec<u8>, usize) -> quickcheck::TestResult);
}

#[test]
fn test_5_array_refs() {
    let mut data: [usize; 128] = [0; 128];
    for i in 0..128 {
        data[i] = i;
    }
    let data = data;
    let (a,b,c,d,e) = array_refs!(&data, 1, 14, 3, 100, 10);
    assert_eq!(a.len(), 1 as usize);
    assert_eq!(b.len(), 14 as usize);
    assert_eq!(c.len(), 3 as usize);
    assert_eq!(d.len(), 100 as usize);
    assert_eq!(e.len(), 10 as usize);
    assert_eq!(a, array_ref![data, 0, 1]);
    assert_eq!(b, array_ref![data, 1, 14]);
    assert_eq!(c, array_ref![data, 15, 3]);
    assert_eq!(e, array_ref![data, 118, 10]);
}

#[test]
fn test_5_mut_xarray_refs() {
    let mut data: [usize; 128] = [0; 128];
    {
        // temporarily borrow the data to modify it.
        let (a,b,c,d,e) = mut_array_refs!(&mut data, 1, 14, 3, 100, 10);
        assert_eq!(a.len(), 1 as usize);
        assert_eq!(b.len(), 14 as usize);
        assert_eq!(c.len(), 3 as usize);
        assert_eq!(d.len(), 100 as usize);
        assert_eq!(e.len(), 10 as usize);
        *a = [1; 1];
        *b = [14; 14];
        *c = [3; 3];
        *d = [100; 100];
        *e = [10; 10];
    }
    assert_eq!(&[1;1], array_ref![data, 0, 1]);
    assert_eq!(&[14;14], array_ref![data, 1, 14]);
    assert_eq!(&[3;3], array_ref![data, 15, 3]);
    assert_eq!(&[10;10], array_ref![data, 118, 10]);
}

} // mod test
<commit_msg>Add #![no_std] (#8)<commit_after>//! This package contains just four macros, which enable the creation
//! of array references to portions of arrays or slices (or things
//! that can be sliced).
//!
//! # Examples
//!
//! Here is a simple example of slicing and dicing a slice into array
//! references with these macros.  Here we implement a simple
//! little-endian conversion from bytes to `u16`, and demonstrate code
//! that uses `array_ref!` to extract an array reference from a larger
//! array.  Note that the documentation for each macro also has an
//! example of its use.
//!
//! ```
//! #[macro_use]
//! extern crate arrayref;
//!
//! fn read_u16(bytes: &[u8; 2]) -> u16 {
//!      bytes[0] as u16 + ((bytes[1] as u16) << 8)
//! }
//! // ...
//! # fn main() {
//! let data = [0,1,2,3,4,0,6,7,8,9];
//! assert_eq!(256, read_u16(array_ref![data,0,2]));
//! assert_eq!(4, read_u16(array_ref![data,4,2]));
//! # }
//! ```
#![deny(warnings)]
#![no_std]

#[cfg(test)]
#[macro_use]
extern crate std;

/// You can use `array_ref` to generate an array reference to a subset
/// of a sliceable bit of data (which could be an array, or a slice,
/// or a Vec).
///
/// **Panics** if the slice is out of bounds.
///
/// ```
/// #[macro_use]
/// extern crate arrayref;
///
/// fn read_u16(bytes: &[u8; 2]) -> u16 {
///      bytes[0] as u16 + ((bytes[1] as u16) << 8)
/// }
/// // ...
/// # fn main() {
/// let data = [0,1,2,3,4,0,6,7,8,9];
/// assert_eq!(256, read_u16(array_ref![data,0,2]));
/// assert_eq!(4, read_u16(array_ref![data,4,2]));
/// # }
/// ```

#[macro_export]
macro_rules! array_ref {
    ($arr:expr, $offset:expr, $len:expr) => {{
        {
            #[inline]
            unsafe fn as_array<T>(slice: &[T]) -> &[T; $len] {
                &*(slice.as_ptr() as *const [_; $len])
            }
            let offset = $offset;
            let slice = & $arr[offset..offset + $len];
            unsafe {
                as_array(slice)
            }
        }
    }}
}

/// You can use `array_refs` to generate a series of array references
/// to an input array reference.  The idea is if you want to break an
/// array into a series of contiguous and non-overlapping arrays.
/// `array_refs` is a bit funny in that it insists on slicing up the
/// *entire* array.  This is intentional, as I find it handy to make
/// me ensure that my sub-arrays add up to the entire array.  This
/// macro will *never* panic, since the sizes are all checked at
/// compile time.
///
/// Note that unlike `array_ref!`, `array_refs` *requires* that the
/// first argument be an array reference.  The following arguments are
/// the lengths of each subarray you wish a reference to.  The total
/// of these arguments *must* equal the size of the array itself.
///
/// ```
/// #[macro_use]
/// extern crate arrayref;
///
/// fn read_u16(bytes: &[u8; 2]) -> u16 {
///      bytes[0] as u16 + ((bytes[1] as u16) << 8)
/// }
/// // ...
/// # fn main() {
/// let data = [0,1,2,3,4,0,6,7];
/// let (a,b,c) = array_refs![&data,2,2,4];
/// assert_eq!(read_u16(a), 256);
/// assert_eq!(read_u16(b), 3*256+2);
/// assert_eq!(*c, [4,0,6,7]);
/// # }
/// ```
#[macro_export]
macro_rules! array_refs {
    ( $arr:expr, $( $len:expr ),* ) => {{
        {
            #[inline]
            #[allow(unused_assignments)]
            unsafe fn as_arrays<T>(a: &[T; $( $len + )* 0 ]) -> ( $( &[T; $len], )* ) {
                let mut p = a.as_ptr();
                ( $( {
                    let aref = &*(p as *const [T; $len]);
                    p = p.offset($len as isize);
                    aref
                } ),* )
            }
            let input = $arr;
            unsafe {
                as_arrays(input)
            }
        }
    }}
}

/// You can use `mut_array_refs` to generate a series of mutable array
/// references to an input mutable array reference.  The idea is if
/// you want to break an array into a series of contiguous and
/// non-overlapping mutable array references.  Like `array_refs!`,
/// `mut_array_refs!` is a bit funny in that it insists on slicing up
/// the *entire* array.  This is intentional, as I find it handy to
/// make me ensure that my sub-arrays add up to the entire array.
/// This macro will *never* panic, since the sizes are all checked at
/// compile time.
///
/// Note that unlike `array_mut_ref!`, `mut_array_refs` *requires*
/// that the first argument be a mutable array reference.  The
/// following arguments are the lengths of each subarray you wish a
/// reference to.  The total of these arguments *must* equal the size
/// of the array itself.  Also note that this macro allows you to take
/// out multiple mutable references to a single object, which is both
/// weird and powerful.
///
/// ```
/// #[macro_use]
/// extern crate arrayref;
///
/// fn write_u16(bytes: &mut [u8; 2], num: u16) {
///      bytes[0] = num as u8;
///      bytes[1] = (num >> 8) as u8;
/// }
/// fn write_u32(bytes: &mut [u8; 4], num: u32) {
///      bytes[0] = num as u8;
///      bytes[1] = (num >> 8) as u8; // this is buggy to save space...
/// }
/// // ...
/// # fn main() {
/// let mut data = [0,1,2,3,4,0,6,7];
/// let (a,b,c) = mut_array_refs![&mut data,2,2,4];
/// // let's write out some nice prime numbers!
/// write_u16(a, 37);
/// write_u16(b, 73);
/// write_u32(c, 137); // approximate inverse of the fine structure constant!
/// # }
/// ```
#[macro_export]
macro_rules! mut_array_refs {
    ( $arr:expr, $( $len:expr ),* ) => {{
        {
            #[inline]
            #[allow(unused_assignments)]
            unsafe fn as_arrays<T>(a: &mut [T; $( $len + )* 0 ]) -> ( $( &mut [T; $len], )* ) {
                let mut p = a.as_mut_ptr();
                ( $( {
                    let aref = &mut *(p as *mut [T; $len]);
                    p = p.offset($len as isize);
                    aref
                } ),* )
            }
            let input = $arr;
            unsafe {
                as_arrays(input)
            }
        }
    }}
}

/// You can use `array_mut_ref` to generate a mutable array reference
/// to a subset of a sliceable bit of data (which could be an array,
/// or a slice, or a Vec).
///
/// **Panics** if the slice is out of bounds.
///
/// ```
/// #[macro_use]
/// extern crate arrayref;
///
/// fn write_u16(bytes: &mut [u8; 2], num: u16) {
///      bytes[0] = num as u8;
///      bytes[1] = (num >> 8) as u8;
/// }
/// // ...
/// # fn main() {
/// let mut data = [0,1,2,3,4,0,6,7,8,9];
/// write_u16(array_mut_ref![data,0,2], 1);
/// write_u16(array_mut_ref![data,2,2], 5);
/// assert_eq!(*array_ref![data,0,4], [1,0,5,0]);
/// *array_mut_ref![data,4,5] = [4,3,2,1,0];
/// assert_eq!(data, [1,0,5,0,4,3,2,1,0,9]);
/// # }
/// ```
#[macro_export]
macro_rules! array_mut_ref {
    ($arr:expr, $offset:expr, $len:expr) => {{
        {
            #[inline]
            unsafe fn as_array<T>(slice: &mut [T]) -> &mut [T; $len] {
                &mut *(slice.as_mut_ptr() as *mut [_; $len])
            }
            let offset = $offset;
            let slice = &mut $arr[offset..offset + $len];
            unsafe {
                as_array(slice)
            }
        }
    }}
}

#[cfg(test)]
mod test {

extern crate quickcheck;

use std::vec::Vec;

// use super::*;

#[test]
#[should_panic]
fn checks_bounds() {
    let foo: [u8; 11] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    let bar = array_ref!(foo, 1, 11);
    println!("I am checking that I can dereference bar[0] = {}", bar[0]);
}

#[test]
fn simple_case_works() {
    fn check(expected: [u8; 3], actual: &[u8; 3]) {
        for (e, a) in (&expected).iter().zip(actual.iter()) {
            assert_eq!(e, a)
        }
    }
    let mut foo: [u8; 11] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    {
        let bar = array_ref!(foo, 2, 3);
        check([2, 3, 4], bar);
    }
    check([0, 1, 2], array_ref!(foo, 0, 3));
    fn zero2(x: &mut [u8; 2]) {
        x[0] = 0;
        x[1] = 0;
    }
    zero2(array_mut_ref!(foo, 8, 2));
    check([0, 0, 10], array_ref!(foo, 8, 3));
}

#[test]
fn check_array_ref_5() {
    fn f(data: Vec<u8>, offset: usize) -> quickcheck::TestResult {
        if data.len() < offset + 5 {
            return quickcheck::TestResult::discard();
        }
        let out = array_ref!(data, offset, 5);
        quickcheck::TestResult::from_bool(out.len() == 5)
    }
    quickcheck::quickcheck(f as fn(Vec<u8>, usize) -> quickcheck::TestResult);
}

#[test]
fn check_array_ref_out_of_bounds_5() {
    fn f(data: Vec<u8>, offset: usize) -> quickcheck::TestResult {
        if data.len() >= offset + 5 {
            return quickcheck::TestResult::discard();
        }
        quickcheck::TestResult::must_fail(move || {
            array_ref!(data, offset, 5);
        })
    }
    quickcheck::quickcheck(f as fn(Vec<u8>, usize) -> quickcheck::TestResult);
}

#[test]
fn check_array_mut_ref_7() {
    fn f(mut data: Vec<u8>, offset: usize) -> quickcheck::TestResult {
        if data.len() < offset + 7 {
            return quickcheck::TestResult::discard();
        }
        let out = array_mut_ref!(data, offset, 7);
        out[6] = 3;
        quickcheck::TestResult::from_bool(out.len() == 7)
    }
    quickcheck::quickcheck(f as fn(Vec<u8>, usize) -> quickcheck::TestResult);
}

#[test]
fn check_array_mut_ref_out_of_bounds_32() {
    fn f(mut data: Vec<u8>, offset: usize) -> quickcheck::TestResult {
        if data.len() >= offset + 32 {
            return quickcheck::TestResult::discard();
        }
        quickcheck::TestResult::must_fail(move || {
            array_mut_ref!(data, offset, 32);
        })
    }
    quickcheck::quickcheck(f as fn(Vec<u8>, usize) -> quickcheck::TestResult);
}

#[test]
fn test_5_array_refs() {
    let mut data: [usize; 128] = [0; 128];
    for i in 0..128 {
        data[i] = i;
    }
    let data = data;
    let (a,b,c,d,e) = array_refs!(&data, 1, 14, 3, 100, 10);
    assert_eq!(a.len(), 1 as usize);
    assert_eq!(b.len(), 14 as usize);
    assert_eq!(c.len(), 3 as usize);
    assert_eq!(d.len(), 100 as usize);
    assert_eq!(e.len(), 10 as usize);
    assert_eq!(a, array_ref![data, 0, 1]);
    assert_eq!(b, array_ref![data, 1, 14]);
    assert_eq!(c, array_ref![data, 15, 3]);
    assert_eq!(e, array_ref![data, 118, 10]);
}

#[test]
fn test_5_mut_xarray_refs() {
    let mut data: [usize; 128] = [0; 128];
    {
        // temporarily borrow the data to modify it.
        let (a,b,c,d,e) = mut_array_refs!(&mut data, 1, 14, 3, 100, 10);
        assert_eq!(a.len(), 1 as usize);
        assert_eq!(b.len(), 14 as usize);
        assert_eq!(c.len(), 3 as usize);
        assert_eq!(d.len(), 100 as usize);
        assert_eq!(e.len(), 10 as usize);
        *a = [1; 1];
        *b = [14; 14];
        *c = [3; 3];
        *d = [100; 100];
        *e = [10; 10];
    }
    assert_eq!(&[1;1], array_ref![data, 0, 1]);
    assert_eq!(&[14;14], array_ref![data, 1, 14]);
    assert_eq!(&[3;3], array_ref![data, 15, 3]);
    assert_eq!(&[10;10], array_ref![data, 118, 10]);
}

} // mod test
<|endoftext|>


<commit_before>#![feature(test)]

extern crate num;

#[cfg(test)]
mod test;

use num::{Zero, One, CheckedAdd};
use std::fmt::Debug;

#[derive(Debug)]
pub struct Fibonacci<T> {
  last_two: (T, T)
}

impl<T> Default for Fibonacci<T>
  where T: Debug + Zero + One
{
  fn default() -> Self {
    Fibonacci { last_two: (T::zero(), T::one()) }
  }
}

impl<T> Iterator for Fibonacci<T>
  where T: Debug + CheckedAdd + Clone
{
  type Item = T;

  fn next(&mut self) -> Option<Self::Item> {
    let n = self.last_two.0.checked_add(&self.last_two.1);
    if let Some(ref x) = n {
      std::mem::swap(&mut self.last_two.0, &mut self.last_two.1);
      self.last_two.1 = x.clone();
    }
    n
  }
}
<commit_msg>docs: add some documentation and doc-tests<commit_after>//! Generate Fibonacci sequence numbers.
//!
//! ```
//! # use fibonacci::Fibonacci;
//! // Collect all of the Fibonacci numbers that fit inside a u8.
//! let some_numbers: Vec<u8> = Fibonacci::default().collect();
//! println!("{:?}", some_numbers);
//! ```

#![feature(test)]

extern crate num;

#[cfg(test)]
mod test;

use num::{Zero, One, CheckedAdd};
use std::fmt::Debug;

/// A generic Fibonacci sequence generator.
///
/// The iterator ends whenever the generic type overflows from the result of adding the last two
/// numbers together. For example, a `Fibonacci<u8>` will only generate 12 elements.
///
/// ```
/// # use fibonacci::Fibonacci;
/// assert_eq!(12, Fibonacci::<u8>::default().take(13).collect::<Vec<_>>().len())
/// ```
///
/// If you need more elements than primitives can provide, try `Fibonacci<num::BigUint>`, which will
/// never overflow.
#[derive(Debug)]
pub struct Fibonacci<T> {
  last_two: (T, T)
}

impl<T> Default for Fibonacci<T>
  where T: Debug + Zero + One
{
  fn default() -> Self {
    Fibonacci { last_two: (T::zero(), T::one()) }
  }
}

impl<T> Iterator for Fibonacci<T>
  where T: Debug + CheckedAdd + Clone
{
  type Item = T;

  fn next(&mut self) -> Option<Self::Item> {
    let n = self.last_two.0.checked_add(&self.last_two.1);
    if let Some(ref x) = n {
      std::mem::swap(&mut self.last_two.0, &mut self.last_two.1);
      self.last_two.1 = x.clone();
    }
    n
  }
}
<|endoftext|>


<commit_before>
mod alias {
    pub enum Commands {
        NewBeacon = 15,
        DelBeacon = 17,
        RegisterAction = 60,
        Action = 62,
        ActionTxStatus = 64,
    }
}

// Commands
// Do not change order; acts as ABI
pub enum Commands {
    Unspec,
    GetWiPhy,
    SetWiPhy,
    NewWiPhy,
    DelWiPhy,

    GetInterface,
    SetInterface,
    NewInterface,
    DelIntreface,

    GetKey,
    SetKey,
    NewKey,
    DelKey,

    GetBeacon,
    SetBeacon,
    StartAp,
    AliasNewBeacon, // StartAp alias
    StopAp,
    AliasDelBeacon, // StopAp alias

    GetStation,
    SetStation,
    NewStation,
    DelStation,

    GetMPath,
    SetMPath,
    NewMPath,
    DelMPath,

    SetBss,

    SetReg,
    ReqSetReg,

    GetMeshConfig,
    SetMeshConfig,

    SetMgmtExtraIe, // Reserved; not used

    GetReg,

    GetScan,
    TriggerScan,
    NewScanResults,
    ScanAborted,

    RegChange,

    Authenticate,
    Associate,
    Deauthenticate,
    Disassociate,

    MichaelMicFailure,

    RegBeaconHint,

    JoinIbss,
    LeaveIbss,

    TestMode,
    Connect,
    Roam,
    Disconnect,

    SetWiPhyNetNs,

    GetSurvey,
    NewSurveyResults,

    SetPmksa,
    DelPmksa,
    FlushPmksa,

    RemainOnChannel,
    CancelRemainOnChannel,

    SetTxBitrateMask,

    RegisterFrame,
    AliasRegisterAction, // RegisterFrame alias
    Frame,
    AliasAction,         // Frame alias
    FrameTxStatus,
    AliasActionTxStatus, // FrameTxStatus

    SetPowerSave,
    GetPowerSave,

    SetCqm,
    NotifyCqm,

    SetChannel,
    SetWdsPeer,

    FrameWaitCancel,

    JoinMesh,
    LeaveMesh,

    UnprotDeathenticate,
    UnProtDisassociate,

    NewPeerCandidate,

    GetWowLan,
    SetWowLan,

    StartSchedScan,
    StopSchedScan,
    SchedScanResults,
    SchedScanStopped,

    SetRekeyOffload,

    PmksaCandidate,

    TdlsOper,
    TdlsMgmt,

    UnexpectedFrame,

    ProbeClient,

    RegisterBeacons,

    Unexpected4AddrFrame,

    SetNoAckMap,

    ChSwitchNotify,

    StartP2pDevice,
    StopP2pDevice,

    ConnFailed,

    SetMcastRate,

    SetMacAcl,

    RadarDetect,

    GetProtocolFeatures,

    UpdateFtIes,
    FtEvent,

    CritProtocolState,
    CritProtocolStop,

    GetCoalesce,
    SetCoalesce,

    Vendor,

    SetQosMap,

    AddTxTs,
    DelTxTs,

    GetMpp,

    AfterLast
}

// attributes
// Do not change order; acts as ABI
enum Attrs {
    Unspec,

    WiPhy,
    WiPhyName,

    IfIndex,
    IfName,
    IfType,

    Mac,

    KeyData,
    KeyIdx,
    KeyCipher,
    KeySeq,
    KeyDefault,

    BeaconInterval,
    DtimPeriod,
    BeaconHead,
    BeaconTail,

    StaAid,
    StaFlags,
    StaListenInterval,
    StaSupportedRates,
    StaVlan,
    StaInfo,

    WiPhyBands,

    MntrFlags,

    MeshId,
    StaPlinkAction,
    MpathNextHop,
    MpathInfo,

    BssCtsProt,
    BssShortPreamble,
    BssShortSlotTime,

    HtCapability,

    SupportedIfTypes,

    RegAlpha2,
    RegRules,

    MeshConfig,

    BssBasicRates,

    WiPhyTxqParams,
    WiPhyFreq,
    WiPhyChannelType,

    KeyDefaultMgmt,

    MgmtSubtype,
    Ie,

    MaxNumScanSsids,

    ScanFrequencies,
    ScanSsids,
    Generation,
    Bss,

    RegInitiator,
    RegType,

    SupportedCommands,

    Frame,
    Ssid,
    AuthType,
    ReasonCode,

    KeyType,

    MaxScanIeLen,
    CipherSuites,

    FreqBefore,
    FreqAfter,

    FreqFixed,

    WiPhyRetryShort,
    WiPhyRetryLong,
    WiPhyFragThreshold,
    WiPhyRtsThreshold,

    TimedOut,

    UseMfp,

    StaFlags2,

    ControlPort,

    TestData,

    Privacy,

    DisconnectedByAp,

    StatusCode,

    CipherSuitesPairwise,
    CipherSuiteGroup,
    WpaVersions,
    AkmSuites,

    ReqIe,
    RespIe,

    PrevBssid,

    Key,
    Keys,

    Pid,

    Addr4,

    SurveyInfo,

    PmkId,
    MaxNumPmkIds,

    Duration,

    Cookie,

    WiPhyCoverageClass,

    TxRates,

    FrameMatch,

    Ack,

    PsState,

    Cqm,

    LocalStateChange,

    ApIsolate,

    WiPhyTxPowerSetting,
    WiPhyTxPowerLevel,

    TxFrameTypes,
    RxFrameTypes,
    FrameType,

    ControlPortEthertype,
    ControlPortNoEncrypt,

    SupportIbssRsn,

    WiPhyAntennaTx,
    WiPhyAntennaRx,

    McastRate,

    OffChannelTxOk,

    BssHtOpmode,

    KeyDefaultTypes,

    MaxRemainOnChannelDuration,

    MeshSetup,

    WiPhyAntennaAvailTx,
    WiPhyAntennaAvailRx,

    SupportMeshAuth,
    StaPlinkState,

    WowLanTriggers,
    WowLanTriggersSupported,

    SchedScanInterval,

    InterfaceCombinations,
    SoftwareIfTypes,

    RekeyData,

    MaxNumSchedScanSsids,
    MaxSchedScanIeLen,

    ScanSuppRates,

    HiddenSsid,

    IeProbeResp,
    IeAssocResp,

    StaWme,
    SupportApUapsd,

    RoamSupport,

    AttrSchedScanMatch,
    MaxMatchSets,

    PmksaCandidate,

    TxNoCckRate,

    TdlsAction,
    TdlsDialogToken,
    TdlsOperation,
    TdlsSupport,
    TdlsExternalSetup,

    DeviceApSme,

    DontWaitForAck,

    FeatureFlags,

    ProbeRespOffload,

    ProbeResp,

    DfsRegion,

    DisableHt,
    HtCapabilityMask,

    NoackMap,

    InactivityTimeout,

    RxSignalDbm,

    BgScanPeriod,

    Wdev,

    UserRegHintType,

    ConnFailedReason,

    SaeData,

    VhtCapability,

    ScanFlags,

    ChannelWidth,
    CenterFreq1,
    CenterFreq2,

    P2pCtwindow,
    P2pOppps,

    LocalMeshPowerMode,

    AclPolicy,

    MacAddrs,

    MacAclMax,

    RadarEvent,

    ExtCapa,

    ExtCapaMask,

    StaCapability,
    StaExtCapability,

    ProtocolFeatures,
    SplitWiphyDump,

    DisableVht,
    VhtCapabilityMask,

    Mdid,

    IeRic,

    CritProtId,
    MaxCritProtDuration,

    PeerAid,

    CoalesceRule,

    ChSwitchCount,
    ChSwitchBlockTx,
    CsaIes,
    CsaCOffBeacon,
    CsaCOffPresp,

    RxmgmtFlags,

    StaSupportedChannels,
    StaSipportedOperClasses,

    HandleDfs,

    Support5Mhz,
    Support10Mhz,

    OpmodeNotif,

    VendorId,
    VendorSubcmd,
    VendorData,
    VendorEvents,

    QodMap,

    MacHint,
    WiPhyFreqHint,

    MaxApAssocSta,

    TdlsPeerCapability,

    IfaceSocketOwnder,
    CsaCOffsetsTx,
    MaxCsaCounters,

    TdlsInitiator,

    UseRrm,

    WiPhyDynAck,

    Tsid,
    UserPrio,
    AdmittedTime,

    SmpsMode,

    AfterLast
}

enum IfType {
    Unspecified,
    AdHoc,
    Station,
    Ap,
    ApVlan,
    Wds,
    Monitor,
    MeshPoint,
    P2pClient,
    P2pGo,
    P2pDevice,

    NumIfTypes
}

<commit_msg>Include Station flags<commit_after>
mod alias {
    pub enum Commands {
        NewBeacon = 15,
        DelBeacon = 17,
        RegisterAction = 60,
        Action = 62,
        ActionTxStatus = 64,
    }
}

// Commands
// Do not change order; acts as ABI
pub enum Commands {
    Unspec,
    GetWiPhy,
    SetWiPhy,
    NewWiPhy,
    DelWiPhy,

    GetInterface,
    SetInterface,
    NewInterface,
    DelIntreface,

    GetKey,
    SetKey,
    NewKey,
    DelKey,

    GetBeacon,
    SetBeacon,
    StartAp,
    AliasNewBeacon, // StartAp alias
    StopAp,
    AliasDelBeacon, // StopAp alias

    GetStation,
    SetStation,
    NewStation,
    DelStation,

    GetMPath,
    SetMPath,
    NewMPath,
    DelMPath,

    SetBss,

    SetReg,
    ReqSetReg,

    GetMeshConfig,
    SetMeshConfig,

    SetMgmtExtraIe, // Reserved; not used

    GetReg,

    GetScan,
    TriggerScan,
    NewScanResults,
    ScanAborted,

    RegChange,

    Authenticate,
    Associate,
    Deauthenticate,
    Disassociate,

    MichaelMicFailure,

    RegBeaconHint,

    JoinIbss,
    LeaveIbss,

    TestMode,
    Connect,
    Roam,
    Disconnect,

    SetWiPhyNetNs,

    GetSurvey,
    NewSurveyResults,

    SetPmksa,
    DelPmksa,
    FlushPmksa,

    RemainOnChannel,
    CancelRemainOnChannel,

    SetTxBitrateMask,

    RegisterFrame,
    AliasRegisterAction, // RegisterFrame alias
    Frame,
    AliasAction,         // Frame alias
    FrameTxStatus,
    AliasActionTxStatus, // FrameTxStatus

    SetPowerSave,
    GetPowerSave,

    SetCqm,
    NotifyCqm,

    SetChannel,
    SetWdsPeer,

    FrameWaitCancel,

    JoinMesh,
    LeaveMesh,

    UnprotDeathenticate,
    UnProtDisassociate,

    NewPeerCandidate,

    GetWowLan,
    SetWowLan,

    StartSchedScan,
    StopSchedScan,
    SchedScanResults,
    SchedScanStopped,

    SetRekeyOffload,

    PmksaCandidate,

    TdlsOper,
    TdlsMgmt,

    UnexpectedFrame,

    ProbeClient,

    RegisterBeacons,

    Unexpected4AddrFrame,

    SetNoAckMap,

    ChSwitchNotify,

    StartP2pDevice,
    StopP2pDevice,

    ConnFailed,

    SetMcastRate,

    SetMacAcl,

    RadarDetect,

    GetProtocolFeatures,

    UpdateFtIes,
    FtEvent,

    CritProtocolState,
    CritProtocolStop,

    GetCoalesce,
    SetCoalesce,

    Vendor,

    SetQosMap,

    AddTxTs,
    DelTxTs,

    GetMpp,

    AfterLast
}

// attributes
// Do not change order; acts as ABI
enum Attrs {
    Unspec,

    WiPhy,
    WiPhyName,

    IfIndex,
    IfName,
    IfType,

    Mac,

    KeyData,
    KeyIdx,
    KeyCipher,
    KeySeq,
    KeyDefault,

    BeaconInterval,
    DtimPeriod,
    BeaconHead,
    BeaconTail,

    StaAid,
    StaFlags,
    StaListenInterval,
    StaSupportedRates,
    StaVlan,
    StaInfo,

    WiPhyBands,

    MntrFlags,

    MeshId,
    StaPlinkAction,
    MpathNextHop,
    MpathInfo,

    BssCtsProt,
    BssShortPreamble,
    BssShortSlotTime,

    HtCapability,

    SupportedIfTypes,

    RegAlpha2,
    RegRules,

    MeshConfig,

    BssBasicRates,

    WiPhyTxqParams,
    WiPhyFreq,
    WiPhyChannelType,

    KeyDefaultMgmt,

    MgmtSubtype,
    Ie,

    MaxNumScanSsids,

    ScanFrequencies,
    ScanSsids,
    Generation,
    Bss,

    RegInitiator,
    RegType,

    SupportedCommands,

    Frame,
    Ssid,
    AuthType,
    ReasonCode,

    KeyType,

    MaxScanIeLen,
    CipherSuites,

    FreqBefore,
    FreqAfter,

    FreqFixed,

    WiPhyRetryShort,
    WiPhyRetryLong,
    WiPhyFragThreshold,
    WiPhyRtsThreshold,

    TimedOut,

    UseMfp,

    StaFlags2,

    ControlPort,

    TestData,

    Privacy,

    DisconnectedByAp,

    StatusCode,

    CipherSuitesPairwise,
    CipherSuiteGroup,
    WpaVersions,
    AkmSuites,

    ReqIe,
    RespIe,

    PrevBssid,

    Key,
    Keys,

    Pid,

    Addr4,

    SurveyInfo,

    PmkId,
    MaxNumPmkIds,

    Duration,

    Cookie,

    WiPhyCoverageClass,

    TxRates,

    FrameMatch,

    Ack,

    PsState,

    Cqm,

    LocalStateChange,

    ApIsolate,

    WiPhyTxPowerSetting,
    WiPhyTxPowerLevel,

    TxFrameTypes,
    RxFrameTypes,
    FrameType,

    ControlPortEthertype,
    ControlPortNoEncrypt,

    SupportIbssRsn,

    WiPhyAntennaTx,
    WiPhyAntennaRx,

    McastRate,

    OffChannelTxOk,

    BssHtOpmode,

    KeyDefaultTypes,

    MaxRemainOnChannelDuration,

    MeshSetup,

    WiPhyAntennaAvailTx,
    WiPhyAntennaAvailRx,

    SupportMeshAuth,
    StaPlinkState,

    WowLanTriggers,
    WowLanTriggersSupported,

    SchedScanInterval,

    InterfaceCombinations,
    SoftwareIfTypes,

    RekeyData,

    MaxNumSchedScanSsids,
    MaxSchedScanIeLen,

    ScanSuppRates,

    HiddenSsid,

    IeProbeResp,
    IeAssocResp,

    StaWme,
    SupportApUapsd,

    RoamSupport,

    AttrSchedScanMatch,
    MaxMatchSets,

    PmksaCandidate,

    TxNoCckRate,

    TdlsAction,
    TdlsDialogToken,
    TdlsOperation,
    TdlsSupport,
    TdlsExternalSetup,

    DeviceApSme,

    DontWaitForAck,

    FeatureFlags,

    ProbeRespOffload,

    ProbeResp,

    DfsRegion,

    DisableHt,
    HtCapabilityMask,

    NoackMap,

    InactivityTimeout,

    RxSignalDbm,

    BgScanPeriod,

    Wdev,

    UserRegHintType,

    ConnFailedReason,

    SaeData,

    VhtCapability,

    ScanFlags,

    ChannelWidth,
    CenterFreq1,
    CenterFreq2,

    P2pCtwindow,
    P2pOppps,

    LocalMeshPowerMode,

    AclPolicy,

    MacAddrs,

    MacAclMax,

    RadarEvent,

    ExtCapa,

    ExtCapaMask,

    StaCapability,
    StaExtCapability,

    ProtocolFeatures,
    SplitWiphyDump,

    DisableVht,
    VhtCapabilityMask,

    Mdid,

    IeRic,

    CritProtId,
    MaxCritProtDuration,

    PeerAid,

    CoalesceRule,

    ChSwitchCount,
    ChSwitchBlockTx,
    CsaIes,
    CsaCOffBeacon,
    CsaCOffPresp,

    RxmgmtFlags,

    StaSupportedChannels,
    StaSipportedOperClasses,

    HandleDfs,

    Support5Mhz,
    Support10Mhz,

    OpmodeNotif,

    VendorId,
    VendorSubcmd,
    VendorData,
    VendorEvents,

    QodMap,

    MacHint,
    WiPhyFreqHint,

    MaxApAssocSta,

    TdlsPeerCapability,

    IfaceSocketOwnder,
    CsaCOffsetsTx,
    MaxCsaCounters,

    TdlsInitiator,

    UseRrm,

    WiPhyDynAck,

    Tsid,
    UserPrio,
    AdmittedTime,

    SmpsMode,

    AfterLast
}

enum IfType {
    Unspecified,
    AdHoc,
    Station,
    Ap,
    ApVlan,
    Wds,
    Monitor,
    MeshPoint,
    P2pClient,
    P2pGo,
    P2pDevice,

    NumIfTypes
}

enum StaFlags {
    __Invalid,
    Authorized,
    ShortPreamble,
    Wme,
    Mfp,
    Authenticated,
    TdlsPeer,
    Associated,
    AfterLast
}
<|endoftext|>


<commit_before>extern crate opus_sys as ffi;
extern crate libc;

use libc::{c_int};

// Generic CTLs
const OPUS_RESET_STATE: c_int = 4028; // void
const OPUS_GET_FINAL_RANGE: c_int = 4031; // *uint
const OPUS_GET_BANDWIDTH: c_int = 4009; // *int
const OPUS_GET_SAMPLE_RATE: c_int = 4029; // *int

pub enum CodingMode {
	Voip = 2048,
	Audio = 2049,
	LowDelay = 2051,
}

pub enum Channels {
	Mono = 1,
	Stereo = 2,
}

pub struct Error(&'static str, c_int);

fn check(what: &'static str, code: c_int) -> Result<()> {
	if code < 0 {
		Err(Error(what, code))
	} else {
		Ok(())
	}
}

pub type Result<T> = std::result::Result<T, Error>;

pub struct Encoder {
	ptr: *mut ffi::OpusEncoder,
}

impl Encoder {
	pub fn new(sample_rate: u32, channels: Channels, mode: CodingMode) -> Result<Encoder> {
		let mut error = 0;
		let ptr = unsafe { ffi::opus_encoder_create(
			sample_rate as i32,
			channels as c_int,
			mode as c_int,
			&mut error) };
		if error != ffi::OPUS_OK || ptr.is_null() {
			Err(Error("opus_encoder_create", error))
		} else {
			Ok(Encoder { ptr: ptr })
		}
	}

	pub fn encode(&mut self, input: &[i16], output: &mut [u8]) -> Result<usize> {
		let len = unsafe { ffi::opus_encode(self.ptr,
			input.as_ptr(), input.len() as c_int,
			output.as_mut_ptr(), output.len() as c_int) };
		try!(check("opus_encode", len));
		Ok(len as usize)
	}

	pub fn encode_float(&mut self, input: &[f32], output: &mut [u8]) -> Result<usize> {
		let len = unsafe { ffi::opus_encode_float(self.ptr,
			input.as_ptr(), input.len() as c_int,
			output.as_mut_ptr(), output.len() as c_int) };
		try!(check("opus_encode_float", len));
		Ok(len as usize)
	}

	pub fn reset_state(&mut self) -> Result<()> {
		check("opus_encoder_ctl(OPUS_RESET_STATE)", unsafe { ffi::opus_encoder_ctl(self.ptr, OPUS_RESET_STATE) })
	}

	pub fn get_final_range(&mut self) -> Result<u32> {
		let mut value = 0;
		let result = unsafe { ffi::opus_encoder_ctl(self.ptr, OPUS_GET_FINAL_RANGE, &mut value) };
		try!(check("opus_encoder_ctl(OPUS_GET_FINAL_RANGE)", result));
		Ok(value)
	}

	pub fn get_bandwidth(&mut self) -> Result<i32> {
		let mut value = 0;
		let result = unsafe { ffi::opus_encoder_ctl(self.ptr, OPUS_GET_BANDWIDTH, &mut value) };
		try!(check("opus_encoder_ctl(OPUS_GET_BANDWIDTH)", result));
		Ok(value)
	}

	pub fn get_sample_rate(&mut self) -> Result<i32> {
		let mut value = 0;
		let result = unsafe { ffi::opus_encoder_ctl(self.ptr, OPUS_GET_SAMPLE_RATE, &mut value) };
		try!(check("opus_encoder_ctl(OPUS_GET_SAMPLE_RATE)", result));
		Ok(value)
	}

	// TODO: Many more CTLs
}

impl Drop for Encoder {
	fn drop(&mut self) {
		unsafe { ffi::opus_encoder_destroy(self.ptr) }
	}
}
<commit_msg>Add Decoder, packets, and Error handling<commit_after>extern crate opus_sys as ffi;
extern crate libc;

use std::ffi::CStr;

use libc::{c_int};

// TODO: Documentation

// ============================================================================
// Constants

// Generic CTLs
const OPUS_RESET_STATE: c_int = 4028; // void
const OPUS_GET_FINAL_RANGE: c_int = 4031; // *uint
const OPUS_GET_BANDWIDTH: c_int = 4009; // *int
const OPUS_GET_SAMPLE_RATE: c_int = 4029; // *int

#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum CodingMode {
	Voip = 2048,
	Audio = 2049,
	LowDelay = 2051,
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum Channels {
	Stereo = 1,
	Mono = 2,
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum Bandwidth {
	Narrowband = 1101,
	Mediumband = 1102,
	Wideband = 1103,
	Superwideband = 1104,
	Fullband = 1105,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum ErrorCode {
	BadArg = -1,
	BufferTooSmall = -2,
	InternalError = -3,
	InvalidPacket = -4,
	Unimplemented = -5,
	InvalidState = -6,
	AllocFail = -7,
	Unknown = -8,
}

pub fn version() -> &'static str {
	// verison string should always be ASCII
	unsafe { CStr::from_ptr(ffi::opus_get_version_string()) }.to_str().unwrap()
}

// ============================================================================
// Encoder

pub struct Encoder {
	ptr: *mut ffi::OpusEncoder,
	channels: Channels,
}

impl Encoder {
	pub fn new(sample_rate: u32, channels: Channels, mode: CodingMode) -> Result<Encoder> {
		let mut error = 0;
		let ptr = unsafe { ffi::opus_encoder_create(
			sample_rate as i32,
			channels as c_int,
			mode as c_int,
			&mut error) };
		if error != ffi::OPUS_OK || ptr.is_null() {
			Err(Error::from_code("opus_encoder_create", error))
		} else {
			Ok(Encoder { ptr: ptr, channels: channels })
		}
	}

	pub fn encode(&mut self, input: &[i16], output: &mut [u8]) -> Result<usize> {
		let len = unsafe { ffi::opus_encode(self.ptr,
			input.as_ptr(), input.len() as c_int / self.channels as c_int,
			output.as_mut_ptr(), output.len() as c_int) };
		try!(check("opus_encode", len));
		Ok(len as usize)
	}

	pub fn encode_float(&mut self, input: &[f32], output: &mut [u8]) -> Result<usize> {
		let len = unsafe { ffi::opus_encode_float(self.ptr,
			input.as_ptr(), input.len() as c_int / self.channels as c_int,
			output.as_mut_ptr(), output.len() as c_int) };
		try!(check("opus_encode_float", len));
		Ok(len as usize)
	}

	pub fn reset_state(&mut self) -> Result<()> {
		check("opus_encoder_ctl(OPUS_RESET_STATE)", unsafe { ffi::opus_encoder_ctl(self.ptr, OPUS_RESET_STATE) })
	}

	pub fn get_final_range(&mut self) -> Result<u32> {
		let mut value = 0;
		let result = unsafe { ffi::opus_encoder_ctl(self.ptr, OPUS_GET_FINAL_RANGE, &mut value) };
		try!(check("opus_encoder_ctl(OPUS_GET_FINAL_RANGE)", result));
		Ok(value)
	}

	pub fn get_bandwidth(&mut self) -> Result<i32> {
		let mut value = 0;
		let result = unsafe { ffi::opus_encoder_ctl(self.ptr, OPUS_GET_BANDWIDTH, &mut value) };
		try!(check("opus_encoder_ctl(OPUS_GET_BANDWIDTH)", result));
		Ok(value)
	}

	pub fn get_sample_rate(&mut self) -> Result<i32> {
		let mut value = 0;
		let result = unsafe { ffi::opus_encoder_ctl(self.ptr, OPUS_GET_SAMPLE_RATE, &mut value) };
		try!(check("opus_encoder_ctl(OPUS_GET_SAMPLE_RATE)", result));
		Ok(value)
	}

	// TODO: Encoder-specific CTLs
}

impl Drop for Encoder {
	fn drop(&mut self) {
		unsafe { ffi::opus_encoder_destroy(self.ptr) }
	}
}

// ============================================================================
// Decoder

pub struct Decoder {
	ptr: *mut ffi::OpusDecoder,
	channels: Channels,
}

impl Decoder {
	pub fn new(sample_rate: u32, channels: Channels) -> Result<Decoder> {
		let mut error = 0;
		let ptr = unsafe { ffi::opus_decoder_create(
			sample_rate as i32,
			channels as c_int,
			&mut error) };
		if error != ffi::OPUS_OK || ptr.is_null() {
			Err(Error::from_code("opus_decoder_create", error))
		} else {
			Ok(Decoder { ptr: ptr, channels: channels })
		}
	}

	// TODO: support null inputs ("packet loss")
	pub fn decode(&mut self, input: &[u8], output: &mut [i16], fec: bool) -> Result<usize> {
		let len = unsafe { ffi::opus_decode(self.ptr,
			input.as_ptr(), input.len() as c_int,
			output.as_mut_ptr(), output.len() as c_int / self.channels as c_int,
			fec as c_int) };
		try!(check("opus_decode", len));
		Ok(len as usize)
	}

	pub fn decode_float(&mut self, input: &[u8], output: &mut [f32], fec: bool) -> Result<usize> {
		let len = unsafe { ffi::opus_decode_float(self.ptr,
			input.as_ptr(), input.len() as c_int,
			output.as_mut_ptr(), output.len() as c_int / self.channels as c_int,
			fec as c_int) };
		try!(check("opus_decode_float", len));
		Ok(len as usize)
	}

	pub fn get_nb_samples(&self, packet: &[u8]) -> Result<usize> {
		let len = unsafe { ffi::opus_decoder_get_nb_samples(self.ptr,
			packet.as_ptr(), packet.len() as i32) };
		try!(check("opus_decoder_get_nb_samples", len));
		Ok(len as usize)
	}

	// TODO: Generic CTLs
	// TODO: Decoder-specific CTLs
}

impl Drop for Decoder {
	fn drop(&mut self) {
		unsafe { ffi::opus_decoder_destroy(self.ptr) }
	}
}

// ============================================================================
// Packet Analysis

pub mod packet {
	use super::*;
	use super::{ffi, check};
	use std::{ptr, slice};
	use libc::c_int;

	pub fn get_bandwidth(packet: &[u8]) -> Result<Bandwidth> {
		if packet.len() < 1 {
			return Err(Error::from_code("opus_packet_get_bandwidth", ffi::OPUS_BAD_ARG))
		}
		let bandwidth = unsafe { ffi::opus_packet_get_bandwidth(packet.as_ptr()) };
		try!(check("opus_packet_get_bandwidth", bandwidth));
		match bandwidth {
			1101 => Ok(Bandwidth::Narrowband),
			1102 => Ok(Bandwidth::Mediumband),
			1103 => Ok(Bandwidth::Wideband),
			1104 => Ok(Bandwidth::Superwideband),
			1105 => Ok(Bandwidth::Fullband),
			_ => Err(Error::from_code("opus_packet_get_bandwidth", ffi::OPUS_BAD_ARG)),
		}
	}

	pub fn get_nb_channels(packet: &[u8]) -> Result<Channels> {
		if packet.len() < 1 {
			return Err(Error::from_code("opus_packet_get_nb_channels", ffi::OPUS_BAD_ARG))
		}
		let channels = unsafe { ffi::opus_packet_get_nb_channels(packet.as_ptr()) };
		try!(check("opus_packet_get_nb_channels", channels));
		match channels {
			1 => Ok(Channels::Mono),
			2 => Ok(Channels::Stereo),
			_ => Err(Error::from_code("opus_packet_get_nb_channels", ffi::OPUS_BAD_ARG)),
		}
	}

	pub fn get_nb_frames(packet: &[u8]) -> Result<usize> {
		let frames = unsafe { ffi::opus_packet_get_nb_frames(packet.as_ptr(), packet.len() as c_int) };
		try!(check("opus_packet_get_nb_frames", frames));
		Ok(frames as usize)
	}

	pub fn get_nb_samples(packet: &[u8], sample_rate: u32) -> Result<usize> {
		let frames = unsafe { ffi::opus_packet_get_nb_samples(
			packet.as_ptr(), packet.len() as c_int,
			sample_rate as c_int) };
		try!(check("opus_packet_get_nb_samples", frames));
		Ok(frames as usize)
	}

	pub fn get_samples_per_frame(packet: &[u8], sample_rate: u32) -> Result<usize> {
		if packet.len() < 1 {
			return Err(Error::from_code("opus_packet_get_samples_per_frame", ffi::OPUS_BAD_ARG))
		}
		let samples = unsafe { ffi::opus_packet_get_samples_per_frame(packet.as_ptr(), sample_rate as c_int) };
		try!(check("opus_packet_get_samples_per_frame", samples));
		Ok(samples as usize)
	}

	pub fn parse(packet: &[u8]) -> Result<Packet> {
		let mut toc: u8 = 0;
		let mut frames = [ptr::null(); 48];
		let mut sizes = [0i16; 48];
		let mut payload_offset: i32 = 0;
		let num_frames = unsafe { ffi::opus_packet_parse(
			packet.as_ptr(), packet.len() as c_int,
			&mut toc, frames.as_mut_ptr(),
			sizes.as_mut_ptr(), &mut payload_offset) };
		try!(check("opus_packet_parse", num_frames));

		let mut frames_vec = Vec::with_capacity(num_frames as usize);
		for i in 0..num_frames as usize {
			frames_vec.push(unsafe { slice::from_raw_parts(frames[i], sizes[i] as usize) });
		}

		Ok(Packet {
			toc: toc,
			frames: frames_vec,
			payload_offset: payload_offset as usize,
		})
	}

	pub struct Packet<'a> {
		pub toc: u8,
		pub frames: Vec<&'a [u8]>,
		pub payload_offset: usize,
	}
}

// ============================================================================
// Float Soft Clipping

pub struct SoftClip {
	channels: Channels,
	memory: [f32; 2],
}

impl SoftClip {
	pub fn new(channels: Channels) -> SoftClip {
		SoftClip { channels: channels, memory: [0.0; 2] }
	}

	pub fn apply(&mut self, signal: &mut [f32]) {
		unsafe { ffi::opus_pcm_soft_clip(
			signal.as_mut_ptr(),
			signal.len() as c_int / self.channels as c_int,
			self.channels as c_int,
			self.memory.as_mut_ptr()) };
	}
}

// ============================================================================
// TODO: Repacketizer

// ============================================================================
// TODO: Multistream API

// ============================================================================
// Error Handling

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug)]
pub struct Error {
	function: &'static str,
	description: &'static str,
	code: ErrorCode,
}

impl Error {
	fn from_code(what: &'static str, code: c_int) -> Error {
		// description should always be ASCII
		let description = unsafe { CStr::from_ptr(ffi::opus_strerror(code)) }.to_str().unwrap();
		let code = match code {
			-1 => ErrorCode::BadArg,
			-2 => ErrorCode::BufferTooSmall,
			-3 => ErrorCode::InternalError,
			-4 => ErrorCode::InvalidPacket,
			-5 => ErrorCode::Unimplemented,
			-6 => ErrorCode::InvalidState,
			-7 => ErrorCode::AllocFail,
			_ => ErrorCode::Unknown,
		};
		Error { function: what, description: description, code: code }
	}

	pub fn function(&self) -> &'static str { self.function }
	pub fn description(&self) -> &'static str { self.description }
	pub fn code(&self) -> ErrorCode { self.code }
}

impl std::fmt::Display for Error {
	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
		write!(f, "{}: {}", self.function, self.description)
	}
}

impl std::error::Error for Error {
	fn description(&self) -> &str {
		self.description
	}
}

fn check(what: &'static str, code: c_int) -> Result<()> {
	if code < 0 {
		Err(Error::from_code(what, code))
	} else {
		Ok(())
	}
}
<|endoftext|>


<commit_before>use std::fs;
use std::fs::File;
use std::io::prelude::*;
use std::io::{Cursor, SeekFrom, Take};
use std::marker::PhantomData;
use std::path::{Path, PathBuf};
use std::vec::Vec;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use fs2::FileExt;
use time;
use regex::Regex;

use data::{Entry, Hint};
use util::{xxhash32, XxHash32, get_file_handle};

const DATA_FILE_EXTENSION: &'static str = "cask.data";
const HINT_FILE_EXTENSION: &'static str = "cask.hint";
const LOCK_FILE_NAME: &'static str = "cask.lock";

const DEFAULT_SIZE_THRESHOLD: usize = 100 * 1024 * 1024;

pub struct Log {
    path: PathBuf,
    sync: bool,
    size_threshold: usize,
    lock_file: File,
    current_file_id: u32,
    active_data_file_path: PathBuf,
    active_data_file: File,
    active_hint_file: File,
    active_hint_file_hasher: XxHash32,
}

pub struct Entries<'a> {
    data_file: Take<File>,
    data_file_pos: u64,
    phantom: PhantomData<&'a ()>,
}

impl<'a> Iterator for Entries<'a> {
    type Item = (u64, Entry<'a>);

    fn next(&mut self) -> Option<(u64, Entry<'a>)> {
        if self.data_file.limit() == 0 {
            None
        } else {
            let entry = Entry::from_read(&mut self.data_file);
            let entry_pos = self.data_file_pos;

            self.data_file_pos += entry.size();

            Some((entry_pos, entry))
        }
    }
}

pub struct Hints<'a> {
    hint_file: Take<File>,
    phantom: PhantomData<&'a ()>,
}

impl<'a> Iterator for Hints<'a> {
    type Item = Hint<'a>;

    fn next(&mut self) -> Option<Hint<'a>> {
        if self.hint_file.limit() == 0 {
            None
        } else {
            Some(Hint::from_read(&mut self.hint_file))
        }
    }
}

pub struct RecreateHints<'a> {
    hint_file: File,
    hint_file_hasher: XxHash32,
    entries: Entries<'a>,
}

impl<'a> Iterator for RecreateHints<'a> {
    type Item = Hint<'a>;

    fn next(&mut self) -> Option<Hint<'a>> {
        self.entries.next().map(|e| {
            let (entry_pos, entry) = e;
            let hint = Hint::from(entry, entry_pos);
            hint.write_bytes(&mut self.hint_file);
            hint.write_bytes(&mut self.hint_file_hasher);
            hint
        })
    }
}

impl<'a> Drop for RecreateHints<'a> {
    fn drop(&mut self) {
        while self.next().is_some() {}
        self.hint_file
            .write_u32::<LittleEndian>(self.hint_file_hasher.get())
            .unwrap();
    }
}

impl Log {
    pub fn open(path: &str, sync: bool) -> Log {
        let path = PathBuf::from(path);

        if path.exists() {
            assert!(path.is_dir());
        } else {
            fs::create_dir(&path).unwrap();
        }

        let lock_file = File::create(path.join(LOCK_FILE_NAME)).unwrap();
        lock_file.try_lock_exclusive().unwrap();

        let current_file_id = time::now().to_timespec().sec as u32;
        let active_data_file_path = get_data_file_path(&path, current_file_id);
        let active_data_file = get_file_handle(&active_data_file_path, true);
        let active_hint_file = get_file_handle(&get_hint_file_path(&path, current_file_id), true);
        let active_hint_file_hasher = XxHash32::new();

        info!("Created new active data file {:?}", active_data_file_path);

        Log {
            path: path,
            sync: sync,
            size_threshold: DEFAULT_SIZE_THRESHOLD,
            lock_file: lock_file,
            current_file_id: current_file_id,
            active_data_file: active_data_file,
            active_data_file_path: active_data_file_path,
            active_hint_file: active_hint_file,
            active_hint_file_hasher: active_hint_file_hasher,
        }
    }

    pub fn find_files(&self) -> Vec<u32> {
        let files = fs::read_dir(&self.path).unwrap();

        lazy_static! {
            static ref RE: Regex =
                Regex::new(&format!("(\\d+).{}$", DATA_FILE_EXTENSION)).unwrap();
        }

        let mut files: Vec<u32> = files.flat_map(|f| {
                let file = f.unwrap();
                let file_metadata = file.metadata().unwrap();

                if file_metadata.is_file() {
                    let file_name = file.file_name();
                    let captures = RE.captures(file_name.to_str().unwrap());
                    captures.and_then(|c| c.at(1).and_then(|n| n.parse::<u32>().ok()))
                        .and_then(|id| if id != self.current_file_id {
                            Some(id)
                        } else {
                            None
                        })
                } else {
                    None
                }
            })
            .collect();

        files.sort();

        files
    }

    pub fn entries<'a>(&self, file_id: u32) -> Entries<'a> {
        let data_file_path = get_data_file_path(&self.path, file_id);
        info!("Loading data file: {:?}", data_file_path);
        let data_file = get_file_handle(&data_file_path, false);
        let data_file_size = data_file.metadata().unwrap().len();

        Entries {
            data_file: data_file.take(data_file_size),
            data_file_pos: 0,
            phantom: PhantomData,
        }
    }

    pub fn hints<'a>(&self, file_id: u32) -> Option<Hints<'a>> {
        let hint_file_path = get_hint_file_path(&self.path, file_id);
        if is_valid_hint_file(&hint_file_path) {
            info!("Loading hint file: {:?}", hint_file_path);
            let hint_file = get_file_handle(&hint_file_path, false);
            let hint_file_size = hint_file.metadata().unwrap().len();

            Some(Hints {
                hint_file: hint_file.take(hint_file_size - 4),
                phantom: PhantomData,
            })
        } else {
            None
        }
    }

    pub fn recreate_hints<'a>(&mut self, file_id: u32) -> RecreateHints<'a> {
        let hint_file_path = get_hint_file_path(&self.path, file_id);
        info!("Re-creating hint file: {:?}", hint_file_path);
        let hint_file = get_file_handle(&hint_file_path, true);
        let entries = self.entries(file_id);

        RecreateHints {
            hint_file: hint_file,
            hint_file_hasher: XxHash32::new(),
            entries: entries,
        }
    }

    pub fn read_entry<'a>(&self, file_id: u32, entry_pos: u64) -> Entry<'a> {
        let mut data_file = get_file_handle(&get_data_file_path(&self.path, file_id), false);
        data_file.seek(SeekFrom::Start(entry_pos)).unwrap();
        Entry::from_read(&mut data_file)
    }

    pub fn write_entry<'a>(&mut self, entry: &Entry<'a>) -> (u32, u64) {
        let mut active_data_file_pos = self.active_data_file.seek(SeekFrom::Current(0)).unwrap();

        if active_data_file_pos + entry.size() > self.size_threshold as u64 {
            info!("Active data file {:?} reached file limit",
                  self.active_data_file_path);

            self.close_active_file();
            self.new_active_file();

            active_data_file_pos = 0;
        }

        let hint = Hint::new(&entry, active_data_file_pos);

        entry.write_bytes(&mut self.active_data_file);
        hint.write_bytes(&mut self.active_hint_file);
        hint.write_bytes(&mut self.active_hint_file_hasher);

        if self.sync {
            self.active_data_file.sync_data().unwrap();
        }

        (self.current_file_id, active_data_file_pos)
    }

    fn close_active_file(&mut self) {
        if self.sync {
            self.active_data_file.sync_data().unwrap();
        }

        self.active_hint_file
            .write_u32::<LittleEndian>(self.active_hint_file_hasher.get())
            .unwrap();

        info!("Closed active data file {:?}", self.active_data_file_path);
    }

    fn new_active_file(&mut self) {
        self.current_file_id = time::now().to_timespec().sec as u32;

        self.active_data_file_path = get_data_file_path(&self.path, self.current_file_id);
        self.active_data_file = get_file_handle(&self.active_data_file_path, true);

        self.active_hint_file =
            get_file_handle(&get_hint_file_path(&self.path, self.current_file_id), true);

        self.active_hint_file_hasher = XxHash32::new();

        info!("Created new active data file {:?}",
              self.active_data_file_path);
    }
}

impl Drop for Log {
    fn drop(&mut self) {
        self.active_hint_file
            .write_u32::<LittleEndian>(self.active_hint_file_hasher.get())
            .unwrap();

        self.lock_file.unlock().unwrap();
    }
}

fn get_data_file_path(path: &Path, file_id: u32) -> PathBuf {
    path.join(file_id.to_string()).with_extension(DATA_FILE_EXTENSION)
}

fn get_hint_file_path(path: &Path, file_id: u32) -> PathBuf {
    path.join(file_id.to_string()).with_extension(HINT_FILE_EXTENSION)
}

fn is_valid_hint_file(path: &Path) -> bool {
    path.is_file() &&
    {
        let mut hint_file = get_file_handle(path, false);

        // FIXME: avoid reading the whole hint file into memory;
        let mut buf = Vec::new();
        hint_file.read_to_end(&mut buf).unwrap();

        buf.len() >= 4 &&
        {
            let hash = xxhash32(&buf[..buf.len() - 4]);

            let mut cursor = Cursor::new(&buf[buf.len() - 4..]);
            let checksum = cursor.read_u32::<LittleEndian>().unwrap();

            let valid = hash == checksum;

            if !valid {
                warn!("Found corrupt hint file: {:?}", &path);
            }

            valid
        }
    }
}
<commit_msg>move log iterators<commit_after>use std::fs;
use std::fs::File;
use std::io::prelude::*;
use std::io::{Cursor, SeekFrom, Take};
use std::marker::PhantomData;
use std::path::{Path, PathBuf};
use std::vec::Vec;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use fs2::FileExt;
use time;
use regex::Regex;

use data::{Entry, Hint};
use util::{xxhash32, XxHash32, get_file_handle};

const DATA_FILE_EXTENSION: &'static str = "cask.data";
const HINT_FILE_EXTENSION: &'static str = "cask.hint";
const LOCK_FILE_NAME: &'static str = "cask.lock";

const DEFAULT_SIZE_THRESHOLD: usize = 100 * 1024 * 1024;

pub struct Log {
    path: PathBuf,
    sync: bool,
    size_threshold: usize,
    lock_file: File,
    current_file_id: u32,
    active_data_file_path: PathBuf,
    active_data_file: File,
    active_hint_file: File,
    active_hint_file_hasher: XxHash32,
}

impl Log {
    pub fn open(path: &str, sync: bool) -> Log {
        let path = PathBuf::from(path);

        if path.exists() {
            assert!(path.is_dir());
        } else {
            fs::create_dir(&path).unwrap();
        }

        let lock_file = File::create(path.join(LOCK_FILE_NAME)).unwrap();
        lock_file.try_lock_exclusive().unwrap();

        let current_file_id = time::now().to_timespec().sec as u32;
        let active_data_file_path = get_data_file_path(&path, current_file_id);
        let active_data_file = get_file_handle(&active_data_file_path, true);
        let active_hint_file = get_file_handle(&get_hint_file_path(&path, current_file_id), true);
        let active_hint_file_hasher = XxHash32::new();

        info!("Created new active data file {:?}", active_data_file_path);

        Log {
            path: path,
            sync: sync,
            size_threshold: DEFAULT_SIZE_THRESHOLD,
            lock_file: lock_file,
            current_file_id: current_file_id,
            active_data_file: active_data_file,
            active_data_file_path: active_data_file_path,
            active_hint_file: active_hint_file,
            active_hint_file_hasher: active_hint_file_hasher,
        }
    }

    pub fn find_files(&self) -> Vec<u32> {
        let files = fs::read_dir(&self.path).unwrap();

        lazy_static! {
            static ref RE: Regex =
                Regex::new(&format!("(\\d+).{}$", DATA_FILE_EXTENSION)).unwrap();
        }

        let mut files: Vec<u32> = files.flat_map(|f| {
                let file = f.unwrap();
                let file_metadata = file.metadata().unwrap();

                if file_metadata.is_file() {
                    let file_name = file.file_name();
                    let captures = RE.captures(file_name.to_str().unwrap());
                    captures.and_then(|c| c.at(1).and_then(|n| n.parse::<u32>().ok()))
                        .and_then(|id| if id != self.current_file_id {
                            Some(id)
                        } else {
                            None
                        })
                } else {
                    None
                }
            })
            .collect();

        files.sort();

        files
    }

    pub fn entries<'a>(&self, file_id: u32) -> Entries<'a> {
        let data_file_path = get_data_file_path(&self.path, file_id);
        info!("Loading data file: {:?}", data_file_path);
        let data_file = get_file_handle(&data_file_path, false);
        let data_file_size = data_file.metadata().unwrap().len();

        Entries {
            data_file: data_file.take(data_file_size),
            data_file_pos: 0,
            phantom: PhantomData,
        }
    }

    pub fn hints<'a>(&self, file_id: u32) -> Option<Hints<'a>> {
        let hint_file_path = get_hint_file_path(&self.path, file_id);
        if is_valid_hint_file(&hint_file_path) {
            info!("Loading hint file: {:?}", hint_file_path);
            let hint_file = get_file_handle(&hint_file_path, false);
            let hint_file_size = hint_file.metadata().unwrap().len();

            Some(Hints {
                hint_file: hint_file.take(hint_file_size - 4),
                phantom: PhantomData,
            })
        } else {
            None
        }
    }

    pub fn recreate_hints<'a>(&mut self, file_id: u32) -> RecreateHints<'a> {
        let hint_file_path = get_hint_file_path(&self.path, file_id);
        info!("Re-creating hint file: {:?}", hint_file_path);
        let hint_file = get_file_handle(&hint_file_path, true);
        let entries = self.entries(file_id);

        RecreateHints {
            hint_file: hint_file,
            hint_file_hasher: XxHash32::new(),
            entries: entries,
        }
    }

    pub fn read_entry<'a>(&self, file_id: u32, entry_pos: u64) -> Entry<'a> {
        let mut data_file = get_file_handle(&get_data_file_path(&self.path, file_id), false);
        data_file.seek(SeekFrom::Start(entry_pos)).unwrap();
        Entry::from_read(&mut data_file)
    }

    pub fn write_entry<'a>(&mut self, entry: &Entry<'a>) -> (u32, u64) {
        let mut active_data_file_pos = self.active_data_file.seek(SeekFrom::Current(0)).unwrap();

        if active_data_file_pos + entry.size() > self.size_threshold as u64 {
            info!("Active data file {:?} reached file limit",
                  self.active_data_file_path);

            self.close_active_file();
            self.new_active_file();

            active_data_file_pos = 0;
        }

        let hint = Hint::new(&entry, active_data_file_pos);

        entry.write_bytes(&mut self.active_data_file);
        hint.write_bytes(&mut self.active_hint_file);
        hint.write_bytes(&mut self.active_hint_file_hasher);

        if self.sync {
            self.active_data_file.sync_data().unwrap();
        }

        (self.current_file_id, active_data_file_pos)
    }

    fn close_active_file(&mut self) {
        if self.sync {
            self.active_data_file.sync_data().unwrap();
        }

        self.active_hint_file
            .write_u32::<LittleEndian>(self.active_hint_file_hasher.get())
            .unwrap();

        info!("Closed active data file {:?}", self.active_data_file_path);
    }

    fn new_active_file(&mut self) {
        self.current_file_id = time::now().to_timespec().sec as u32;

        self.active_data_file_path = get_data_file_path(&self.path, self.current_file_id);
        self.active_data_file = get_file_handle(&self.active_data_file_path, true);

        self.active_hint_file =
            get_file_handle(&get_hint_file_path(&self.path, self.current_file_id), true);

        self.active_hint_file_hasher = XxHash32::new();

        info!("Created new active data file {:?}",
              self.active_data_file_path);
    }
}

impl Drop for Log {
    fn drop(&mut self) {
        self.active_hint_file
            .write_u32::<LittleEndian>(self.active_hint_file_hasher.get())
            .unwrap();

        self.lock_file.unlock().unwrap();
    }
}

pub struct Entries<'a> {
    data_file: Take<File>,
    data_file_pos: u64,
    phantom: PhantomData<&'a ()>,
}

impl<'a> Iterator for Entries<'a> {
    type Item = (u64, Entry<'a>);

    fn next(&mut self) -> Option<(u64, Entry<'a>)> {
        if self.data_file.limit() == 0 {
            None
        } else {
            let entry = Entry::from_read(&mut self.data_file);
            let entry_pos = self.data_file_pos;

            self.data_file_pos += entry.size();

            Some((entry_pos, entry))
        }
    }
}

pub struct Hints<'a> {
    hint_file: Take<File>,
    phantom: PhantomData<&'a ()>,
}

impl<'a> Iterator for Hints<'a> {
    type Item = Hint<'a>;

    fn next(&mut self) -> Option<Hint<'a>> {
        if self.hint_file.limit() == 0 {
            None
        } else {
            Some(Hint::from_read(&mut self.hint_file))
        }
    }
}

pub struct RecreateHints<'a> {
    hint_file: File,
    hint_file_hasher: XxHash32,
    entries: Entries<'a>,
}

impl<'a> Iterator for RecreateHints<'a> {
    type Item = Hint<'a>;

    fn next(&mut self) -> Option<Hint<'a>> {
        self.entries.next().map(|e| {
            let (entry_pos, entry) = e;
            let hint = Hint::from(entry, entry_pos);
            hint.write_bytes(&mut self.hint_file);
            hint.write_bytes(&mut self.hint_file_hasher);
            hint
        })
    }
}

impl<'a> Drop for RecreateHints<'a> {
    fn drop(&mut self) {
        while self.next().is_some() {}
        self.hint_file
            .write_u32::<LittleEndian>(self.hint_file_hasher.get())
            .unwrap();
    }
}

fn get_data_file_path(path: &Path, file_id: u32) -> PathBuf {
    path.join(file_id.to_string()).with_extension(DATA_FILE_EXTENSION)
}

fn get_hint_file_path(path: &Path, file_id: u32) -> PathBuf {
    path.join(file_id.to_string()).with_extension(HINT_FILE_EXTENSION)
}

fn is_valid_hint_file(path: &Path) -> bool {
    path.is_file() &&
    {
        let mut hint_file = get_file_handle(path, false);

        // FIXME: avoid reading the whole hint file into memory;
        let mut buf = Vec::new();
        hint_file.read_to_end(&mut buf).unwrap();

        buf.len() >= 4 &&
        {
            let hash = xxhash32(&buf[..buf.len() - 4]);

            let mut cursor = Cursor::new(&buf[buf.len() - 4..]);
            let checksum = cursor.read_u32::<LittleEndian>().unwrap();

            let valid = hash == checksum;

            if !valid {
                warn!("Found corrupt hint file: {:?}", &path);
            }

            valid
        }
    }
}
<|endoftext|>


<commit_before>use super::signal::*;
use super::value::*;

use std::cell::RefCell;

/// A hardware register, created by the [`Module`]::[`reg`] method.
///
/// # Examples
///
/// ```
/// use kaze::*;
///
/// let c = Context::new();
///
/// let m = c.module("my_module");
///
/// let my_reg = m.reg("my_reg", 32);
/// my_reg.default_value(0xfadebabeu32); // Optional
/// my_reg.drive_next(!my_reg.value);
/// m.output("my_output", my_reg.value);
/// ```
///
/// [`Module`]: ./struct.Module.html
/// [`reg`]: ./struct.Module.html#method.reg
#[must_use]
pub struct Register<'a> {
    pub(crate) data: &'a RegisterData<'a>,
    /// This `Register`'s current value.
    ///
    /// [`Signal`]: ./struct.Signal.html
    pub value: &'a Signal<'a>,
}

impl<'a> Register<'a> {
    pub fn default_value<V: Into<Value>>(&'a self, value: V) {
        // TODO: Panic if this register already has a default value
        // TODO: Value range check
        let value = value.into();
        *self.data.initial_value.borrow_mut() = Some(value);
    }

    pub fn drive_next(&'a self, n: &'a Signal<'a>) {
        // TODO: Ensure n is in the same module as self
        // TODO: Ensure n's bit_width is the same as self.value.data.bit_width
        // TODO: Ensure this register isn't already driven
        *self.data.next.borrow_mut() = Some(n);
    }
}

pub(crate) struct RegisterData<'a> {
    pub name: String,
    pub initial_value: RefCell<Option<Value>>,
    pub bit_width: u32,
    pub next: RefCell<Option<&'a Signal<'a>>>,
}
<commit_msg>Add more Register documentation<commit_after>use super::signal::*;
use super::value::*;

use std::cell::RefCell;

/// A hardware register, created by the [`Module`]::[`reg`] method.
///
/// A `Register` is a stateful component that behaves like a [D flip-flop](https://en.wikipedia.org/wiki/Flip-flop_(electronics)#D_flip-flop) (more precisely as a [positive-edge-triggered D flip-flop](https://en.wikipedia.org/wiki/Flip-flop_(electronics)#Classical_positive-edge-triggered_D_flip-flop)).
///
/// It always has a current value represented by the [`value`] field (often referred to as `Q`) and a next value specified by the [`drive_next`] method (often referred to as `D`).
/// It will hold its [`value`] until a positive edge of its [`Module`]'s implicit clock occurs, at which point [`value`] will be updated to reflect the next value.
///
/// Optionally, it also has a default value specified by the [`default_value`] method. If at any time its [`Module`]'s implicit reset is driven low, the register's [`value`] will reflect the default value.
/// Default values are used to provide a known register state on system power-on and reset, but are often omitted to reduce combinational logic (which ultimately is how default values are typically implemented), especially for registers on timing-critical data paths.
///
/// # Examples
///
/// ```
/// use kaze::*;
///
/// let c = Context::new();
///
/// let m = c.module("my_module");
///
/// let my_reg = m.reg("my_reg", 32);
/// my_reg.default_value(0xfadebabeu32); // Optional
/// my_reg.drive_next(!my_reg.value);
/// m.output("my_output", my_reg.value);
/// ```
///
/// [`default_value`]: #method.default_value
/// [`drive_next`]: #method.drive_next
/// [`Module`]: ./struct.Module.html
/// [`reg`]: ./struct.Module.html#method.reg
/// [`value`]: #structfield.value
#[must_use]
pub struct Register<'a> {
    pub(crate) data: &'a RegisterData<'a>,
    /// This `Register`'s current value.
    ///
    /// [`Signal`]: ./struct.Signal.html
    pub value: &'a Signal<'a>,
}

impl<'a> Register<'a> {
    pub fn default_value<V: Into<Value>>(&'a self, value: V) {
        // TODO: Panic if this register already has a default value
        // TODO: Value range check
        let value = value.into();
        *self.data.initial_value.borrow_mut() = Some(value);
    }

    pub fn drive_next(&'a self, n: &'a Signal<'a>) {
        // TODO: Ensure n is in the same module as self
        // TODO: Ensure n's bit_width is the same as self.value.data.bit_width
        // TODO: Ensure this register isn't already driven
        *self.data.next.borrow_mut() = Some(n);
    }
}

pub(crate) struct RegisterData<'a> {
    pub name: String,
    pub initial_value: RefCell<Option<Value>>,
    pub bit_width: u32,
    pub next: RefCell<Option<&'a Signal<'a>>>,
}
<|endoftext|>


<commit_before>//! Clippy wrappers around rustc's diagnostic functions.

use rustc_errors::{Applicability, CodeSuggestion, DiagnosticBuilder, Substitution, SubstitutionPart, SuggestionStyle};
use rustc_hir::HirId;
use rustc_lint::{LateContext, Lint, LintContext};
use rustc_span::source_map::{MultiSpan, Span};
use std::env;

/// Wrapper around `DiagnosticBuilder` that adds a link to Clippy documentation for the emitted lint
struct DiagnosticWrapper<'a>(DiagnosticBuilder<'a>);

impl<'a> Drop for DiagnosticWrapper<'a> {
    fn drop(&mut self) {
        self.0.emit();
    }
}

impl<'a> DiagnosticWrapper<'a> {
    fn docs_link(&mut self, lint: &'static Lint) {
        if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() {
            self.0.help(&format!(
                "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{}",
                &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| {
                    // extract just major + minor version and ignore patch versions
                    format!("rust-{}", n.rsplitn(2, '.').nth(1).unwrap())
                }),
                lint.name_lower().replacen("clippy::", "", 1)
            ));
        }
    }
}

/// Emit a basic lint message with a `msg` and a `span`.
///
/// This is the most primitive of our lint emission methods and can
/// be a good way to get a new lint started.
///
/// Usually it's nicer to provide more context for lint messages.
/// Be sure the output is understandable when you use this method.
///
/// # Example
///
/// ```ignore
/// error: usage of mem::forget on Drop type
///   --> $DIR/mem_forget.rs:17:5
///    |
/// 17 |     std::mem::forget(seven);
///    |     ^^^^^^^^^^^^^^^^^^^^^^^
/// ```
pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<MultiSpan>, msg: &str) {
    DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)).docs_link(lint);
}

/// Same as `span_lint` but with an extra `help` message.
///
/// Use this if you want to provide some general help but
/// can't provide a specific machine applicable suggestion.
///
/// The `help` message is not attached to any `Span`.
///
/// # Example
///
/// ```ignore
/// error: constant division of 0.0 with 0.0 will always result in NaN
///   --> $DIR/zero_div_zero.rs:6:25
///    |
/// 6  |     let other_f64_nan = 0.0f64 / 0.0;
///    |                         ^^^^^^^^^^^^
///    |
///    = help: Consider using `std::f64::NAN` if you would like a constant representing NaN
/// ```
pub fn span_lint_and_help<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, help: &str) {
    let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg));
    db.0.help(help);
    db.docs_link(lint);
}

/// Like `span_lint` but with a `note` section instead of a `help` message.
///
/// The `note` message is presented separately from the main lint message
/// and is attached to a specific span:
///
/// # Example
///
/// ```ignore
/// error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
///   --> $DIR/drop_forget_ref.rs:10:5
///    |
/// 10 |     forget(&SomeStruct);
///    |     ^^^^^^^^^^^^^^^^^^^
///    |
///    = note: `-D clippy::forget-ref` implied by `-D warnings`
/// note: argument has type &SomeStruct
///   --> $DIR/drop_forget_ref.rs:10:12
///    |
/// 10 |     forget(&SomeStruct);
///    |            ^^^^^^^^^^^
/// ```
pub fn span_lint_and_note<'a, T: LintContext>(
    cx: &'a T,
    lint: &'static Lint,
    span: Span,
    msg: &str,
    note_span: Span,
    note: &str,
) {
    let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg));
    if note_span == span {
        db.0.note(note);
    } else {
        db.0.span_note(note_span, note);
    }
    db.docs_link(lint);
}

pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F)
where
    F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>),
{
    let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg));
    f(&mut db.0);
    db.docs_link(lint);
}

pub fn span_lint_hir(cx: &LateContext<'_, '_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) {
    DiagnosticWrapper(cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg)).docs_link(lint);
}

pub fn span_lint_hir_and_then(
    cx: &LateContext<'_, '_>,
    lint: &'static Lint,
    hir_id: HirId,
    sp: Span,
    msg: &str,
    f: impl FnOnce(&mut DiagnosticBuilder<'_>),
) {
    let mut db = DiagnosticWrapper(cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg));
    f(&mut db.0);
    db.docs_link(lint);
}

/// Add a span lint with a suggestion on how to fix it.
///
/// These suggestions can be parsed by rustfix to allow it to automatically fix your code.
/// In the example below, `help` is `"try"` and `sugg` is the suggested replacement `".any(|x| x >
/// 2)"`.
///
/// ```ignore
/// error: This `.fold` can be more succinctly expressed as `.any`
/// --> $DIR/methods.rs:390:13
///     |
/// 390 |     let _ = (0..3).fold(false, |acc, x| acc || x > 2);
///     |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
///     |
///     = note: `-D fold-any` implied by `-D warnings`
/// ```
pub fn span_lint_and_sugg<'a, T: LintContext>(
    cx: &'a T,
    lint: &'static Lint,
    sp: Span,
    msg: &str,
    help: &str,
    sugg: String,
    applicability: Applicability,
) {
    span_lint_and_then(cx, lint, sp, msg, |db| {
        db.span_suggestion(sp, help, sugg, applicability);
    });
}

/// Create a suggestion made from several `span → replacement`.
///
/// Note: in the JSON format (used by `compiletest_rs`), the help message will
/// appear once per
/// replacement. In human-readable format though, it only appears once before
/// the whole suggestion.
pub fn multispan_sugg<I>(db: &mut DiagnosticBuilder<'_>, help_msg: String, sugg: I)
where
    I: IntoIterator<Item = (Span, String)>,
{
    let sugg = CodeSuggestion {
        substitutions: vec![Substitution {
            parts: sugg
                .into_iter()
                .map(|(span, snippet)| SubstitutionPart { snippet, span })
                .collect(),
        }],
        msg: help_msg,
        style: SuggestionStyle::ShowCode,
        applicability: Applicability::Unspecified,
    };
    db.suggestions.push(sugg);
}
<commit_msg>Auto merge of #5152 - flip1995:rustup, r=flip1995<commit_after>//! Clippy wrappers around rustc's diagnostic functions.

use rustc_errors::{Applicability, CodeSuggestion, DiagnosticBuilder, Substitution, SubstitutionPart, SuggestionStyle};
use rustc_hir::HirId;
use rustc_lint::{LateContext, Lint, LintContext};
use rustc_span::source_map::{MultiSpan, Span};
use std::env;

fn docs_link(db: &mut DiagnosticBuilder<'_>, lint: &'static Lint) {
    if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() {
        db.help(&format!(
            "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{}",
            &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| {
                // extract just major + minor version and ignore patch versions
                format!("rust-{}", n.rsplitn(2, '.').nth(1).unwrap())
            }),
            lint.name_lower().replacen("clippy::", "", 1)
        ));
    }
}

/// Emit a basic lint message with a `msg` and a `span`.
///
/// This is the most primitive of our lint emission methods and can
/// be a good way to get a new lint started.
///
/// Usually it's nicer to provide more context for lint messages.
/// Be sure the output is understandable when you use this method.
///
/// # Example
///
/// ```ignore
/// error: usage of mem::forget on Drop type
///   --> $DIR/mem_forget.rs:17:5
///    |
/// 17 |     std::mem::forget(seven);
///    |     ^^^^^^^^^^^^^^^^^^^^^^^
/// ```
pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<MultiSpan>, msg: &str) {
    cx.struct_span_lint(lint, sp, |ldb| {
        let mut db = ldb.build(msg);
        docs_link(&mut db, lint);
        db.emit();
    });
}

/// Same as `span_lint` but with an extra `help` message.
///
/// Use this if you want to provide some general help but
/// can't provide a specific machine applicable suggestion.
///
/// The `help` message is not attached to any `Span`.
///
/// # Example
///
/// ```ignore
/// error: constant division of 0.0 with 0.0 will always result in NaN
///   --> $DIR/zero_div_zero.rs:6:25
///    |
/// 6  |     let other_f64_nan = 0.0f64 / 0.0;
///    |                         ^^^^^^^^^^^^
///    |
///    = help: Consider using `std::f64::NAN` if you would like a constant representing NaN
/// ```
pub fn span_lint_and_help<'a, T: LintContext>(cx: &'a T, lint: &'static Lint, span: Span, msg: &str, help: &str) {
    cx.struct_span_lint(lint, span, |ldb| {
        let mut db = ldb.build(msg);
        db.help(help);
        docs_link(&mut db, lint);
        db.emit();
    });
}

/// Like `span_lint` but with a `note` section instead of a `help` message.
///
/// The `note` message is presented separately from the main lint message
/// and is attached to a specific span:
///
/// # Example
///
/// ```ignore
/// error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
///   --> $DIR/drop_forget_ref.rs:10:5
///    |
/// 10 |     forget(&SomeStruct);
///    |     ^^^^^^^^^^^^^^^^^^^
///    |
///    = note: `-D clippy::forget-ref` implied by `-D warnings`
/// note: argument has type &SomeStruct
///   --> $DIR/drop_forget_ref.rs:10:12
///    |
/// 10 |     forget(&SomeStruct);
///    |            ^^^^^^^^^^^
/// ```
pub fn span_lint_and_note<'a, T: LintContext>(
    cx: &'a T,
    lint: &'static Lint,
    span: Span,
    msg: &str,
    note_span: Span,
    note: &str,
) {
    cx.struct_span_lint(lint, span, |ldb| {
        let mut db = ldb.build(msg);
        if note_span == span {
            db.note(note);
        } else {
            db.span_note(note_span, note);
        }
        docs_link(&mut db, lint);
        db.emit();
    });
}

pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F)
where
    F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>),
{
    cx.struct_span_lint(lint, sp, |ldb| {
        let mut db = ldb.build(msg);
        f(&mut db);
        docs_link(&mut db, lint);
        db.emit();
    });
}

pub fn span_lint_hir(cx: &LateContext<'_, '_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) {
    cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |ldb| {
        let mut db = ldb.build(msg);
        docs_link(&mut db, lint);
        db.emit();
    });
}

pub fn span_lint_hir_and_then(
    cx: &LateContext<'_, '_>,
    lint: &'static Lint,
    hir_id: HirId,
    sp: Span,
    msg: &str,
    f: impl FnOnce(&mut DiagnosticBuilder<'_>),
) {
    cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |ldb| {
        let mut db = ldb.build(msg);
        f(&mut db);
        docs_link(&mut db, lint);
        db.emit();
    });
}

/// Add a span lint with a suggestion on how to fix it.
///
/// These suggestions can be parsed by rustfix to allow it to automatically fix your code.
/// In the example below, `help` is `"try"` and `sugg` is the suggested replacement `".any(|x| x >
/// 2)"`.
///
/// ```ignore
/// error: This `.fold` can be more succinctly expressed as `.any`
/// --> $DIR/methods.rs:390:13
///     |
/// 390 |     let _ = (0..3).fold(false, |acc, x| acc || x > 2);
///     |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
///     |
///     = note: `-D fold-any` implied by `-D warnings`
/// ```
pub fn span_lint_and_sugg<'a, T: LintContext>(
    cx: &'a T,
    lint: &'static Lint,
    sp: Span,
    msg: &str,
    help: &str,
    sugg: String,
    applicability: Applicability,
) {
    span_lint_and_then(cx, lint, sp, msg, |db| {
        db.span_suggestion(sp, help, sugg, applicability);
    });
}

/// Create a suggestion made from several `span → replacement`.
///
/// Note: in the JSON format (used by `compiletest_rs`), the help message will
/// appear once per
/// replacement. In human-readable format though, it only appears once before
/// the whole suggestion.
pub fn multispan_sugg<I>(db: &mut DiagnosticBuilder<'_>, help_msg: String, sugg: I)
where
    I: IntoIterator<Item = (Span, String)>,
{
    let sugg = CodeSuggestion {
        substitutions: vec![Substitution {
            parts: sugg
                .into_iter()
                .map(|(span, snippet)| SubstitutionPart { snippet, span })
                .collect(),
        }],
        msg: help_msg,
        style: SuggestionStyle::ShowCode,
        applicability: Applicability::Unspecified,
    };
    db.suggestions.push(sugg);
}
<|endoftext|>


<commit_before>use heartbeats_simple_sys::pow::*;
use std::mem;
use std::io::{self, Write};
use std::fs::File;

/// Contains the Heartbeat and its window data buffer.
pub struct HeartbeatPow {
    pub hb: heartbeat_pow_context,
    pub hbr: Vec<heartbeat_pow_record>,
    pub log: Option<File>,
}

impl HeartbeatPow {
    /// Allocate and initialize a new `Heartbeat`.
    pub fn new(window_size: usize,
               hwc_callback: Option<heartbeat_pow_window_complete>,
               mut log: Option<File>) -> Result<HeartbeatPow, &'static str> {
        let mut hbr: Vec<heartbeat_pow_record> = Vec::with_capacity(window_size);
        let hb: heartbeat_pow_context = unsafe {
            // must explicitly set size so we can read data later
            // (Rust isn't aware of native code modifying the buffer)
            hbr.set_len(window_size);
            let mut hb = mem::uninitialized();
            match heartbeat_pow_init(&mut hb,
                                     hbr.capacity() as u64,
                                     hbr.as_mut_ptr(),
                                     hwc_callback) {
                0 => hb,
                _ => return Err("Failed to initialize heartbeat")
            }
        };
        // write header to log file if there is one
        if let Some(ref mut l) = log {
            l.write_all("HB    Tag    Work    Start_Time    End_time    \
                Global_Perf    Window_Perf    Instant_Perf    \
                Start_Energy    End_Energy    \
                Global_Pwr    Window_Pwr    Instant_Pwr\n".as_bytes()).unwrap()
        }
        Ok(HeartbeatPow { hb: hb, hbr: hbr, log: log, })
    }

    /// Issue a heartbeat
    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     start_time: u64,
                     end_time: u64,
                     start_energy: u64,
                     end_energy: u64) {
        unsafe {
            heartbeat_pow(&mut self.hb, tag, work, start_time, end_time, start_energy, end_energy)
        }
    }

    fn write_log(r: &heartbeat_pow_record, l: &mut File) -> io::Result<usize> {
        l.write(format!("{}    {}    {}    {}    {}    \
                         {}    {}    {}    \
                         {}    {}    \
                         {}    {}    {}\n",
                        r.id, r.user_tag, r.work, r.start_time, r.end_time,
                        r.perf.global, r.perf.window, r.perf.instant,
                        r.start_energy, r.end_energy,
                        r.pwr.global, r.pwr.window, r.pwr.instant).as_bytes())
    }

    /// Rust-only function that logs the buffer (up to buffer_index) to a file.
    pub fn log_to_buffer_index(&mut self) -> io::Result<()> {
        match self.log {
            Some(ref mut l) => {
                for i in 0..self.hb.ws.buffer_index {
                    match HeartbeatPow::write_log(self.hbr.get(i as usize).unwrap(), l) {
                        Ok(_) => (),
                        Err(e) => return Err(e),
                    }
                }
                l.flush()
            }
            None => Ok(())
        }
    }
}

#[cfg(test)]
mod test {
    use super::HeartbeatPow;
    use std::fs::File;

    #[test]
    fn test_simple() {
        const TIME_INC: u64 = 1000000000;
        const ENERGY_INC: u64 = 1000000;
        let mut hb = HeartbeatPow::new(5, None, None).unwrap();
        let mut start_time: u64 = 0;
        let mut end_time: u64 = TIME_INC;
        let mut start_energy: u64 = 0;
        let mut end_energy: u64 = ENERGY_INC;
        for tag in 0..10 {
            hb.heartbeat(tag, 1, start_time, end_time, start_energy, end_energy);
            start_time = end_time;
            end_time += TIME_INC;
            start_energy = end_energy;
            end_energy += ENERGY_INC;
        }
    }

    #[test]
    fn test_file() {
        let mut hb = HeartbeatPow::new(5, None, Some(File::create("foo.log").unwrap())).unwrap();
        hb.heartbeat(0, 1, 0, 1, 0, 0);
        hb.log_to_buffer_index().unwrap();
    }
}
<commit_msg>Update logging to support new fields<commit_after>use heartbeats_simple_sys::pow::*;
use std::mem;
use std::io::{self, Write};
use std::fs::File;

/// Contains the Heartbeat and its window data buffer.
pub struct HeartbeatPow {
    pub hb: heartbeat_pow_context,
    pub hbr: Vec<heartbeat_pow_record>,
    pub log: Option<File>,
}

impl HeartbeatPow {
    /// Allocate and initialize a new `Heartbeat`.
    pub fn new(window_size: usize,
               hwc_callback: Option<heartbeat_pow_window_complete>,
               mut log: Option<File>) -> Result<HeartbeatPow, &'static str> {
        let mut hbr: Vec<heartbeat_pow_record> = Vec::with_capacity(window_size);
        let hb: heartbeat_pow_context = unsafe {
            // must explicitly set size so we can read data later
            // (Rust isn't aware of native code modifying the buffer)
            hbr.set_len(window_size);
            let mut hb = mem::uninitialized();
            match heartbeat_pow_init(&mut hb,
                                     hbr.capacity() as u64,
                                     hbr.as_mut_ptr(),
                                     hwc_callback) {
                0 => hb,
                _ => return Err("Failed to initialize heartbeat")
            }
        };
        // write header to log file if there is one
        if let Some(ref mut l) = log {
            l.write_all("HB    Tag    \
              Global_Work    Window_Work    Work    \
              Global_Time    Window_Time    Start_Time    End_Time    \
              Global_Perf    Window_Perf    Instant_Perf    \
              Global_Energy    Window_Energy    Start_Energy    End_Energy    \
              Global_Pwr    Window_Pwr    Instant_Pwr\n".as_bytes()).unwrap()
        }
        Ok(HeartbeatPow { hb: hb, hbr: hbr, log: log, })
    }

    /// Issue a heartbeat
    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     start_time: u64,
                     end_time: u64,
                     start_energy: u64,
                     end_energy: u64) {
        unsafe {
            heartbeat_pow(&mut self.hb, tag, work, start_time, end_time, start_energy, end_energy)
        }
    }

    fn write_log(r: &heartbeat_pow_record, l: &mut File) -> io::Result<usize> {
        l.write(format!("{}    {}    \
                         {}    {}    {}    \
                         {}    {}    {}    {}    \
                         {}    {}    {}    \
                         {}    {}    {}    {}    \
                         {}    {}    {}\n",
                        r.id, r.user_tag,
                        r.wd.global, r.wd.window, r.work,
                        r.td.global, r.td.window, r.start_time, r.end_time,
                        r.perf.global, r.perf.window, r.perf.instant,
                        r.ed.global, r.ed.window, r.start_energy, r.end_energy,
                        r.pwr.global, r.pwr.window, r.pwr.instant).as_bytes())
    }

    /// Rust-only function that logs the buffer (up to buffer_index) to a file.
    pub fn log_to_buffer_index(&mut self) -> io::Result<()> {
        match self.log {
            Some(ref mut l) => {
                for i in 0..self.hb.ws.buffer_index {
                    match HeartbeatPow::write_log(self.hbr.get(i as usize).unwrap(), l) {
                        Ok(_) => (),
                        Err(e) => return Err(e),
                    }
                }
                l.flush()
            }
            None => Ok(())
        }
    }
}

#[cfg(test)]
mod test {
    use super::HeartbeatPow;
    use std::fs::File;

    #[test]
    fn test_simple() {
        const TIME_INC: u64 = 1000000000;
        const ENERGY_INC: u64 = 1000000;
        let mut hb = HeartbeatPow::new(5, None, None).unwrap();
        let mut start_time: u64 = 0;
        let mut end_time: u64 = TIME_INC;
        let mut start_energy: u64 = 0;
        let mut end_energy: u64 = ENERGY_INC;
        for tag in 0..10 {
            hb.heartbeat(tag, 1, start_time, end_time, start_energy, end_energy);
            start_time = end_time;
            end_time += TIME_INC;
            start_energy = end_energy;
            end_energy += ENERGY_INC;
        }
    }

    #[test]
    fn test_file() {
        let mut hb = HeartbeatPow::new(5, None, Some(File::create("foo.log").unwrap())).unwrap();
        hb.heartbeat(0, 1, 0, 1, 0, 0);
        hb.log_to_buffer_index().unwrap();
    }
}
<|endoftext|>