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

//! this is context class to use autograd.

extern crate std;

// TODO #[inline] where appropriate.

pub trait Context<T: std::num::Float>: std::marker::Sized {
    // public functions

    fn new() -> Self {
        // TODO implement correctly.
        // let size: usize = (std::u32::MAX as usize) / 2;
        Context::<T>::new_tmp()
    }

    fn new_variable(&self, value: T) -> super::float::Float<T, Self> {
        super::float::float_new(value, <Self as Context<T>>::get_new_variable_index())
    }

    fn differentiate(&self, float: super::float::Float<T, Self>) {
        unsafe {
            // let count = <Self as Context<T>>::get_recorded_variables_count();
            *<Self as Context<T>>::get_result_derivatives().offset(super::float::float_get_index(&float) as isize) = std::num::Float::one();
            for i in (0..(*<Self as Context<T>>::get_recorded_entries_count())).rev() {
                let lhs_index = *<Self as Context<T>>::get_lhs_indices().offset(i as isize);
                let rhs_index = *<Self as Context<T>>::get_rhs_indices().offset(i as isize);
                *<Self as Context<T>>::get_result_derivatives().offset(rhs_index as isize) =
                    *<Self as Context<T>>::get_result_derivatives().offset(rhs_index as isize)
                    + (*<Self as Context<T>>::get_result_derivatives().offset(lhs_index as isize)
                       * *<Self as Context<T>>::get_adjoints().offset(i as isize));

                let t = *<Self as Context<T>>::get_result_derivatives().offset(i as isize);
            }
        }
    }

    fn get_derivative(&self, float: super::float::Float<T, Self>) -> T {
        let float_index_offset = super::float::float_get_index(&float) as isize;
        unsafe {
            *<Self as Context<T>>::get_result_derivatives().offset(float_index_offset)
        }
    }

    // Private functions

    fn get_new_variable_index() -> usize {
        let count = <Self as Context<T>>::get_recorded_variables_count();
        let index = *count;
        *count += 1;
        index
    }

    fn get_new_entry_index() -> usize {
        let count = <Self as Context<T>>::get_recorded_entries_count();
        let index = *count;
        *count += 1;
        index
    }

    fn unary_operation(adjoint: T, rhs_index: usize) -> usize {
        let lhs_index = <Self as Context<T>>::get_new_variable_index();
        let recorded_entries_count_offset = <Self as Context<T>>::get_new_entry_index() as isize;
        unsafe {
            *<Self as Context<T>>::get_adjoints().offset(recorded_entries_count_offset) = adjoint;
            *<Self as Context<T>>::get_lhs_indices().offset(recorded_entries_count_offset) = lhs_index;
            *<Self as Context<T>>::get_rhs_indices().offset(recorded_entries_count_offset) = rhs_index;
        }
        lhs_index
    }

    fn binary_operation(adjoints: &[T; 2],
                        rhs_indices: &[usize; 2]) -> usize {
        let lhs_index = <Self as Context<T>>::get_new_variable_index();
        let recorded_entries_count_offset_1 = <Self as Context<T>>::get_new_entry_index() as isize;
        let recorded_entries_count_offset_2 = <Self as Context<T>>::get_new_entry_index() as isize;

        unsafe {
            // TODO is indexing inefficient?
            *<Self as Context<T>>::get_adjoints().offset(recorded_entries_count_offset_1) = adjoints[0];
            *<Self as Context<T>>::get_lhs_indices().offset(recorded_entries_count_offset_1) = lhs_index;
            *<Self as Context<T>>::get_rhs_indices().offset(recorded_entries_count_offset_1) = rhs_indices[0];

            *<Self as Context<T>>::get_adjoints().offset(recorded_entries_count_offset_2) = adjoints[1];
            *<Self as Context<T>>::get_lhs_indices().offset(recorded_entries_count_offset_2) = lhs_index;
            *<Self as Context<T>>::get_rhs_indices().offset(recorded_entries_count_offset_2) = rhs_indices[1];
        }
        lhs_index
    }

    fn get_recorded_variables_count<'a>() -> &'a mut usize;
    fn get_recorded_entries_count<'a>() -> &'a mut usize;
    fn get_adjoints<'a>() -> &'a mut*mut T;
    fn get_lhs_indices<'a>() -> &'a mut*mut usize;
    fn get_rhs_indices<'a>() -> &'a mut*mut usize;
    fn get_result_derivatives<'a>() -> &'a mut*mut T;

    fn new_tmp() -> Self;
}

pub struct ContextImpl {
    // TODO this is to keep the struct construction private. Remove when we don't need it.
    _private: (),
}

impl Context<f32> for ContextImpl {
    fn get_recorded_variables_count<'a>() -> &'a mut usize {
        #[thread_local]
        static mut ptr : usize = 0;
        unsafe {
            &mut ptr
        }
    }
    fn get_recorded_entries_count<'a>() -> &'a mut usize {
        #[thread_local]
        static mut ptr : usize = 0;
        unsafe {
            &mut ptr
        }
    }
    fn get_adjoints<'a>() -> &'a mut*mut f32 {
        #[thread_local]
        static mut ptr : *mut f32 = 0 as *mut f32;
        unsafe {
            &mut ptr
        }
    }
    fn get_lhs_indices<'a>() -> &'a mut*mut usize {
        #[thread_local]
        static mut ptr : *mut usize = 0 as *mut usize;
        unsafe {
            &mut ptr
        }
    }
    fn get_rhs_indices<'a>() -> &'a mut*mut usize{
        #[thread_local]
        static mut ptr : *mut usize = 0 as *mut usize;
        unsafe {
            &mut ptr
        }
    }

    fn get_result_derivatives<'a>() -> &'a mut*mut f32 {
        #[thread_local]
        static mut ptr : *mut f32 = 0 as *mut f32;
        unsafe {
            &mut ptr
        }
    }

    fn new_tmp() -> Self {
        // TODO implement

        let capacity: usize = 1000;

        // TODO use checked_mul?
        //      example : let usize_size = capacity.checked_mul(std::mem::size_of::<usize>()).expect("capacity overflow");
        let usize_size = capacity * std::mem::size_of::<usize>();
        let f32_size = capacity * std::mem::size_of::<f32>();
        // std::rt::heap::allocate(f32_size, mem::min_align_of::<T>())

        unsafe {
            *<Self as Context<f32>>::get_recorded_variables_count() = 0;
            *<Self as Context<f32>>::get_recorded_entries_count() = 0;
            *<Self as Context<f32>>::get_adjoints() = std::rt::heap::allocate(f32_size, std::mem::align_of::<f32>()) as *mut f32;
            *<Self as Context<f32>>::get_lhs_indices() = std::rt::heap::allocate(usize_size, std::mem::align_of::<usize>()) as *mut usize;
            *<Self as Context<f32>>::get_rhs_indices() = std::rt::heap::allocate(usize_size, std::mem::align_of::<usize>()) as *mut usize;
            // TODO we don't have to allocate get_result_derivatives now, isn't it?
            *<Self as Context<f32>>::get_result_derivatives() = std::rt::heap::allocate(f32_size, std::mem::align_of::<f32>()) as *mut f32;
        }
        ContextImpl{_private: ()}
    }
}

// TODO implement safe lock mutex.
// impl ContextImpl {
//     fn get_mutex() {
//         #[thread_local]
//         static MUTEX : std::sync::StaticMutex = std::sync::MUTEX_INIT;
//     }
// }

impl std::ops::Drop for ContextImpl {
    fn drop(&mut self) {
        // *Context::<f32>::get_recorded_variables_count(None::<Self>) = 0;
        // *Context::<f32>::get_adjoints(None::<Self>) = 0;
        // TODO implement.

        let capacity: usize = 1000;
        let usize_size = capacity * std::mem::size_of::<usize>();
        let f32_size = capacity * std::mem::size_of::<f32>();

        unsafe {
            std::rt::heap::deallocate(*<Self as Context<f32>>::get_adjoints() as *mut u8, f32_size, std::mem::align_of::<f32>());
            std::rt::heap::deallocate(*<Self as Context<f32>>::get_lhs_indices() as *mut u8, usize_size, std::mem::align_of::<usize>());
            std::rt::heap::deallocate(*<Self as Context<f32>>::get_rhs_indices() as *mut u8, usize_size, std::mem::align_of::<usize>());
            std::rt::heap::deallocate(*<Self as Context<f32>>::get_result_derivatives() as *mut u8, f32_size, std::mem::align_of::<f32>());
        }
    }
}
<commit_msg>Put contributor license agreement TODO.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// TODO Setup contributor license agreement.

//! this is context class to use autograd.

extern crate std;

// TODO #[inline] where appropriate.

pub trait Context<T: std::num::Float>: std::marker::Sized {
    // public functions

    fn new() -> Self {
        // TODO implement correctly.
        // let size: usize = (std::u32::MAX as usize) / 2;
        Context::<T>::new_tmp()
    }

    fn new_variable(&self, value: T) -> super::float::Float<T, Self> {
        super::float::float_new(value, <Self as Context<T>>::get_new_variable_index())
    }

    fn differentiate(&self, float: super::float::Float<T, Self>) {
        unsafe {
            // let count = <Self as Context<T>>::get_recorded_variables_count();
            *<Self as Context<T>>::get_result_derivatives().offset(super::float::float_get_index(&float) as isize) = std::num::Float::one();
            for i in (0..(*<Self as Context<T>>::get_recorded_entries_count())).rev() {
                let lhs_index = *<Self as Context<T>>::get_lhs_indices().offset(i as isize);
                let rhs_index = *<Self as Context<T>>::get_rhs_indices().offset(i as isize);
                *<Self as Context<T>>::get_result_derivatives().offset(rhs_index as isize) =
                    *<Self as Context<T>>::get_result_derivatives().offset(rhs_index as isize)
                    + (*<Self as Context<T>>::get_result_derivatives().offset(lhs_index as isize)
                       * *<Self as Context<T>>::get_adjoints().offset(i as isize));

                let t = *<Self as Context<T>>::get_result_derivatives().offset(i as isize);
            }
        }
    }

    fn get_derivative(&self, float: super::float::Float<T, Self>) -> T {
        let float_index_offset = super::float::float_get_index(&float) as isize;
        unsafe {
            *<Self as Context<T>>::get_result_derivatives().offset(float_index_offset)
        }
    }

    // Private functions

    fn get_new_variable_index() -> usize {
        let count = <Self as Context<T>>::get_recorded_variables_count();
        let index = *count;
        *count += 1;
        index
    }

    fn get_new_entry_index() -> usize {
        let count = <Self as Context<T>>::get_recorded_entries_count();
        let index = *count;
        *count += 1;
        index
    }

    fn unary_operation(adjoint: T, rhs_index: usize) -> usize {
        let lhs_index = <Self as Context<T>>::get_new_variable_index();
        let recorded_entries_count_offset = <Self as Context<T>>::get_new_entry_index() as isize;
        unsafe {
            *<Self as Context<T>>::get_adjoints().offset(recorded_entries_count_offset) = adjoint;
            *<Self as Context<T>>::get_lhs_indices().offset(recorded_entries_count_offset) = lhs_index;
            *<Self as Context<T>>::get_rhs_indices().offset(recorded_entries_count_offset) = rhs_index;
        }
        lhs_index
    }

    fn binary_operation(adjoints: &[T; 2],
                        rhs_indices: &[usize; 2]) -> usize {
        let lhs_index = <Self as Context<T>>::get_new_variable_index();
        let recorded_entries_count_offset_1 = <Self as Context<T>>::get_new_entry_index() as isize;
        let recorded_entries_count_offset_2 = <Self as Context<T>>::get_new_entry_index() as isize;

        unsafe {
            // TODO is indexing inefficient?
            *<Self as Context<T>>::get_adjoints().offset(recorded_entries_count_offset_1) = adjoints[0];
            *<Self as Context<T>>::get_lhs_indices().offset(recorded_entries_count_offset_1) = lhs_index;
            *<Self as Context<T>>::get_rhs_indices().offset(recorded_entries_count_offset_1) = rhs_indices[0];

            *<Self as Context<T>>::get_adjoints().offset(recorded_entries_count_offset_2) = adjoints[1];
            *<Self as Context<T>>::get_lhs_indices().offset(recorded_entries_count_offset_2) = lhs_index;
            *<Self as Context<T>>::get_rhs_indices().offset(recorded_entries_count_offset_2) = rhs_indices[1];
        }
        lhs_index
    }

    fn get_recorded_variables_count<'a>() -> &'a mut usize;
    fn get_recorded_entries_count<'a>() -> &'a mut usize;
    fn get_adjoints<'a>() -> &'a mut*mut T;
    fn get_lhs_indices<'a>() -> &'a mut*mut usize;
    fn get_rhs_indices<'a>() -> &'a mut*mut usize;
    fn get_result_derivatives<'a>() -> &'a mut*mut T;

    fn new_tmp() -> Self;
}

pub struct ContextImpl {
    // TODO this is to keep the struct construction private. Remove when we don't need it.
    _private: (),
}

impl Context<f32> for ContextImpl {
    fn get_recorded_variables_count<'a>() -> &'a mut usize {
        #[thread_local]
        static mut ptr : usize = 0;
        unsafe {
            &mut ptr
        }
    }
    fn get_recorded_entries_count<'a>() -> &'a mut usize {
        #[thread_local]
        static mut ptr : usize = 0;
        unsafe {
            &mut ptr
        }
    }
    fn get_adjoints<'a>() -> &'a mut*mut f32 {
        #[thread_local]
        static mut ptr : *mut f32 = 0 as *mut f32;
        unsafe {
            &mut ptr
        }
    }
    fn get_lhs_indices<'a>() -> &'a mut*mut usize {
        #[thread_local]
        static mut ptr : *mut usize = 0 as *mut usize;
        unsafe {
            &mut ptr
        }
    }
    fn get_rhs_indices<'a>() -> &'a mut*mut usize{
        #[thread_local]
        static mut ptr : *mut usize = 0 as *mut usize;
        unsafe {
            &mut ptr
        }
    }

    fn get_result_derivatives<'a>() -> &'a mut*mut f32 {
        #[thread_local]
        static mut ptr : *mut f32 = 0 as *mut f32;
        unsafe {
            &mut ptr
        }
    }

    fn new_tmp() -> Self {
        // TODO implement

        let capacity: usize = 1000;

        // TODO use checked_mul?
        //      example : let usize_size = capacity.checked_mul(std::mem::size_of::<usize>()).expect("capacity overflow");
        let usize_size = capacity * std::mem::size_of::<usize>();
        let f32_size = capacity * std::mem::size_of::<f32>();
        // std::rt::heap::allocate(f32_size, mem::min_align_of::<T>())

        unsafe {
            *<Self as Context<f32>>::get_recorded_variables_count() = 0;
            *<Self as Context<f32>>::get_recorded_entries_count() = 0;
            *<Self as Context<f32>>::get_adjoints() = std::rt::heap::allocate(f32_size, std::mem::align_of::<f32>()) as *mut f32;
            *<Self as Context<f32>>::get_lhs_indices() = std::rt::heap::allocate(usize_size, std::mem::align_of::<usize>()) as *mut usize;
            *<Self as Context<f32>>::get_rhs_indices() = std::rt::heap::allocate(usize_size, std::mem::align_of::<usize>()) as *mut usize;
            // TODO we don't have to allocate get_result_derivatives now, isn't it?
            *<Self as Context<f32>>::get_result_derivatives() = std::rt::heap::allocate(f32_size, std::mem::align_of::<f32>()) as *mut f32;
        }
        ContextImpl{_private: ()}
    }
}

// TODO implement safe lock mutex.
// impl ContextImpl {
//     fn get_mutex() {
//         #[thread_local]
//         static MUTEX : std::sync::StaticMutex = std::sync::MUTEX_INIT;
//     }
// }

impl std::ops::Drop for ContextImpl {
    fn drop(&mut self) {
        // *Context::<f32>::get_recorded_variables_count(None::<Self>) = 0;
        // *Context::<f32>::get_adjoints(None::<Self>) = 0;
        // TODO implement.

        let capacity: usize = 1000;
        let usize_size = capacity * std::mem::size_of::<usize>();
        let f32_size = capacity * std::mem::size_of::<f32>();

        unsafe {
            std::rt::heap::deallocate(*<Self as Context<f32>>::get_adjoints() as *mut u8, f32_size, std::mem::align_of::<f32>());
            std::rt::heap::deallocate(*<Self as Context<f32>>::get_lhs_indices() as *mut u8, usize_size, std::mem::align_of::<usize>());
            std::rt::heap::deallocate(*<Self as Context<f32>>::get_rhs_indices() as *mut u8, usize_size, std::mem::align_of::<usize>());
            std::rt::heap::deallocate(*<Self as Context<f32>>::get_result_derivatives() as *mut u8, f32_size, std::mem::align_of::<f32>());
        }
    }
}
<|endoftext|>


<commit_before>
use {Field, Borrowed, Value};
use vecmath::{rotate_radians, multiply, translate, scale, shear, identity};
use {Transform2d, Matrix2d};
use {ColorContext, EllipseContext, PolygonContext, RectangleContext};
use {AddColor, AddEllipse, AddPolygon, AddRectangle};
use {View};

/// Drawing 2d context.
pub struct Context<'a> {
    /// Base/original transformation.
    pub base: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
}

impl<'a> Transform2d<'a> for Context<'a> {
    #[inline(always)]
    fn trans(&'a self, x: f64, y: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let trans = translate(x, y);
                 multiply(&trans, self.transform.get())
            }),
        }
    }

    #[inline(always)]
    fn trans_local(&'a self, x: f64, y: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let trans = translate(x, y);
                 multiply(self.transform.get(), &trans)
            }),
        }
    }

    #[inline(always)]
    fn rot_rad(&'a self, angle: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let rot = rotate_radians(angle);
                multiply(&rot, self.transform.get())
            }),
        }
    }

    #[inline(always)]
    fn rot_rad_local(&'a self, angle: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let rot = rotate_radians(angle);
                multiply(self.transform.get(), &rot)
            }),
        }
    }

    #[inline(always)]
    fn scale(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let scale = scale(sx, sy);
                multiply(&scale, self.transform.get())
            }),
        }
    }

    #[inline(always)]
    fn scale_local(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let scale = scale(sx, sy);
                multiply(self.transform.get(), &scale)
            }),
        }
    }

    #[inline(always)]
    fn shear(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let shear = shear(sx, sy);
                multiply(&shear, self.transform.get())
            }),
        }
    }

    #[inline(always)]
    fn shear_local(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let shear = shear(sx, sy);
                multiply(self.transform.get(), &shear)
            }),
        }
    }
}

impl<'a> Context<'a> {
    /// Creates a new drawing context.
    pub fn new() -> Context {
        Context {
            base:  Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            transform: Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
        }
    }
}

#[test]
fn test_context() {
    let c = Context::new();
    {
        let d = c.trans(20.0, 40.0);
        let d = d.trans(10.0, 10.0);
        assert_eq!(d.transform.get()[2], 30.0);
        assert_eq!(d.transform.get()[5], 50.0);
    }
    assert_eq!(c.transform.get()[2], 0.0);
    assert_eq!(c.transform.get()[5], 0.0);

    let c = c.rot_deg(90.0);
    assert!((c.transform.get()[0] - 0.0).abs() < 0.00001);
    assert!((c.transform.get()[1] - 1.0).abs() < 0.00001);
}

#[test]
fn test_scale() {
    let c = Context::new();
    let c = c.scale(2.0, 3.0);
    assert!((c.transform.get()[0] - 2.0).abs() < 0.00001);
    assert!((c.transform.get()[4] - 3.0).abs() < 0.00001);
}

impl<'a> AddRectangle<'a, RectangleContext<'a>> for Context<'a> {
    #[inline(always)]
    fn rect(&'a self, x: f64, y: f64, w: f64, h: f64) -> RectangleContext<'a> {
        RectangleContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value([x, y, w, h]),
        }
    }
}

#[test]
fn test_rect() {
    let c = Context::new();
    let d = c.rect(0.0, 0.0, 100.0, 50.0);
    assert_eq!(d.rect.get()[2], 100.0);
}

impl<'a> AddColor<'a, ColorContext<'a>> for Context<'a> {
    #[inline(always)]
    fn rgba(&'a self, r: f32, g: f32, b: f32, a: f32) -> ColorContext<'a> {
        ColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Value([r, g, b, a]),
        }
    }
}

#[test]
fn test_rgba() {
    let c = Context::new();
    let d: ColorContext = c.rgba(1.0, 0.0, 0.0, 1.0);
    assert_eq!(d.color.get()[0], 1.0);
}

impl<'a> AddEllipse<'a, EllipseContext<'a>> for Context<'a> {
    #[inline(always)]
    fn ellipse(&'a self, x: f64, y: f64, w: f64, h: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value([x, y, w, h]),
        }
    }
}

#[test]
fn test_ellipse() {
    let c = Context::new();
    let d: EllipseContext = c.ellipse(0.0, 0.0, 100.0, 100.0);
    assert_eq!(d.rect.get()[2], 100.0);
}

impl<'a> AddPolygon<'a, PolygonContext<'a>> for Context<'a> {
    #[inline(always)]
    fn polygon(&'a self, polygon: &'a [f64]) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            polygon: Value(polygon),
        }
    }
}

impl<'a> View<'a> for Context<'a> {
    #[inline(always)]
    fn view(&'a self) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> Context<'a> {
        Context {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
        }
    }
}

<commit_msg>Sorted use alphabetically<commit_after>
use {
    AddColor,
    AddEllipse,
    AddPolygon,
    AddRectangle,
    Borrowed,
    ColorContext,
    EllipseContext,
    Field,
    Matrix2d,
    PolygonContext,
    RectangleContext,
    Transform2d,
    Value,
    View,
};
use vecmath::{
    identity,
    multiply,
    rotate_radians,
    scale,
    shear,
    translate,
};

/// Drawing 2d context.
pub struct Context<'a> {
    /// Base/original transformation.
    pub base: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
}

impl<'a> Transform2d<'a> for Context<'a> {
    #[inline(always)]
    fn trans(&'a self, x: f64, y: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let trans = translate(x, y);
                 multiply(&trans, self.transform.get())
            }),
        }
    }

    #[inline(always)]
    fn trans_local(&'a self, x: f64, y: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let trans = translate(x, y);
                 multiply(self.transform.get(), &trans)
            }),
        }
    }

    #[inline(always)]
    fn rot_rad(&'a self, angle: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let rot = rotate_radians(angle);
                multiply(&rot, self.transform.get())
            }),
        }
    }

    #[inline(always)]
    fn rot_rad_local(&'a self, angle: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let rot = rotate_radians(angle);
                multiply(self.transform.get(), &rot)
            }),
        }
    }

    #[inline(always)]
    fn scale(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let scale = scale(sx, sy);
                multiply(&scale, self.transform.get())
            }),
        }
    }

    #[inline(always)]
    fn scale_local(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let scale = scale(sx, sy);
                multiply(self.transform.get(), &scale)
            }),
        }
    }

    #[inline(always)]
    fn shear(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let shear = shear(sx, sy);
                multiply(&shear, self.transform.get())
            }),
        }
    }

    #[inline(always)]
    fn shear_local(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let shear = shear(sx, sy);
                multiply(self.transform.get(), &shear)
            }),
        }
    }
}

impl<'a> Context<'a> {
    /// Creates a new drawing context.
    pub fn new() -> Context {
        Context {
            base:  Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            transform: Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
        }
    }
}

#[test]
fn test_context() {
    let c = Context::new();
    {
        let d = c.trans(20.0, 40.0);
        let d = d.trans(10.0, 10.0);
        assert_eq!(d.transform.get()[2], 30.0);
        assert_eq!(d.transform.get()[5], 50.0);
    }
    assert_eq!(c.transform.get()[2], 0.0);
    assert_eq!(c.transform.get()[5], 0.0);

    let c = c.rot_deg(90.0);
    assert!((c.transform.get()[0] - 0.0).abs() < 0.00001);
    assert!((c.transform.get()[1] - 1.0).abs() < 0.00001);
}

#[test]
fn test_scale() {
    let c = Context::new();
    let c = c.scale(2.0, 3.0);
    assert!((c.transform.get()[0] - 2.0).abs() < 0.00001);
    assert!((c.transform.get()[4] - 3.0).abs() < 0.00001);
}

impl<'a> AddRectangle<'a, RectangleContext<'a>> for Context<'a> {
    #[inline(always)]
    fn rect(&'a self, x: f64, y: f64, w: f64, h: f64) -> RectangleContext<'a> {
        RectangleContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value([x, y, w, h]),
        }
    }
}

#[test]
fn test_rect() {
    let c = Context::new();
    let d = c.rect(0.0, 0.0, 100.0, 50.0);
    assert_eq!(d.rect.get()[2], 100.0);
}

impl<'a> AddColor<'a, ColorContext<'a>> for Context<'a> {
    #[inline(always)]
    fn rgba(&'a self, r: f32, g: f32, b: f32, a: f32) -> ColorContext<'a> {
        ColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            color: Value([r, g, b, a]),
        }
    }
}

#[test]
fn test_rgba() {
    let c = Context::new();
    let d: ColorContext = c.rgba(1.0, 0.0, 0.0, 1.0);
    assert_eq!(d.color.get()[0], 1.0);
}

impl<'a> AddEllipse<'a, EllipseContext<'a>> for Context<'a> {
    #[inline(always)]
    fn ellipse(&'a self, x: f64, y: f64, w: f64, h: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value([x, y, w, h]),
        }
    }
}

#[test]
fn test_ellipse() {
    let c = Context::new();
    let d: EllipseContext = c.ellipse(0.0, 0.0, 100.0, 100.0);
    assert_eq!(d.rect.get()[2], 100.0);
}

impl<'a> AddPolygon<'a, PolygonContext<'a>> for Context<'a> {
    #[inline(always)]
    fn polygon(&'a self, polygon: &'a [f64]) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            polygon: Value(polygon),
        }
    }
}

impl<'a> View<'a> for Context<'a> {
    #[inline(always)]
    fn view(&'a self) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> Context<'a> {
        Context {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
        }
    }
}

<|endoftext|>


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

//! A work queue for scheduling units of work across threads in a fork-join fashion.
//!
//! Data associated with queues is simply a pair of unsigned integers. It is expected that a
//! higher-level API on top of this could allow safe fork-join parallelism.

#[cfg(windows)]
extern crate kernel32;

use deque::{self, Abort, Data, Empty, Stealer, Worker};
#[cfg(not(windows))]
use libc::usleep;
use rand::{Rng, XorShiftRng, weak_rng};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::{Receiver, Sender, channel};
use thread::spawn_named;
use thread_state;

/// A unit of work.
///
/// # Type parameters
///
/// - `QueueData`: global custom data for the entire work queue.
/// - `WorkData`: custom data specific to each unit of work.
pub struct WorkUnit<QueueData, WorkData: Send> {
    /// The function to execute.
    pub fun: extern "Rust" fn(WorkData, &mut WorkerProxy<QueueData, WorkData>),
    /// Arbitrary data.
    pub data: WorkData,
}

/// Messages from the supervisor to the worker.
enum WorkerMsg<QueueData: 'static, WorkData: 'static + Send> {
    /// Tells the worker to start work.
    Start(Worker<WorkUnit<QueueData, WorkData>>, *mut AtomicUsize, *const QueueData),
    /// Tells the worker to stop. It can be restarted again with a `WorkerMsg::Start`.
    Stop,
    /// Tells the worker to measure the heap size of its TLS using the supplied function.
    HeapSizeOfTLS(fn() -> usize),
    /// Tells the worker thread to terminate.
    Exit,
}

unsafe impl<QueueData: 'static, WorkData: 'static + Send> Send for WorkerMsg<QueueData, WorkData> {}

/// Messages to the supervisor.
enum SupervisorMsg<QueueData: 'static, WorkData: 'static + Send> {
    Finished,
    HeapSizeOfTLS(usize),
    ReturnDeque(usize, Worker<WorkUnit<QueueData, WorkData>>),
}

unsafe impl<QueueData: 'static, WorkData: 'static + Send> Send for SupervisorMsg<QueueData, WorkData> {}

/// Information that the supervisor thread keeps about the worker threads.
struct WorkerInfo<QueueData: 'static, WorkData: 'static + Send> {
    /// The communication channel to the workers.
    chan: Sender<WorkerMsg<QueueData, WorkData>>,
    /// The worker end of the deque, if we have it.
    deque: Option<Worker<WorkUnit<QueueData, WorkData>>>,
    /// The thief end of the work-stealing deque.
    thief: Stealer<WorkUnit<QueueData, WorkData>>,
}

/// Information specific to each worker thread that the thread keeps.
struct WorkerThread<QueueData: 'static, WorkData: 'static + Send> {
    /// The index of this worker.
    index: usize,
    /// The communication port from the supervisor.
    port: Receiver<WorkerMsg<QueueData, WorkData>>,
    /// The communication channel on which messages are sent to the supervisor.
    chan: Sender<SupervisorMsg<QueueData, WorkData>>,
    /// The thief end of the work-stealing deque for all other workers.
    other_deques: Vec<Stealer<WorkUnit<QueueData, WorkData>>>,
    /// The random number generator for this worker.
    rng: XorShiftRng,
}

unsafe impl<QueueData: 'static, WorkData: 'static + Send> Send for WorkerThread<QueueData, WorkData> {}

const SPINS_UNTIL_BACKOFF: u32 = 128;
const BACKOFF_INCREMENT_IN_US: u32 = 5;
const BACKOFFS_UNTIL_CONTROL_CHECK: u32 = 6;

fn next_power_of_two(mut v: u32) -> u32 {
    v -= 1;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    v += 1;
    v
}

#[cfg(not(windows))]
fn sleep_microseconds(usec: u32) {
    unsafe {
        usleep(usec);
    }
}

#[cfg(windows)]
fn sleep_microseconds(_: u32) {
    unsafe {
        kernel32::Sleep(0);
    }
}

impl<QueueData: Sync, WorkData: Send> WorkerThread<QueueData, WorkData> {
    /// The main logic. This function starts up the worker and listens for
    /// messages.
    fn start(&mut self) {
        let deque_index_mask = next_power_of_two(self.other_deques.len() as u32) - 1;
        loop {
            // Wait for a start message.
            let (mut deque, ref_count, queue_data) = match self.port.recv().unwrap() {
                WorkerMsg::Start(deque, ref_count, queue_data) => (deque, ref_count, queue_data),
                WorkerMsg::Stop => panic!("unexpected stop message"),
                WorkerMsg::Exit => return,
                WorkerMsg::HeapSizeOfTLS(f) => {
                    self.chan.send(SupervisorMsg::HeapSizeOfTLS(f())).unwrap();
                    continue;
                }
            };

            let mut back_off_sleep = 0 as u32;

            // We're off!
            'outer: loop {
                let work_unit;
                match deque.pop() {
                    Some(work) => work_unit = work,
                    None => {
                        // Become a thief.
                        let mut i = 0;
                        loop {
                            // Don't just use `rand % len` because that's slow on ARM.
                            let mut victim;
                            loop {
                                victim = self.rng.next_u32() & deque_index_mask;
                                if (victim as usize) < self.other_deques.len() {
                                    break
                                }
                            }

                            match self.other_deques[victim as usize].steal() {
                                Empty | Abort => {
                                    // Continue.
                                }
                                Data(work) => {
                                    work_unit = work;
                                    back_off_sleep = 0 as u32;
                                    break
                                }
                            }

                            if i > SPINS_UNTIL_BACKOFF {
                                if back_off_sleep >= BACKOFF_INCREMENT_IN_US *
                                        BACKOFFS_UNTIL_CONTROL_CHECK {
                                    match self.port.try_recv() {
                                        Ok(WorkerMsg::Stop) => break 'outer,
                                        Ok(WorkerMsg::Exit) => return,
                                        Ok(_) => panic!("unexpected message"),
                                        _ => {}
                                    }
                                }

                                sleep_microseconds(back_off_sleep);

                                back_off_sleep += BACKOFF_INCREMENT_IN_US;
                                i = 0
                            } else {
                                i += 1
                            }
                        }
                    }
                }

                // At this point, we have some work. Perform it.
                let mut proxy = WorkerProxy {
                    worker: &mut deque,
                    ref_count: ref_count,
                    // queue_data is kept alive in the stack frame of
                    // WorkQueue::run until we send the
                    // SupervisorMsg::ReturnDeque message below.
                    queue_data: unsafe { &*queue_data },
                    worker_index: self.index as u8,
                };
                (work_unit.fun)(work_unit.data, &mut proxy);

                // The work is done. Now decrement the count of outstanding work items. If this was
                // the last work unit in the queue, then send a message on the channel.
                unsafe {
                    if (*ref_count).fetch_sub(1, Ordering::Release) == 1 {
                        self.chan.send(SupervisorMsg::Finished).unwrap()
                    }
                }
            }

            // Give the deque back to the supervisor.
            self.chan.send(SupervisorMsg::ReturnDeque(self.index, deque)).unwrap()
        }
    }
}

/// A handle to the work queue that individual work units have.
pub struct WorkerProxy<'a, QueueData: 'a, WorkData: 'a + Send> {
    worker: &'a mut Worker<WorkUnit<QueueData, WorkData>>,
    ref_count: *mut AtomicUsize,
    queue_data: &'a QueueData,
    worker_index: u8,
}

impl<'a, QueueData: 'static, WorkData: Send + 'static> WorkerProxy<'a, QueueData, WorkData> {
    /// Enqueues a block into the work queue.
    #[inline]
    pub fn push(&mut self, work_unit: WorkUnit<QueueData, WorkData>) {
        unsafe {
            drop((*self.ref_count).fetch_add(1, Ordering::Relaxed));
        }
        self.worker.push(work_unit);
    }

    /// Retrieves the queue user data.
    #[inline]
    pub fn user_data(&self) -> &'a QueueData {
        self.queue_data
    }

    /// Retrieves the index of the worker.
    #[inline]
    pub fn worker_index(&self) -> u8 {
        self.worker_index
    }
}

/// A work queue on which units of work can be submitted.
pub struct WorkQueue<QueueData: 'static, WorkData: 'static + Send> {
    /// Information about each of the workers.
    workers: Vec<WorkerInfo<QueueData, WorkData>>,
    /// A port on which deques can be received from the workers.
    port: Receiver<SupervisorMsg<QueueData, WorkData>>,
    /// The amount of work that has been enqueued.
    work_count: usize,
}

impl<QueueData: Sync, WorkData: Send> WorkQueue<QueueData, WorkData> {
    /// Creates a new work queue and spawns all the threads associated with
    /// it.
    pub fn new(thread_name: &'static str,
               state: thread_state::ThreadState,
               thread_count: usize) -> WorkQueue<QueueData, WorkData> {
        // Set up data structures.
        let (supervisor_chan, supervisor_port) = channel();
        let (mut infos, mut threads) = (vec!(), vec!());
        for i in 0..thread_count {
            let (worker_chan, worker_port) = channel();
            let (worker, thief) = deque::new();
            infos.push(WorkerInfo {
                chan: worker_chan,
                deque: Some(worker),
                thief: thief,
            });
            threads.push(WorkerThread {
                index: i,
                port: worker_port,
                chan: supervisor_chan.clone(),
                other_deques: vec!(),
                rng: weak_rng(),
            });
        }

        // Connect workers to one another.
        for (i, mut thread) in threads.iter_mut().enumerate() {
            for (j, info) in infos.iter().enumerate() {
                if i != j {
                    thread.other_deques.push(info.thief.clone())
                }
            }
            assert!(thread.other_deques.len() == thread_count - 1)
        }

        // Spawn threads.
        for (i, thread) in threads.into_iter().enumerate() {

            spawn_named(
                format!("{} worker {}/{}", thread_name, i + 1, thread_count),
                move || {
                    thread_state::initialize(state | thread_state::IN_WORKER);
                    let mut thread = thread;
                    thread.start()
                })
        }

        WorkQueue {
            workers: infos,
            port: supervisor_port,
            work_count: 0,
        }
    }

    /// Enqueues a block into the work queue.
    #[inline]
    pub fn push(&mut self, work_unit: WorkUnit<QueueData, WorkData>) {
        let deque = &mut self.workers[0].deque;
        match *deque {
            None => {
                panic!("tried to push a block but we don't have the deque?!")
            }
            Some(ref mut deque) => deque.push(work_unit),
        }
        self.work_count += 1
    }

    /// Synchronously runs all the enqueued tasks and waits for them to complete.
    pub fn run(&mut self, data: &QueueData) {
        // Tell the workers to start.
        let mut work_count = AtomicUsize::new(self.work_count);
        for worker in &mut self.workers {
            worker.chan.send(WorkerMsg::Start(worker.deque.take().unwrap(),
                                              &mut work_count,
                                              data)).unwrap()
        }

        // Wait for the work to finish.
        drop(self.port.recv());
        self.work_count = 0;

        // Tell everyone to stop.
        for worker in &self.workers {
            worker.chan.send(WorkerMsg::Stop).unwrap()
        }

        // Get our deques back.
        for _ in 0..self.workers.len() {
            match self.port.recv().unwrap() {
                SupervisorMsg::ReturnDeque(index, deque) => self.workers[index].deque = Some(deque),
                SupervisorMsg::HeapSizeOfTLS(_) => panic!("unexpected HeapSizeOfTLS message"),
                SupervisorMsg::Finished => panic!("unexpected finished message!"),
            }
        }
    }

    /// Synchronously measure memory usage of any thread-local storage.
    pub fn heap_size_of_tls(&self, f: fn() -> usize) -> Vec<usize> {
        // Tell the workers to measure themselves.
        for worker in &self.workers {
            worker.chan.send(WorkerMsg::HeapSizeOfTLS(f)).unwrap()
        }

        // Wait for the workers to finish measuring themselves.
        let mut sizes = vec![];
        for _ in 0..self.workers.len() {
            match self.port.recv().unwrap() {
                SupervisorMsg::HeapSizeOfTLS(size) => {
                    sizes.push(size);
                }
                _ => panic!("unexpected message!"),
            }
        }
        sizes
    }

    pub fn shutdown(&mut self) {
        for worker in &self.workers {
            worker.chan.send(WorkerMsg::Exit).unwrap()
        }
    }
}
<commit_msg>Auto merge of #11132 - mbrubeck:workqueue-panic, r=larsbergstrom<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A work queue for scheduling units of work across threads in a fork-join fashion.
//!
//! Data associated with queues is simply a pair of unsigned integers. It is expected that a
//! higher-level API on top of this could allow safe fork-join parallelism.

#[cfg(windows)]
extern crate kernel32;

use deque::{self, Abort, Data, Empty, Stealer, Worker};
#[cfg(not(windows))]
use libc::usleep;
use rand::{Rng, XorShiftRng, weak_rng};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::{Receiver, Sender, channel};
use thread::spawn_named;
use thread_state;

/// A unit of work.
///
/// # Type parameters
///
/// - `QueueData`: global custom data for the entire work queue.
/// - `WorkData`: custom data specific to each unit of work.
pub struct WorkUnit<QueueData, WorkData: Send> {
    /// The function to execute.
    pub fun: extern "Rust" fn(WorkData, &mut WorkerProxy<QueueData, WorkData>),
    /// Arbitrary data.
    pub data: WorkData,
}

/// Messages from the supervisor to the worker.
enum WorkerMsg<QueueData: 'static, WorkData: 'static + Send> {
    /// Tells the worker to start work.
    Start(Worker<WorkUnit<QueueData, WorkData>>, *mut AtomicUsize, *const QueueData),
    /// Tells the worker to stop. It can be restarted again with a `WorkerMsg::Start`.
    Stop,
    /// Tells the worker to measure the heap size of its TLS using the supplied function.
    HeapSizeOfTLS(fn() -> usize),
    /// Tells the worker thread to terminate.
    Exit,
}

unsafe impl<QueueData: 'static, WorkData: 'static + Send> Send for WorkerMsg<QueueData, WorkData> {}

/// Messages to the supervisor.
enum SupervisorMsg<QueueData: 'static, WorkData: 'static + Send> {
    Finished,
    HeapSizeOfTLS(usize),
    ReturnDeque(usize, Worker<WorkUnit<QueueData, WorkData>>),
}

unsafe impl<QueueData: 'static, WorkData: 'static + Send> Send for SupervisorMsg<QueueData, WorkData> {}

/// Information that the supervisor thread keeps about the worker threads.
struct WorkerInfo<QueueData: 'static, WorkData: 'static + Send> {
    /// The communication channel to the workers.
    chan: Sender<WorkerMsg<QueueData, WorkData>>,
    /// The worker end of the deque, if we have it.
    deque: Option<Worker<WorkUnit<QueueData, WorkData>>>,
    /// The thief end of the work-stealing deque.
    thief: Stealer<WorkUnit<QueueData, WorkData>>,
}

/// Information specific to each worker thread that the thread keeps.
struct WorkerThread<QueueData: 'static, WorkData: 'static + Send> {
    /// The index of this worker.
    index: usize,
    /// The communication port from the supervisor.
    port: Receiver<WorkerMsg<QueueData, WorkData>>,
    /// The communication channel on which messages are sent to the supervisor.
    chan: Sender<SupervisorMsg<QueueData, WorkData>>,
    /// The thief end of the work-stealing deque for all other workers.
    other_deques: Vec<Stealer<WorkUnit<QueueData, WorkData>>>,
    /// The random number generator for this worker.
    rng: XorShiftRng,
}

unsafe impl<QueueData: 'static, WorkData: 'static + Send> Send for WorkerThread<QueueData, WorkData> {}

const SPINS_UNTIL_BACKOFF: u32 = 128;
const BACKOFF_INCREMENT_IN_US: u32 = 5;
const BACKOFFS_UNTIL_CONTROL_CHECK: u32 = 6;

#[cfg(not(windows))]
fn sleep_microseconds(usec: u32) {
    unsafe {
        usleep(usec);
    }
}

#[cfg(windows)]
fn sleep_microseconds(_: u32) {
    unsafe {
        kernel32::Sleep(0);
    }
}

impl<QueueData: Sync, WorkData: Send> WorkerThread<QueueData, WorkData> {
    /// The main logic. This function starts up the worker and listens for
    /// messages.
    fn start(&mut self) {
        let deque_index_mask = (self.other_deques.len() as u32).next_power_of_two() - 1;
        loop {
            // Wait for a start message.
            let (mut deque, ref_count, queue_data) = match self.port.recv().unwrap() {
                WorkerMsg::Start(deque, ref_count, queue_data) => (deque, ref_count, queue_data),
                WorkerMsg::Stop => panic!("unexpected stop message"),
                WorkerMsg::Exit => return,
                WorkerMsg::HeapSizeOfTLS(f) => {
                    self.chan.send(SupervisorMsg::HeapSizeOfTLS(f())).unwrap();
                    continue;
                }
            };

            let mut back_off_sleep = 0 as u32;

            // We're off!
            'outer: loop {
                let work_unit;
                match deque.pop() {
                    Some(work) => work_unit = work,
                    None => {
                        // Become a thief.
                        let mut i = 0;
                        loop {
                            // Don't just use `rand % len` because that's slow on ARM.
                            let mut victim;
                            loop {
                                victim = self.rng.next_u32() & deque_index_mask;
                                if (victim as usize) < self.other_deques.len() {
                                    break
                                }
                            }

                            match self.other_deques[victim as usize].steal() {
                                Empty | Abort => {
                                    // Continue.
                                }
                                Data(work) => {
                                    work_unit = work;
                                    back_off_sleep = 0 as u32;
                                    break
                                }
                            }

                            if i > SPINS_UNTIL_BACKOFF {
                                if back_off_sleep >= BACKOFF_INCREMENT_IN_US *
                                        BACKOFFS_UNTIL_CONTROL_CHECK {
                                    match self.port.try_recv() {
                                        Ok(WorkerMsg::Stop) => break 'outer,
                                        Ok(WorkerMsg::Exit) => return,
                                        Ok(_) => panic!("unexpected message"),
                                        _ => {}
                                    }
                                }

                                sleep_microseconds(back_off_sleep);

                                back_off_sleep += BACKOFF_INCREMENT_IN_US;
                                i = 0
                            } else {
                                i += 1
                            }
                        }
                    }
                }

                // At this point, we have some work. Perform it.
                let mut proxy = WorkerProxy {
                    worker: &mut deque,
                    ref_count: ref_count,
                    // queue_data is kept alive in the stack frame of
                    // WorkQueue::run until we send the
                    // SupervisorMsg::ReturnDeque message below.
                    queue_data: unsafe { &*queue_data },
                    worker_index: self.index as u8,
                };
                (work_unit.fun)(work_unit.data, &mut proxy);

                // The work is done. Now decrement the count of outstanding work items. If this was
                // the last work unit in the queue, then send a message on the channel.
                unsafe {
                    if (*ref_count).fetch_sub(1, Ordering::Release) == 1 {
                        self.chan.send(SupervisorMsg::Finished).unwrap()
                    }
                }
            }

            // Give the deque back to the supervisor.
            self.chan.send(SupervisorMsg::ReturnDeque(self.index, deque)).unwrap()
        }
    }
}

/// A handle to the work queue that individual work units have.
pub struct WorkerProxy<'a, QueueData: 'a, WorkData: 'a + Send> {
    worker: &'a mut Worker<WorkUnit<QueueData, WorkData>>,
    ref_count: *mut AtomicUsize,
    queue_data: &'a QueueData,
    worker_index: u8,
}

impl<'a, QueueData: 'static, WorkData: Send + 'static> WorkerProxy<'a, QueueData, WorkData> {
    /// Enqueues a block into the work queue.
    #[inline]
    pub fn push(&mut self, work_unit: WorkUnit<QueueData, WorkData>) {
        unsafe {
            drop((*self.ref_count).fetch_add(1, Ordering::Relaxed));
        }
        self.worker.push(work_unit);
    }

    /// Retrieves the queue user data.
    #[inline]
    pub fn user_data(&self) -> &'a QueueData {
        self.queue_data
    }

    /// Retrieves the index of the worker.
    #[inline]
    pub fn worker_index(&self) -> u8 {
        self.worker_index
    }
}

/// A work queue on which units of work can be submitted.
pub struct WorkQueue<QueueData: 'static, WorkData: 'static + Send> {
    /// Information about each of the workers.
    workers: Vec<WorkerInfo<QueueData, WorkData>>,
    /// A port on which deques can be received from the workers.
    port: Receiver<SupervisorMsg<QueueData, WorkData>>,
    /// The amount of work that has been enqueued.
    work_count: usize,
}

impl<QueueData: Sync, WorkData: Send> WorkQueue<QueueData, WorkData> {
    /// Creates a new work queue and spawns all the threads associated with
    /// it.
    pub fn new(thread_name: &'static str,
               state: thread_state::ThreadState,
               thread_count: usize) -> WorkQueue<QueueData, WorkData> {
        // Set up data structures.
        let (supervisor_chan, supervisor_port) = channel();
        let (mut infos, mut threads) = (vec!(), vec!());
        for i in 0..thread_count {
            let (worker_chan, worker_port) = channel();
            let (worker, thief) = deque::new();
            infos.push(WorkerInfo {
                chan: worker_chan,
                deque: Some(worker),
                thief: thief,
            });
            threads.push(WorkerThread {
                index: i,
                port: worker_port,
                chan: supervisor_chan.clone(),
                other_deques: vec!(),
                rng: weak_rng(),
            });
        }

        // Connect workers to one another.
        for (i, mut thread) in threads.iter_mut().enumerate() {
            for (j, info) in infos.iter().enumerate() {
                if i != j {
                    thread.other_deques.push(info.thief.clone())
                }
            }
            assert!(thread.other_deques.len() == thread_count - 1)
        }

        // Spawn threads.
        for (i, thread) in threads.into_iter().enumerate() {

            spawn_named(
                format!("{} worker {}/{}", thread_name, i + 1, thread_count),
                move || {
                    thread_state::initialize(state | thread_state::IN_WORKER);
                    let mut thread = thread;
                    thread.start()
                })
        }

        WorkQueue {
            workers: infos,
            port: supervisor_port,
            work_count: 0,
        }
    }

    /// Enqueues a block into the work queue.
    #[inline]
    pub fn push(&mut self, work_unit: WorkUnit<QueueData, WorkData>) {
        let deque = &mut self.workers[0].deque;
        match *deque {
            None => {
                panic!("tried to push a block but we don't have the deque?!")
            }
            Some(ref mut deque) => deque.push(work_unit),
        }
        self.work_count += 1
    }

    /// Synchronously runs all the enqueued tasks and waits for them to complete.
    pub fn run(&mut self, data: &QueueData) {
        // Tell the workers to start.
        let mut work_count = AtomicUsize::new(self.work_count);
        for worker in &mut self.workers {
            worker.chan.send(WorkerMsg::Start(worker.deque.take().unwrap(),
                                              &mut work_count,
                                              data)).unwrap()
        }

        // Wait for the work to finish.
        drop(self.port.recv());
        self.work_count = 0;

        // Tell everyone to stop.
        for worker in &self.workers {
            worker.chan.send(WorkerMsg::Stop).unwrap()
        }

        // Get our deques back.
        for _ in 0..self.workers.len() {
            match self.port.recv().unwrap() {
                SupervisorMsg::ReturnDeque(index, deque) => self.workers[index].deque = Some(deque),
                SupervisorMsg::HeapSizeOfTLS(_) => panic!("unexpected HeapSizeOfTLS message"),
                SupervisorMsg::Finished => panic!("unexpected finished message!"),
            }
        }
    }

    /// Synchronously measure memory usage of any thread-local storage.
    pub fn heap_size_of_tls(&self, f: fn() -> usize) -> Vec<usize> {
        // Tell the workers to measure themselves.
        for worker in &self.workers {
            worker.chan.send(WorkerMsg::HeapSizeOfTLS(f)).unwrap()
        }

        // Wait for the workers to finish measuring themselves.
        let mut sizes = vec![];
        for _ in 0..self.workers.len() {
            match self.port.recv().unwrap() {
                SupervisorMsg::HeapSizeOfTLS(size) => {
                    sizes.push(size);
                }
                _ => panic!("unexpected message!"),
            }
        }
        sizes
    }

    pub fn shutdown(&mut self) {
        for worker in &self.workers {
            worker.chan.send(WorkerMsg::Exit).unwrap()
        }
    }
}
<|endoftext|>


<commit_before>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

use gtk::ffi;

pub struct TreeStore {
    pointer: *mut ffi::C_GtkTreeStore
}

impl TreeStore {
    pub fn new(column_types: Vec<u64>) -> Option<TreeStore> {
        let tmp_pointer = unsafe { ffi::gtk_tree_store_newv(column_types.len().to_i32().unwrap(), column_types.as_slice()) };
        check_pointer!(tmp_pointer, TreeStore)
    }

    pub fn set_column_types(&self, column_types: Vec<u64>) {
        unsafe { ffi::gtk_tree_store_set_column_types(self.pointer, column_types.len().to_i32().unwrap(), column_types.as_slice()) }
    }

    // TODO: set_value

    // TODO: set

    // TODO: set_values

    // TODO: remove

    // TODO: insert

    // TODO: insert_before

    // TODO: insert_after

    // TODO: insert_with_values

    // TODO: prepend

    // TODO: append

    // TODO: is_ancestor

    // TODO: iter_depth

    // TODO: clear

    // TODO: is_valid

    // TODO: reorder

    // TODO: swap

    // TODO: move_before

    // TODO: move_after

    #[doc(hidden)]
    pub fn get_pointer(&self) -> *mut ffi::C_GtkTreeStore {
        self.pointer
    }

    #[doc(hidden)]
    pub fn wrap_pointer(c_treestore: *mut ffi::C_GtkTreeStore) -> TreeStore {
        TreeStore {
            pointer: c_treestore
        }
    }
}
<commit_msg>Fix comment<commit_after>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

use gtk::ffi;

pub struct TreeStore {
    pointer: *mut ffi::C_GtkTreeStore
}

impl TreeStore {
    pub fn new(column_types: Vec<u64>) -> Option<TreeStore> {
        let tmp_pointer = unsafe { ffi::gtk_tree_store_newv(column_types.len().to_i32().unwrap(), column_types.as_slice()) };
        check_pointer!(tmp_pointer, TreeStore)
    }

    pub fn set_column_types(&self, column_types: Vec<u64>) {
        unsafe { ffi::gtk_tree_store_set_column_types(self.pointer, column_types.len().to_i32().unwrap(), column_types.as_slice()) }
    }

    // TODO: set_value

    // TODO: set

    // TODO: set_values

    // TODO: remove

    // TODO: insert

    // TODO: insert_before

    // TODO: insert_after

    // TODO: insert_with_values

    // TODO: prepend

    // TODO: append

    // TODO: is_ancestor

    // TODO: iter_depth

    // TODO: clear

    // TODO: iter_is_valid

    // TODO: reorder

    // TODO: swap

    // TODO: move_before

    // TODO: move_after

    #[doc(hidden)]
    pub fn get_pointer(&self) -> *mut ffi::C_GtkTreeStore {
        self.pointer
    }

    #[doc(hidden)]
    pub fn wrap_pointer(c_treestore: *mut ffi::C_GtkTreeStore) -> TreeStore {
        TreeStore {
            pointer: c_treestore
        }
    }
}
<|endoftext|>


<commit_before>use av_format::error::*;
use std::io::SeekFrom;
//use av_data::packet::Packet;
use av_format::stream::*;
use av_format::buffer::Buffered;
use av_format::demuxer::demux::{Demuxer, Event};
use av_format::demuxer::context::GlobalInfo;
use std::collections::VecDeque;
use rational::Rational32;

use ebml::{ebml_header, EBMLHeader};
use elements::{segment, segment_element, Cluster, SeekHead, Info, Tracks, TrackEntry,
               SegmentElement};
use nom::{self, IResult, Offset};

#[derive(Debug, Clone, PartialEq)]
pub struct MkvDemuxer {
    pub header: Option<EBMLHeader>,
    pub seek_head: Option<SeekHead>,
    pub info: Option<Info>,
    pub tracks: Option<Tracks>,
    //pub clusters: Vec<Cluster>,
    pub queue: VecDeque<Event>,
}

impl MkvDemuxer {
    pub fn new() -> MkvDemuxer {
        MkvDemuxer {
            header: None,
            seek_head: None,
            info: None,
            tracks: None,
            //clusters: Vec::new(),
            queue: VecDeque::new(),
        }
    }

    pub fn parse_until_tracks<'a>(&mut self, original_input: &'a [u8]) -> IResult<&'a [u8], ()> {
        let (i1, header) = try_parse!(original_input, ebml_header);

        self.header = Some(header);

        let (mut input, _) = try_parse!(i1, segment);

        loop {
            if self.seek_head.is_some() && self.info.is_some() && self.tracks.is_some() {
                return IResult::Done(input, ());
            }

            println!("offset: {}", original_input.offset(input));

            let (i3, element) = try_parse!(input, segment_element);

            match element {
                SegmentElement::SeekHead(s) => {
                    println!("got seek head: {:#?}", s);
                    if self.seek_head.is_some() {
                        return IResult::Error(nom::ErrorKind::Custom(1));
                    } else {
                        self.seek_head = Some(s);
                    }
                }
                SegmentElement::Info(i) => {
                    println!("got info: {:#?}", i);
                    if self.info.is_some() {
                        return IResult::Error(nom::ErrorKind::Custom(1));
                    } else {
                        self.info = Some(i);
                    }
                }
                SegmentElement::Tracks(t) => {
                    println!("got tracks: {:#?}", t);
                    if self.tracks.is_some() {
                        return IResult::Error(nom::ErrorKind::Custom(1));
                    } else {
                        self.tracks = Some(t);
                    }
                }
                SegmentElement::Cluster(c) => {
                    println!("got a cluster: {:#?}", c);
                    //self.clusters.push(c);
                }
                el => {
                    println!("got element: {:#?}", el);
                }
            }

            input = i3;
        }
    }
}

impl Demuxer for MkvDemuxer {
    fn open(&mut self) {}

    fn read_headers(&mut self, buf: &Box<Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom> {
        match self.parse_until_tracks(buf.data()) {
            IResult::Done(i, _) => {
                info.duration = self.info.as_ref().and_then(|info| info.duration).map(|d| {
                    d as u64
                });
                if let Some(ref t) = self.tracks {
                    info.streams = t.tracks.iter().map(|tr| track_to_stream(tr)).collect();
                }
                Ok(SeekFrom::Current(buf.data().offset(i) as i64))
            }
            IResult::Incomplete(_) => Err(ErrorKind::MoreDataNeeded.into()),
            e => {
              println!("error reading headers: {:?}", e);
              Err(ErrorKind::InvalidData.into())
            },
        }
    }

    fn read_packet(&mut self, buf: &Box<Buffered>) -> Result<(SeekFrom, Event)> {
        match segment_element(buf.data()) {
            IResult::Done(i, element) => {
                let seek = SeekFrom::Current(buf.data().offset(i) as i64);
                match element {
                    SegmentElement::Cluster(c) => {
                        //self.clusters.push(c);
                    }
                    el => {
                        println!("got element: {:#?}", el);
                    }
                }

                Ok((seek, Event::MoreDataNeeded))
            }
            IResult::Incomplete(_) => Ok((SeekFrom::Current(0), Event::MoreDataNeeded)),
            e => {
                println!("parsing issue: {:?}", e);
                Err(ErrorKind::InvalidData.into())
            }
        }
    }
}

fn track_entry_codec_id(t: &TrackEntry) -> Option<CodecID> {
    // TODO: Support V_QUICKTIME and V_MS/VFW/FOURCC
    match t.codec_id.as_ref() {
        "A_OPUS" => Some(CodecID::Opus),
        "V_VP9"  => Some(CodecID::VP9),
        _ => None
    }
}

fn track_entry_video_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref video) = t.video {
        let v = VideoInfo {
            width : video.pixel_width as usize,
            height : video.pixel_height as usize,
            // TODO parse Colour and/or CodecPrivate to extract the format
            format : None
        };
        Some(MediaKind::Video(v))
    } else {
        None
    }
}

fn track_entry_audio_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref audio) = t.audio {
        let rate = if let Some(r) = audio.output_sampling_frequency {
            r
        } else {
            audio.sampling_frequency
        };
        // TODO: complete it
        let a = AudioInfo {
            samples: 0,
            rate: rate as usize,
            map: None,
            format: None,
        };
        Some(MediaKind::Audio(a))
    } else {
        None
    }
}

fn track_entry_media_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Use an enum for the track type
    match t.track_type {
        0x1 => track_entry_video_kind(t),
        0x2 => track_entry_audio_kind(t),
        _ => None
    }
}

pub fn track_to_stream(t: &TrackEntry) -> Stream {
    Stream {
    id: t.track_uid as usize,
    index: t.track_number as usize,
    start: None,
    duration: t.default_duration,
    timebase : Rational32::from_integer(1),
    // TODO: Extend CodecParams and fill it with the remaining information
    params : CodecParams {
        extradata: t.codec_private.clone(),
        bit_rate: 0,
        codec_id: track_entry_codec_id(t),
        kind: track_entry_media_kind(t)
    },
  }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::Cursor;
    use nom::{IResult, Offset};
    use av_format::demuxer::context::DemuxerContext;

    const webm: &'static [u8] = include_bytes!("../assets/bbb-vp9-opus.webm");

    #[test]
    fn parse_headers() {
        let mut demuxer = MkvDemuxer::new();

        let res = demuxer.parse_until_tracks(webm);
        println!("got parsing res: {:?}", res);
        match res {
            IResult::Done(i, _) => {
                println!("offset: {} bytes", webm.offset(i));
            }
            e => {
                println!("could not parse: {:?}", e);
            }
        }

        println!("demuxer: {:#?}", demuxer);
        panic!();
    }

    #[test]
    fn context() {
        let mut context = DemuxerContext::new(Box::new(MkvDemuxer::new()),
                                              Box::new(Cursor::new(webm)));
        println!("DEMUXER CONTEXT read headers: {:?}", context.read_headers());
        println!("DEMUXER CONTEXT streams: {:?}", context.info.streams);
        println!("DEMUXER CONTEXT event: {:?}", context.read_packet());
        println!("DEMUXER CONTEXT event: {:?}", context.read_packet());
        println!("DEMUXER CONTEXT event: {:?}", context.read_packet());
        println!("DEMUXER CONTEXT event: {:?}", context.read_packet());
        panic!();
    }
}
<commit_msg>crude way to merge blocks for now<commit_after>use av_format::error::*;
use std::io::SeekFrom;
//use av_data::packet::Packet;
use av_format::stream::*;
use av_format::buffer::Buffered;
use av_format::demuxer::demux::{Demuxer, Event};
use av_format::demuxer::context::GlobalInfo;
use std::collections::VecDeque;
use rational::Rational32;

use ebml::{ebml_header, EBMLHeader};
use elements::{segment, segment_element, Cluster, SeekHead, Info, Tracks, TrackEntry,
               SegmentElement};
use nom::{self, IResult, Offset};

#[derive(Debug, Clone, PartialEq)]
pub struct MkvDemuxer {
    pub header: Option<EBMLHeader>,
    pub seek_head: Option<SeekHead>,
    pub info: Option<Info>,
    pub tracks: Option<Tracks>,
    //pub clusters: Vec<Cluster>,
    pub queue: VecDeque<Event>,
    pub blockstream: Vec<u8>,
}

impl MkvDemuxer {
    pub fn new() -> MkvDemuxer {
        MkvDemuxer {
            header: None,
            seek_head: None,
            info: None,
            tracks: None,
            //clusters: Vec::new(),
            queue: VecDeque::new(),
            blockstream: Vec::new(),
        }
    }

    pub fn parse_until_tracks<'a>(&mut self, original_input: &'a [u8]) -> IResult<&'a [u8], ()> {
        let (i1, header) = try_parse!(original_input, ebml_header);

        self.header = Some(header);

        let (mut input, _) = try_parse!(i1, segment);

        loop {
            if self.seek_head.is_some() && self.info.is_some() && self.tracks.is_some() {
                return IResult::Done(input, ());
            }

            println!("offset: {}", original_input.offset(input));

            let (i3, element) = try_parse!(input, segment_element);

            match element {
                SegmentElement::SeekHead(s) => {
                    println!("got seek head: {:#?}", s);
                    if self.seek_head.is_some() {
                        return IResult::Error(nom::ErrorKind::Custom(1));
                    } else {
                        self.seek_head = Some(s);
                    }
                }
                SegmentElement::Info(i) => {
                    println!("got info: {:#?}", i);
                    if self.info.is_some() {
                        return IResult::Error(nom::ErrorKind::Custom(1));
                    } else {
                        self.info = Some(i);
                    }
                }
                SegmentElement::Tracks(t) => {
                    println!("got tracks: {:#?}", t);
                    if self.tracks.is_some() {
                        return IResult::Error(nom::ErrorKind::Custom(1));
                    } else {
                        self.tracks = Some(t);
                    }
                }
                SegmentElement::Cluster(c) => {
                    println!("got a cluster: {:#?}", c);
                    //self.clusters.push(c);
                }
                el => {
                    println!("got element: {:#?}", el);
                }
            }

            input = i3;
        }
    }
}

impl Demuxer for MkvDemuxer {
    fn open(&mut self) {}

    fn read_headers(&mut self, buf: &Box<Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom> {
        match self.parse_until_tracks(buf.data()) {
            IResult::Done(i, _) => {
                info.duration = self.info.as_ref().and_then(|info| info.duration).map(|d| {
                    d as u64
                });
                if let Some(ref t) = self.tracks {
                    info.streams = t.tracks.iter().map(|tr| track_to_stream(tr)).collect();
                }
                Ok(SeekFrom::Current(buf.data().offset(i) as i64))
            }
            IResult::Incomplete(_) => Err(ErrorKind::MoreDataNeeded.into()),
            e => {
              println!("error reading headers: {:?}", e);
              Err(ErrorKind::InvalidData.into())
            },
        }
    }

    fn read_packet(&mut self, buf: &Box<Buffered>) -> Result<(SeekFrom, Event)> {
        match segment_element(buf.data()) {
            IResult::Done(i, element) => {
                let seek = SeekFrom::Current(buf.data().offset(i) as i64);
                match element {
                    SegmentElement::Cluster(c) => {
                        //self.clusters.push(c);
                        println!("got cluster element at timecode: {}", c.timecode);
                        for block in c.simple_block.iter() {
                          println!("got simple block of size {}", block.len());
                          self.blockstream.extend(*block);
                        }

                        for block_group in c.block_group.iter() {
                          println!("got block group of size {}", block_group.block.len());
                          self.blockstream.extend(block_group.block);
                        }
                    }
                    el => {
                        println!("got element: {:#?}", el);
                    }
                }

                Ok((seek, Event::MoreDataNeeded))
            }
            IResult::Incomplete(_) => Ok((SeekFrom::Current(0), Event::MoreDataNeeded)),
            e => {
                println!("parsing issue: {:?}", e);
                Err(ErrorKind::InvalidData.into())
            }
        }
    }
}

fn track_entry_codec_id(t: &TrackEntry) -> Option<CodecID> {
    // TODO: Support V_QUICKTIME and V_MS/VFW/FOURCC
    match t.codec_id.as_ref() {
        "A_OPUS" => Some(CodecID::Opus),
        "V_VP9"  => Some(CodecID::VP9),
        _ => None
    }
}

fn track_entry_video_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref video) = t.video {
        let v = VideoInfo {
            width : video.pixel_width as usize,
            height : video.pixel_height as usize,
            // TODO parse Colour and/or CodecPrivate to extract the format
            format : None
        };
        Some(MediaKind::Video(v))
    } else {
        None
    }
}

fn track_entry_audio_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Validate that a track::video exists for track::type video before.
    if let Some(ref audio) = t.audio {
        let rate = if let Some(r) = audio.output_sampling_frequency {
            r
        } else {
            audio.sampling_frequency
        };
        // TODO: complete it
        let a = AudioInfo {
            samples: 0,
            rate: rate as usize,
            map: None,
            format: None,
        };
        Some(MediaKind::Audio(a))
    } else {
        None
    }
}

fn track_entry_media_kind(t: &TrackEntry) -> Option<MediaKind> {
    // TODO: Use an enum for the track type
    match t.track_type {
        0x1 => track_entry_video_kind(t),
        0x2 => track_entry_audio_kind(t),
        _ => None
    }
}

pub fn track_to_stream(t: &TrackEntry) -> Stream {
    Stream {
    id: t.track_uid as usize,
    index: t.track_number as usize,
    start: None,
    duration: t.default_duration,
    timebase : Rational32::from_integer(1),
    // TODO: Extend CodecParams and fill it with the remaining information
    params : CodecParams {
        extradata: t.codec_private.clone(),
        bit_rate: 0,
        codec_id: track_entry_codec_id(t),
        kind: track_entry_media_kind(t)
    },
  }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::Cursor;
    use nom::{IResult, Offset};
    use av_format::demuxer::context::DemuxerContext;

    const webm: &'static [u8] = include_bytes!("../assets/bbb-vp9-opus.webm");

    #[test]
    fn parse_headers() {
        let mut demuxer = MkvDemuxer::new();

        let res = demuxer.parse_until_tracks(webm);
        println!("got parsing res: {:?}", res);
        match res {
            IResult::Done(i, _) => {
                println!("offset: {} bytes", webm.offset(i));
            }
            e => {
                println!("could not parse: {:?}", e);
            }
        }

        println!("demuxer: {:#?}", demuxer);
        panic!();
    }

    #[test]
    fn context() {
        let mut context = DemuxerContext::new(Box::new(MkvDemuxer::new()),
                                              Box::new(Cursor::new(webm)));
        println!("DEMUXER CONTEXT read headers: {:?}", context.read_headers());
        println!("DEMUXER CONTEXT streams: {:?}", context.info.streams);
        println!("DEMUXER CONTEXT event: {:?}", context.read_packet());
        println!("DEMUXER CONTEXT event: {:?}", context.read_packet());
        println!("DEMUXER CONTEXT event: {:?}", context.read_packet());
        println!("DEMUXER CONTEXT event: {:?}", context.read_packet());
        panic!();
    }
}
<|endoftext|>


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

use env as henv;

/// Default Depot URL
pub const DEFAULT_DEPOT_URL: &'static str = "https://willem.habitat.sh/v1/depot";

/// Default Depot URL environment variable
pub const DEPOT_URL_ENVVAR: &'static str = "HAB_DEPOT_URL";

pub fn default_depot_url() -> String {
    match henv::var(DEPOT_URL_ENVVAR) {
        Ok(val) => val,
        Err(_) => DEFAULT_DEPOT_URL.to_string(),
    }
}
<commit_msg>Add channel support to builder-worker<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use env as henv;

/// Default Depot URL
pub const DEFAULT_DEPOT_URL: &'static str = "https://willem.habitat.sh/v1/depot";

/// Default Depot channel
pub const DEFAULT_DEPOT_CHANNEL: &'static str = "unstable";

/// Default Depot URL environment variable
pub const DEPOT_URL_ENVVAR: &'static str = "HAB_DEPOT_URL";

/// Default Depot Channel environment variable
pub const DEPOT_CHANNEL_ENVVAR: &'static str = "HAB_DEPOT_CHANNEL";

pub fn default_depot_url() -> String {
    match henv::var(DEPOT_URL_ENVVAR) {
        Ok(val) => val,
        Err(_) => DEFAULT_DEPOT_URL.to_string(),
    }
}

pub fn default_depot_channel() -> String {
    match henv::var(DEPOT_CHANNEL_ENVVAR) {
        Ok(val) => val,
        Err(_) => DEFAULT_DEPOT_CHANNEL.to_string(),
    }
}
<|endoftext|>


<commit_before>extern crate cfg_if;

use cfg_if::cfg_if;

cfg_if! {
    if #[cfg(all(windows, feature = "neon-sys"))] {
        use std::env::var;
        use std::path::Path;

        const NODE_ROOT_DIR: &'static str = include_str!(concat!(env!("OUT_DIR"), "\\node_root_dir"));
        const NODE_ARCH:     &'static str = include_str!(concat!(env!("OUT_DIR"), "\\node_arch"));
        const NODE_LIB_FILE: &'static str = include_str!(concat!(env!("OUT_DIR"), "\\node_lib_file"));

        /// Set up the build environment by setting Cargo configuration variables.
        pub fn setup() {
            let debug = var("DEBUG").ok().map_or(false, |s| s == "true");
            let configuration = if debug { "Debug" } else { "Release" };
            let node_lib_file_path = Path::new(NODE_LIB_FILE);
            let mut node_lib_path = Path::new(NODE_ROOT_DIR).to_path_buf();
            node_lib_path.push(NODE_ARCH);
            println!("cargo:rustc-link-search={}\\{}", NODE_ROOT_DIR, configuration);
            println!("cargo:rustc-link-search=native={}", &node_lib_path.display());
            println!("cargo:rustc-link-lib={}", &node_lib_file_path.file_stem().unwrap().to_str().unwrap());

            if debug
            {
                println!("cargo:rustc-link-lib=msvcrtd");
            }

            // Link `win_delay_load_hook.obj` for windows electron
            let node_runtime_env = "npm_config_runtime";
            println!("cargo:rerun-if-env-changed={}", node_runtime_env);
            if var(node_runtime_env).map(|s| s == "electron") == Ok(true) {
                println!("cargo:rustc-cdylib-link-arg=win_delay_load_hook.obj");
                println!("cargo:rustc-cdylib-link-arg=delayimp.lib");
                println!("cargo:rustc-cdylib-link-arg=/DELAYLOAD:node.exe");
            }
        }
    } else if #[cfg(target_os = "macos")] {
        /// Set up the build environment by setting Cargo configuration variables.
        pub fn setup() {
            println!("cargo:rustc-cdylib-link-arg=-undefined");
            println!("cargo:rustc-cdylib-link-arg=dynamic_lookup");
        }
    } else {
        pub fn setup() { }
    }
}
<commit_msg>fixup ; safety for the other `target_env`s<commit_after>extern crate cfg_if;

use cfg_if::cfg_if;

cfg_if! {
    if #[cfg(all(windows, feature = "neon-sys"))] {
        use std::env::var;
        use std::path::Path;

        const NODE_ROOT_DIR: &'static str = include_str!(concat!(env!("OUT_DIR"), "\\node_root_dir"));
        const NODE_ARCH:     &'static str = include_str!(concat!(env!("OUT_DIR"), "\\node_arch"));
        const NODE_LIB_FILE: &'static str = include_str!(concat!(env!("OUT_DIR"), "\\node_lib_file"));

        /// Set up the build environment by setting Cargo configuration variables.
        pub fn setup() {
            let debug = var("DEBUG").ok().map_or(false, |s| s == "true");
            let configuration = if debug { "Debug" } else { "Release" };
            let node_lib_file_path = Path::new(NODE_LIB_FILE);
            let mut node_lib_path = Path::new(NODE_ROOT_DIR).to_path_buf();
            node_lib_path.push(NODE_ARCH);
            println!("cargo:rustc-link-search={}\\{}", NODE_ROOT_DIR, configuration);
            println!("cargo:rustc-link-search=native={}", &node_lib_path.display());
            println!("cargo:rustc-link-lib={}", &node_lib_file_path.file_stem().unwrap().to_str().unwrap());

            if cfg!(target_env = "msvc") && debug
            {
                println!("cargo:rustc-link-lib=msvcrtd");
            }

            // Link `win_delay_load_hook.obj` for windows electron
            let node_runtime_env = "npm_config_runtime";
            println!("cargo:rerun-if-env-changed={}", node_runtime_env);
            if var(node_runtime_env).map(|s| s == "electron") == Ok(true) {
                println!("cargo:rustc-cdylib-link-arg=win_delay_load_hook.obj");
                println!("cargo:rustc-cdylib-link-arg=delayimp.lib");
                println!("cargo:rustc-cdylib-link-arg=/DELAYLOAD:node.exe");
            }
        }
    } else if #[cfg(target_os = "macos")] {
        /// Set up the build environment by setting Cargo configuration variables.
        pub fn setup() {
            println!("cargo:rustc-cdylib-link-arg=-undefined");
            println!("cargo:rustc-cdylib-link-arg=dynamic_lookup");
        }
    } else {
        pub fn setup() { }
    }
}
<|endoftext|>