<commit_before>extern crate libc;

use std::rc::Rc;
use std::rc::Weak;
use std::cell::RefCell;
use std::ptr;

use drawing_ctx::RsvgDrawingCtx;

use handle::RsvgHandle;

use property_bag::RsvgPropertyBag;

use state::RsvgState;

/* A *const RsvgNode is just a pointer for the C code's benefit: it
 * points to an  Rc<Node>, which is our refcounted Rust representation
 * of nodes.
 */
pub type RsvgNode = Rc<Node>;

/* A *const RsvgCNodeImpl is just an opaque pointer to the C code's
 * struct for a particular node type.
 */
pub enum RsvgCNodeImpl {}

pub trait NodeTrait {
    fn set_atts (&self, node: &RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag);
    fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32);
    fn get_c_impl (&self) -> *const RsvgCNodeImpl;
}

pub struct Node {
    node_type: NodeType,
    parent:    Option<Weak<Node>>,       // optional; weak ref to parent
    children:  RefCell<Vec<Rc<Node>>>,   // strong references to children
    state:     *mut RsvgState,
    node_impl: Box<NodeTrait>
}

/* Keep this in sync with rsvg-private.h:RsvgNodeType */
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum NodeType {
    Invalid = 0,

    Chars,
    Circle,
    ClipPath,
    ComponentTransferFunction,
    Defs,
    Ellipse,
    Filter,
    Group,
    Image,
    LightSource,
    Line,
    LinearGradient,
    Marker,
    Mask,
    Path,
    Pattern,
    Polygon,
    Polyline,
    RadialGradient,
    Rect,
    Stop,
    Svg,
    Switch,
    Symbol,
    Text,
    TRef,
    TSpan,
    Use,

    /* Filter primitives */
    FilterPrimitiveFirst,              /* just a marker; not a valid type */
    FilterPrimitiveBlend,
    FilterPrimitiveColorMatrix,
    FilterPrimitiveComponentTransfer,
    FilterPrimitiveComposite,
    FilterPrimitiveConvolveMatrix,
    FilterPrimitiveDiffuseLighting,
    FilterPrimitiveDisplacementMap,
    FilterPrimitiveErode,
    FilterPrimitiveFlood,
    FilterPrimitiveGaussianBlur,
    FilterPrimitiveImage,
    FilterPrimitiveMerge,
    FilterPrimitiveMergeNode,
    FilterPrimitiveOffset,
    FilterPrimitiveSpecularLighting,
    FilterPrimitiveTile,
    FilterPrimitiveTurbulence,
    FilterPrimitiveLast                /* just a marker; not a valid type */
}

impl Node {
    pub fn new (node_type: NodeType,
                parent:    Option<Weak<Node>>,
                state:     *mut RsvgState,
                node_impl: Box<NodeTrait>) -> Node {
        Node {
            node_type: node_type,
            parent:    parent,
            children:  RefCell::new (Vec::new ()),
            state:     state,
            node_impl: node_impl
        }
    }

    pub fn get_type (&self) -> NodeType {
        self.node_type
    }

    pub fn get_state (&self) -> *mut RsvgState {
        self.state
    }

    pub fn add_child (&self, child: &Rc<Node>) {
        self.children.borrow_mut ().push (child.clone ());
    }

    pub fn set_atts (&self, node: &RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag) {
        self.node_impl.set_atts (node, handle, pbag);
    }

    pub fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
        self.node_impl.draw (node, draw_ctx, dominate);
    }

    pub fn get_c_impl (&self) -> *const RsvgCNodeImpl {
        self.node_impl.get_c_impl ()
    }
}

extern "C" {
    fn rsvg_state_free (state: *mut RsvgState);
}

impl Drop for Node {
    fn drop (&mut self) {
//        unsafe { rsvg_state_free (self.state); }
    }
}

#[no_mangle]
pub extern fn rsvg_node_get_type (raw_node: *const RsvgNode) -> NodeType {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    node.get_type ()
}

pub fn box_node (node: RsvgNode) -> *mut RsvgNode {
    Box::into_raw (Box::new (node))
}

#[no_mangle]
pub extern fn rsvg_node_get_parent (raw_node: *const RsvgNode) -> *const RsvgNode {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    match node.parent {
        None => { ptr::null () }

        Some (ref weak_node) => {
            let strong_node = weak_node.upgrade ().unwrap ();
            box_node (strong_node)
        }
    }
}

#[no_mangle]
pub extern fn rsvg_node_ref (raw_node: *mut RsvgNode) -> *mut RsvgNode {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    box_node (node.clone ())
}

#[no_mangle]
pub extern fn rsvg_node_unref (raw_node: *mut RsvgNode) -> *mut RsvgNode {
    if !raw_node.is_null () {
        let _ = unsafe { Box::from_raw (raw_node) };
    }

    ptr::null_mut () // so the caller can do "node = rsvg_node_unref (node);" and lose access to the node
}

// See https://github.com/rust-lang/rust/issues/36497 - this is what
// added Rc::ptr_eq(), but we don't want to depend on unstable Rust
// just yet.

fn rc_node_ptr_eq<T: ?Sized> (this: &Rc<T>, other: &Rc<T>) -> bool {
    let this_ptr: *const T = &**this;
    let other_ptr: *const T = &**other;
    this_ptr == other_ptr
}

#[no_mangle]
pub extern fn rsvg_node_is_same (raw_node1: *const RsvgNode, raw_node2: *const RsvgNode) -> bool {
    if raw_node1.is_null () && raw_node2.is_null () {
        true
    } else if !raw_node1.is_null () && !raw_node2.is_null () {
        let node1: &RsvgNode = unsafe { & *raw_node1 };
        let node2: &RsvgNode = unsafe { & *raw_node2 };

        rc_node_ptr_eq (node1, node2)
    } else {
        false
    }
}

#[no_mangle]
pub extern fn rsvg_node_get_state (raw_node: *const RsvgNode) -> *mut RsvgState {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    node.get_state ()
}

#[no_mangle]
pub extern fn rsvg_node_add_child (raw_node: *mut RsvgNode, raw_child: *const RsvgNode) {
    assert! (!raw_node.is_null ());
    assert! (!raw_child.is_null ());
    let node: &mut RsvgNode = unsafe { &mut *raw_node };
    let child: &RsvgNode = unsafe { & *raw_child };

    node.add_child (child);
}

#[no_mangle]
pub extern fn rsvg_node_set_atts (raw_node: *mut RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag) {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    node.set_atts (node, handle, pbag);
}

#[no_mangle]
pub extern fn rsvg_node_draw (raw_node: *const RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    node.draw (node, draw_ctx, dominate);
}

type NodeForeachChild = unsafe extern "C" fn (node: *const RsvgNode, data: *const libc::c_void) -> bool;

#[no_mangle]
pub extern fn rsvg_node_foreach_child (raw_node: *const RsvgNode, func: NodeForeachChild, data: *const libc::c_void)
{
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    for child in &*node.children.borrow () {
        let boxed_child = box_node (child.clone ());

        let next = unsafe { func (boxed_child, data) };

        unsafe { rsvg_node_unref (boxed_child); }

        if !next {
            break;
        }
    }
}

#[cfg(test)]
mod tests {
    use std::rc::Rc;
    use drawing_ctx::RsvgDrawingCtx;
    use handle::RsvgHandle;
    use property_bag::RsvgPropertyBag;
    use state::RsvgState;
    use super::*;
    use std::ptr;
    use std::mem;

    struct TestNodeImpl {}

    impl NodeTrait for TestNodeImpl {
        fn set_atts (&self, node: &RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag) {
        }

        fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
        }

        fn get_c_impl (&self) -> *const RsvgCNodeImpl {
            return ptr::null ();
        }
    }

    #[test]
    fn node_refs_and_unrefs () {
        let node = Rc::new (Node::new (NodeType::Path,
                                       None,
                                       ptr::null_mut (),
                                       Box::new (TestNodeImpl {})));

        let mut ref1 = box_node (node);

        let new_node: &mut RsvgNode = unsafe { &mut *ref1 };
        let weak = Rc::downgrade (new_node);

        let mut ref2 = unsafe { rsvg_node_ref (new_node) };
        assert! (weak.upgrade ().is_some ());

        ref2 = unsafe { rsvg_node_unref (ref2) };
        assert! (weak.upgrade ().is_some ());

        ref1 = unsafe { rsvg_node_unref (ref1) };
        assert! (weak.upgrade ().is_none ());
    }

    #[test]
    fn reffed_node_is_same_as_original_node () {
        let node = Rc::new (Node::new (NodeType::Path,
                                       None,
                                       ptr::null_mut (),
                                       Box::new (TestNodeImpl {})));

        let mut ref1 = box_node (node);

        let mut ref2 = unsafe { rsvg_node_ref (ref1) };

        unsafe { assert! (rsvg_node_is_same (ref1, ref2)); }

        ref1 = rsvg_node_unref (ref1);
        ref2 = rsvg_node_unref (ref2);
    }

    #[test]
    fn different_nodes_have_different_pointers () {
        let node1 = Rc::new (Node::new (NodeType::Path,
                                       None,
                                       ptr::null_mut (),
                                       Box::new (TestNodeImpl {})));

        let mut ref1 = box_node (node1);

        let node2 = Rc::new (Node::new (NodeType::Path,
                                       None,
                                       ptr::null_mut (),
                                       Box::new (TestNodeImpl {})));

        let mut ref2 = box_node (node2);

        unsafe { assert! (!rsvg_node_is_same (ref1, ref2)); }

        ref1 = rsvg_node_unref (ref1);
        ref2 = rsvg_node_unref (ref2);
    }
}
<commit_msg>Remove an unused unsafe block<commit_after>extern crate libc;

use std::rc::Rc;
use std::rc::Weak;
use std::cell::RefCell;
use std::ptr;

use drawing_ctx::RsvgDrawingCtx;

use handle::RsvgHandle;

use property_bag::RsvgPropertyBag;

use state::RsvgState;

/* A *const RsvgNode is just a pointer for the C code's benefit: it
 * points to an  Rc<Node>, which is our refcounted Rust representation
 * of nodes.
 */
pub type RsvgNode = Rc<Node>;

/* A *const RsvgCNodeImpl is just an opaque pointer to the C code's
 * struct for a particular node type.
 */
pub enum RsvgCNodeImpl {}

pub trait NodeTrait {
    fn set_atts (&self, node: &RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag);
    fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32);
    fn get_c_impl (&self) -> *const RsvgCNodeImpl;
}

pub struct Node {
    node_type: NodeType,
    parent:    Option<Weak<Node>>,       // optional; weak ref to parent
    children:  RefCell<Vec<Rc<Node>>>,   // strong references to children
    state:     *mut RsvgState,
    node_impl: Box<NodeTrait>
}

/* Keep this in sync with rsvg-private.h:RsvgNodeType */
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum NodeType {
    Invalid = 0,

    Chars,
    Circle,
    ClipPath,
    ComponentTransferFunction,
    Defs,
    Ellipse,
    Filter,
    Group,
    Image,
    LightSource,
    Line,
    LinearGradient,
    Marker,
    Mask,
    Path,
    Pattern,
    Polygon,
    Polyline,
    RadialGradient,
    Rect,
    Stop,
    Svg,
    Switch,
    Symbol,
    Text,
    TRef,
    TSpan,
    Use,

    /* Filter primitives */
    FilterPrimitiveFirst,              /* just a marker; not a valid type */
    FilterPrimitiveBlend,
    FilterPrimitiveColorMatrix,
    FilterPrimitiveComponentTransfer,
    FilterPrimitiveComposite,
    FilterPrimitiveConvolveMatrix,
    FilterPrimitiveDiffuseLighting,
    FilterPrimitiveDisplacementMap,
    FilterPrimitiveErode,
    FilterPrimitiveFlood,
    FilterPrimitiveGaussianBlur,
    FilterPrimitiveImage,
    FilterPrimitiveMerge,
    FilterPrimitiveMergeNode,
    FilterPrimitiveOffset,
    FilterPrimitiveSpecularLighting,
    FilterPrimitiveTile,
    FilterPrimitiveTurbulence,
    FilterPrimitiveLast                /* just a marker; not a valid type */
}

impl Node {
    pub fn new (node_type: NodeType,
                parent:    Option<Weak<Node>>,
                state:     *mut RsvgState,
                node_impl: Box<NodeTrait>) -> Node {
        Node {
            node_type: node_type,
            parent:    parent,
            children:  RefCell::new (Vec::new ()),
            state:     state,
            node_impl: node_impl
        }
    }

    pub fn get_type (&self) -> NodeType {
        self.node_type
    }

    pub fn get_state (&self) -> *mut RsvgState {
        self.state
    }

    pub fn add_child (&self, child: &Rc<Node>) {
        self.children.borrow_mut ().push (child.clone ());
    }

    pub fn set_atts (&self, node: &RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag) {
        self.node_impl.set_atts (node, handle, pbag);
    }

    pub fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
        self.node_impl.draw (node, draw_ctx, dominate);
    }

    pub fn get_c_impl (&self) -> *const RsvgCNodeImpl {
        self.node_impl.get_c_impl ()
    }
}

extern "C" {
    fn rsvg_state_free (state: *mut RsvgState);
}

impl Drop for Node {
    fn drop (&mut self) {
//        unsafe { rsvg_state_free (self.state); }
    }
}

#[no_mangle]
pub extern fn rsvg_node_get_type (raw_node: *const RsvgNode) -> NodeType {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    node.get_type ()
}

pub fn box_node (node: RsvgNode) -> *mut RsvgNode {
    Box::into_raw (Box::new (node))
}

#[no_mangle]
pub extern fn rsvg_node_get_parent (raw_node: *const RsvgNode) -> *const RsvgNode {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    match node.parent {
        None => { ptr::null () }

        Some (ref weak_node) => {
            let strong_node = weak_node.upgrade ().unwrap ();
            box_node (strong_node)
        }
    }
}

#[no_mangle]
pub extern fn rsvg_node_ref (raw_node: *mut RsvgNode) -> *mut RsvgNode {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    box_node (node.clone ())
}

#[no_mangle]
pub extern fn rsvg_node_unref (raw_node: *mut RsvgNode) -> *mut RsvgNode {
    if !raw_node.is_null () {
        let _ = unsafe { Box::from_raw (raw_node) };
    }

    ptr::null_mut () // so the caller can do "node = rsvg_node_unref (node);" and lose access to the node
}

// See https://github.com/rust-lang/rust/issues/36497 - this is what
// added Rc::ptr_eq(), but we don't want to depend on unstable Rust
// just yet.

fn rc_node_ptr_eq<T: ?Sized> (this: &Rc<T>, other: &Rc<T>) -> bool {
    let this_ptr: *const T = &**this;
    let other_ptr: *const T = &**other;
    this_ptr == other_ptr
}

#[no_mangle]
pub extern fn rsvg_node_is_same (raw_node1: *const RsvgNode, raw_node2: *const RsvgNode) -> bool {
    if raw_node1.is_null () && raw_node2.is_null () {
        true
    } else if !raw_node1.is_null () && !raw_node2.is_null () {
        let node1: &RsvgNode = unsafe { & *raw_node1 };
        let node2: &RsvgNode = unsafe { & *raw_node2 };

        rc_node_ptr_eq (node1, node2)
    } else {
        false
    }
}

#[no_mangle]
pub extern fn rsvg_node_get_state (raw_node: *const RsvgNode) -> *mut RsvgState {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    node.get_state ()
}

#[no_mangle]
pub extern fn rsvg_node_add_child (raw_node: *mut RsvgNode, raw_child: *const RsvgNode) {
    assert! (!raw_node.is_null ());
    assert! (!raw_child.is_null ());
    let node: &mut RsvgNode = unsafe { &mut *raw_node };
    let child: &RsvgNode = unsafe { & *raw_child };

    node.add_child (child);
}

#[no_mangle]
pub extern fn rsvg_node_set_atts (raw_node: *mut RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag) {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    node.set_atts (node, handle, pbag);
}

#[no_mangle]
pub extern fn rsvg_node_draw (raw_node: *const RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    node.draw (node, draw_ctx, dominate);
}

type NodeForeachChild = unsafe extern "C" fn (node: *const RsvgNode, data: *const libc::c_void) -> bool;

#[no_mangle]
pub extern fn rsvg_node_foreach_child (raw_node: *const RsvgNode, func: NodeForeachChild, data: *const libc::c_void)
{
    assert! (!raw_node.is_null ());
    let node: &RsvgNode = unsafe { & *raw_node };

    for child in &*node.children.borrow () {
        let mut boxed_child = box_node (child.clone ());

        let next = unsafe { func (boxed_child, data) };

        boxed_child = rsvg_node_unref (boxed_child);

        if !next {
            break;
        }
    }
}

#[cfg(test)]
mod tests {
    use std::rc::Rc;
    use drawing_ctx::RsvgDrawingCtx;
    use handle::RsvgHandle;
    use property_bag::RsvgPropertyBag;
    use state::RsvgState;
    use super::*;
    use std::ptr;
    use std::mem;

    struct TestNodeImpl {}

    impl NodeTrait for TestNodeImpl {
        fn set_atts (&self, node: &RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag) {
        }

        fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
        }

        fn get_c_impl (&self) -> *const RsvgCNodeImpl {
            return ptr::null ();
        }
    }

    #[test]
    fn node_refs_and_unrefs () {
        let node = Rc::new (Node::new (NodeType::Path,
                                       None,
                                       ptr::null_mut (),
                                       Box::new (TestNodeImpl {})));

        let mut ref1 = box_node (node);

        let new_node: &mut RsvgNode = unsafe { &mut *ref1 };
        let weak = Rc::downgrade (new_node);

        let mut ref2 = unsafe { rsvg_node_ref (new_node) };
        assert! (weak.upgrade ().is_some ());

        ref2 = unsafe { rsvg_node_unref (ref2) };
        assert! (weak.upgrade ().is_some ());

        ref1 = unsafe { rsvg_node_unref (ref1) };
        assert! (weak.upgrade ().is_none ());
    }

    #[test]
    fn reffed_node_is_same_as_original_node () {
        let node = Rc::new (Node::new (NodeType::Path,
                                       None,
                                       ptr::null_mut (),
                                       Box::new (TestNodeImpl {})));

        let mut ref1 = box_node (node);

        let mut ref2 = unsafe { rsvg_node_ref (ref1) };

        unsafe { assert! (rsvg_node_is_same (ref1, ref2)); }

        ref1 = rsvg_node_unref (ref1);
        ref2 = rsvg_node_unref (ref2);
    }

    #[test]
    fn different_nodes_have_different_pointers () {
        let node1 = Rc::new (Node::new (NodeType::Path,
                                       None,
                                       ptr::null_mut (),
                                       Box::new (TestNodeImpl {})));

        let mut ref1 = box_node (node1);

        let node2 = Rc::new (Node::new (NodeType::Path,
                                       None,
                                       ptr::null_mut (),
                                       Box::new (TestNodeImpl {})));

        let mut ref2 = box_node (node2);

        unsafe { assert! (!rsvg_node_is_same (ref1, ref2)); }

        ref1 = rsvg_node_unref (ref1);
        ref2 = rsvg_node_unref (ref2);
    }
}
<|endoftext|>


<commit_before>use cgmath::*;
use crossbeam;
use rand;
use rand::Rng;
use utils::v3;

pub type V3 = Vector3<f32>;

pub struct CubeState {
    pub pos: V3,
    pub rot: Basis3<f32>,
    pub spd: V3,
    pub rot_axe: V3,
    pub rot_spd: f32,
}

pub struct State {
    pub tick: f64,
    pub cubes: Vec<CubeState>,
    pub light_pos: V3,
}

const CUBE_SPAN : f32 = 200.;

impl State {
    pub fn new(object_count: u32) -> Self {
        let mut rng = rand::XorShiftRng::new_unseeded();
        let mut cubes = Vec::with_capacity(object_count as usize);
        for _ in 0 .. object_count {
            let cube_state = CubeState {
                pos: v3((rng.next_f32() - 0.5) * CUBE_SPAN,
                             (rng.next_f32() - 0.5) * CUBE_SPAN,
                             (rng.next_f32() - 1.) * CUBE_SPAN),
                rot: <Basis3<f32> as Rotation<_>>::one(),
                spd: v3(rng.next_f32() - 0.5,
                             rng.next_f32() - 0.5,
                             rng.next_f32() - 0.5).normalize()*rng.next_f32()*1.,
                rot_axe: v3(rng.next_f32() - 0.5,
                             rng.next_f32() - 0.5,
                             rng.next_f32() - 0.5)
                              .normalize(),
                rot_spd: rng.next_f32()*30.0,
            };
            cubes.push(cube_state);
        };
        State {
            tick: 0.0,
            cubes: cubes,
            light_pos: v3(0., 0., 0.),
        }
    }

    pub fn update(&self, dt: f32, thread_cnt: u32) -> Self {
        // advance position of cubes
        let mut cubes = Vec::with_capacity(self.cubes.len());
        // Uninitialized content of cubes will be immediately overwritten
        unsafe{ cubes.set_len(self.cubes.len()) };
        crossbeam::scope(|scope| {
            let chunk_len = (cubes.len()/thread_cnt as usize)+1;
            for (chunk, chunk_src) in cubes[..].chunks_mut(chunk_len).zip(self.cubes[..].chunks(chunk_len)) {
                scope.spawn(move || {
                    for (c, cube) in chunk.iter_mut().zip(chunk_src) {
                        let mut new_spd = cube.spd;
                        let mut new_pos = cube.pos + cube.spd * dt;
                        if new_pos.x < -CUBE_SPAN/2. {
                            new_pos.x = -CUBE_SPAN/2.;
                            new_spd.x = -new_spd.x;
                        }
                        if new_pos.x > CUBE_SPAN/2. {
                            new_pos.x = CUBE_SPAN/2.;
                            new_spd.x = -new_spd.x;
                        }
                        if new_pos.y < -CUBE_SPAN/2. {
                            new_pos.y = -CUBE_SPAN/2.;
                            new_spd.y = -new_spd.y;
                        }
                        if new_pos.y > CUBE_SPAN/2. {
                            new_pos.y = CUBE_SPAN/2.;
                            new_spd.y = -new_spd.y;
                        }
                        if new_pos.z < -CUBE_SPAN {
                            new_pos.z = -CUBE_SPAN;
                            new_spd.z = -new_spd.z;
                        }
                        if new_pos.z > 0. {
                            new_pos.z = 0.;
                            new_spd.z = -new_spd.z;
                        }
                        *c = CubeState {
                            pos: new_pos,
                            spd: new_spd,
                            rot: Basis3::from_axis_angle(cube.rot_axe, Angle::from(deg(cube.rot_spd * dt))).concat(&cube.rot),
                            .. *cube
                        };
                    };
                });
            };
        });

//        for cube in &self.cubes {
//            let mut cs = CubeState {
//                pos: cube.pos + cube.spd * dt,
//                rot: Basis3::from_axis_angle(cube.rot_axe, Angle::from(deg(cube.rot_spd * dt))).concat(&cube.rot),
//                .. *cube};
//            cubes.push(cs);
//        }
        let (lx, ly) = f64::sin_cos(self.tick*0.1);
        let (lx, ly) = (lx as f32, ly as f32);
        let light_pos = v3(lx*50., ly*50., -3.);
        State {
            tick: self.tick + dt as f64,
            cubes: cubes,
            light_pos: light_pos,
        }
    }
}

use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{channel, Receiver, Sender};

fn state_update_agent(thread_cnt: u32, rx: Receiver<(Arc<State>, f32)>, tx: Sender<State>) {
    loop {
        if let Ok((state_ref, dt)) = rx.recv() {
            if let Err(_) = tx.send(state_ref.update(dt, thread_cnt)) {
                return ();
            }
        } else {
            return ();
        }
    }
}

pub struct StateUpdateAgent {
    tx: Sender<(Arc<State>, f32)>,
    rx: Receiver<State>,
}

impl StateUpdateAgent {
    pub fn new(thread_cnt: u32) -> Self {
        let (otx, orx) = channel();
        let (itx, irx) = channel();
        thread::spawn(move || state_update_agent(thread_cnt, orx, itx));
        StateUpdateAgent {
            tx: otx,
            rx: irx,
        }
    }

    pub fn start_update<'a>(&'a self, state: Arc<State>, dt: f32) -> UpdateResult<'a> {
        self.tx.send((state, dt)).unwrap();
        UpdateResult{
            agent: self,
            result_aquired: false,
        }
    }
}

pub struct UpdateResult<'a> {
    agent: &'a StateUpdateAgent,
    result_aquired: bool,
}

impl<'a> UpdateResult<'a> {
    pub fn get(&mut self) -> State {
        self.result_aquired = true;
        self.agent.rx.recv().unwrap()
    }
}

impl<'a> Drop for UpdateResult<'a> {
    fn drop(&mut self) {
        if !self.result_aquired {
            error!("Update result is not retrieved before drop");
        }
    }
}
<commit_msg>Minor tweaks<commit_after>use cgmath::*;
use crossbeam;
use rand;
use rand::Rng;
use utils::v3;

pub type V3 = Vector3<f32>;

#[derive(Clone)]
pub struct CubeState {
    pub pos: V3,
    pub rot: Basis3<f32>,
    pub spd: V3,
    pub rot_axe: V3,
    pub rot_spd: f32,
}

#[derive(Clone)]
pub struct State {
    pub tick: f64,
    pub cubes: Vec<CubeState>,
    pub light_pos: V3,
}

const CUBE_SPAN : f32 = 200.;

impl State {
    pub fn new(object_count: u32) -> Self {
        let mut rng = rand::XorShiftRng::new_unseeded();
        let mut cubes = Vec::with_capacity(object_count as usize);
        for _ in 0 .. object_count {
            let cube_state = CubeState {
                pos: v3((rng.next_f32() - 0.5) * CUBE_SPAN,
                             (rng.next_f32() - 0.5) * CUBE_SPAN,
                             (rng.next_f32() - 1.) * CUBE_SPAN),
                rot: <Basis3<f32> as Rotation<_>>::one(),
                spd: v3(rng.next_f32() - 0.5,
                             rng.next_f32() - 0.5,
                             rng.next_f32() - 0.5).normalize()*rng.next_f32()*1.,
                rot_axe: v3(rng.next_f32() - 0.5,
                             rng.next_f32() - 0.5,
                             rng.next_f32() - 0.5)
                              .normalize(),
                rot_spd: rng.next_f32()*30.0,
            };
            cubes.push(cube_state);
        };
        State {
            tick: 0.0,
            cubes: cubes,
            light_pos: v3(0., 0., 0.),
        }
    }

    fn update_one(cube: &CubeState, dt: f32) -> CubeState {
        let mut new_spd = cube.spd;
        let mut new_pos = cube.pos + cube.spd * dt;
        if new_pos.x < -CUBE_SPAN/2. {
            new_pos.x = -CUBE_SPAN/2.;
            new_spd.x = -new_spd.x;
        }
        if new_pos.x > CUBE_SPAN/2. {
            new_pos.x = CUBE_SPAN/2.;
            new_spd.x = -new_spd.x;
        }
        if new_pos.y < -CUBE_SPAN/2. {
            new_pos.y = -CUBE_SPAN/2.;
            new_spd.y = -new_spd.y;
        }
        if new_pos.y > CUBE_SPAN/2. {
            new_pos.y = CUBE_SPAN/2.;
            new_spd.y = -new_spd.y;
        }
        if new_pos.z < -CUBE_SPAN {
            new_pos.z = -CUBE_SPAN;
            new_spd.z = -new_spd.z;
        }
        if new_pos.z > 0. {
            new_pos.z = 0.;
            new_spd.z = -new_spd.z;
        }
        CubeState {
            pos: new_pos,
            spd: new_spd,
            rot: Basis3::from_axis_angle(cube.rot_axe, deg(cube.rot_spd * dt).into()).concat(&cube.rot),
            .. *cube
        }
    }

    pub fn update(&self, dt: f32, thread_cnt: u32) -> Self {
        if dt == 0.0 {
          return (*self).clone();
        }
        // advance position of cubes
        let mut cubes = Vec::with_capacity(self.cubes.len());
        if thread_cnt == 1 {
            for cube in &self.cubes[..] {
                cubes.push(State::update_one(cube, dt));
            }
        } else {
            // Uninitialized content of cubes will be immediately overwritten
            unsafe{ cubes.set_len(self.cubes.len()) };
            crossbeam::scope(|scope| {
                let chunk_len = (cubes.len()/thread_cnt as usize)+1;
                for (chunk, chunk_src) in cubes[..].chunks_mut(chunk_len).zip(self.cubes[..].chunks(chunk_len)) {
                    scope.spawn(move || {
                        for (c, cube) in chunk.iter_mut().zip(chunk_src) {
                            *c = State::update_one(cube, dt);
                        };
                    });
                };
            });
        }
        let (lx, ly) = f64::sin_cos(self.tick*0.1);
        let (lx, ly) = (lx as f32, ly as f32);
        let light_pos = v3(0., 0., -100.);//v3(lx*50., ly*50., -201.);
        State {
            tick: self.tick + dt as f64,
            cubes: cubes,
            light_pos: light_pos,
        }
    }
}

use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{channel, Receiver, Sender};

fn state_update_agent(thread_cnt: u32, rx: Receiver<(Arc<State>, f32)>, tx: Sender<State>) {
    loop {
        if let Ok((state_ref, dt)) = rx.recv() {
            if let Err(_) = tx.send(state_ref.update(dt, thread_cnt)) {
                return ();
            }
        } else {
            return ();
        }
    }
}

pub struct StateUpdateAgent {
    tx: Sender<(Arc<State>, f32)>,
    rx: Receiver<State>,
}

impl StateUpdateAgent {
    pub fn new(thread_cnt: u32) -> Self {
        let (otx, orx) = channel();
        let (itx, irx) = channel();
        thread::spawn(move || state_update_agent(thread_cnt, orx, itx));
        StateUpdateAgent {
            tx: otx,
            rx: irx,
        }
    }

    pub fn start_update<'a>(&'a self, state: Arc<State>, dt: f32) -> UpdateResult<'a> {
        self.tx.send((state, dt)).unwrap();
        UpdateResult{
            agent: self,
            result_aquired: false,
        }
    }
}

pub struct UpdateResult<'a> {
    agent: &'a StateUpdateAgent,
    result_aquired: bool,
}

impl<'a> UpdateResult<'a> {
    pub fn get(&mut self) -> State {
        self.result_aquired = true;
        self.agent.rx.recv().unwrap()
    }
}

impl<'a> Drop for UpdateResult<'a> {
    fn drop(&mut self) {
        if !self.result_aquired {
            error!("Update result is not retrieved before drop");
        }
    }
}
<|endoftext|>


<commit_before><ATTRIBUTE>#[macro_use]</ATTRIBUTE>
extern crate <CRATE>log</CRATE>;

use std::collections::<STRUCT>HashMap</STRUCT>;
use std::rc::<STRUCT>Rc</STRUCT>;

mod <MODULE>stuff</MODULE>;

pub enum <ENUM>Flag</ENUM> {
    <ENUM_VARIANT>Good</ENUM_VARIANT>,
    <ENUM_VARIANT>Bad</ENUM_VARIANT>,
    <ENUM_VARIANT>Ugly</ENUM_VARIANT>
}

const <CONSTANT>QUALITY</CONSTANT>: <ENUM>Flag</ENUM> = <ENUM>Flag</ENUM>::<ENUM_VARIANT>Good</ENUM_VARIANT>;

struct Table<const <CONST_PARAMETER>N</CONST_PARAMETER>: usize>([[i32; <CONST_PARAMETER>N</CONST_PARAMETER>]; <CONST_PARAMETER>N</CONST_PARAMETER>])

pub trait <TRAIT>Write</TRAIT> {
    fn <METHOD>write</METHOD>(&mut <SELF_PARAMETER>self</SELF_PARAMETER>, <PARAMETER>buf</PARAMETER>: &[<PRIMITIVE_TYPE>u8</PRIMITIVE_TYPE>]) -> <ENUM>Result</ENUM><usize>;
}

struct <STRUCT>Object</STRUCT><<TYPE_PARAMETER>T</TYPE_PARAMETER>> {
    <FIELD>flag</FIELD>: <ENUM>Flag</ENUM>,
    <FIELD>fields</FIELD>: <STRUCT>HashMap</STRUCT><<TYPE_PARAMETER>T</TYPE_PARAMETER>, <PRIMITIVE_TYPE>u64</PRIMITIVE_TYPE>>
}

<KEYWORD>union</KEYWORD> <UNION>MyUnion</UNION> {
    <FIELD>f1</FIELD>: <PRIMITIVE_TYPE>u32</PRIMITIVE_TYPE>,
    <FIELD>f2</FIELD>: <PRIMITIVE_TYPE>f32</PRIMITIVE_TYPE>,
}

type <TYPE_ALIAS>RcObject</TYPE_ALIAS><<TYPE_PARAMETER>T</TYPE_PARAMETER>> = <STRUCT>Rc</STRUCT><<STRUCT>Object</STRUCT><<TYPE_PARAMETER>T</TYPE_PARAMETER>>>;

impl<<TYPE_PARAMETER>T</TYPE_PARAMETER>> Write for <STRUCT>Object</STRUCT><<TYPE_PARAMETER>T</TYPE_PARAMETER>> {
    fn <METHOD>write</METHOD>(&mut <SELF_PARAMETER>self</SELF_PARAMETER>, <PARAMETER>buf</PARAMETER>: &[<PRIMITIVE_TYPE>u8</PRIMITIVE_TYPE>]) -> <ENUM>Result</ENUM><usize> {
        let <VARIABLE>s</VARIABLE> = stuff::<FUNCTION_CALL>write_map</FUNCTION_CALL>(&self.<FIELD>fields</FIELD>, <PARAMETER>buf</PARAMETER>)<Q_OPERATOR>?</Q_OPERATOR>;
        <MACRO>info!</MACRO>("{} byte(s) written", <VARIABLE>s</VARIABLE>);
        <ENUM_VARIANT>Ok</ENUM_VARIANT>(<VARIABLE>s</VARIABLE>)
    }
}

impl<<TYPE_PARAMETER>T</TYPE_PARAMETER>> <TRAIT>Default</TRAIT> for <STRUCT>Object</STRUCT><<TYPE_PARAMETER>T</TYPE_PARAMETER>> {
    fn <ASSOC_FUNCTION>default</ASSOC_FUNCTION>() -> Self {
        <STRUCT>Object</STRUCT> { <FIELD>flag</FIELD>: <ENUM>Flag</ENUM>::<ENUM_VARIANT>Good</ENUM_VARIANT>, <FIELD>fields</FIELD>: <STRUCT>HashMap</STRUCT>::<ASSOC_FUNCTION_CALL>new</ASSOC_FUNCTION_CALL>() }
    }
}

/* Block comment */
fn <FUNCTION>main</FUNCTION>() {
    // A simple integer calculator:
    // `+` or `-` means add or subtract by 1
    // `*` or `/` means multiply or divide by 2
    <MODULE>stuff</MODULE>::<STRUCT>AppVersion</STRUCT>::<ASSOC_FUNCTION_CALL>print</ASSOC_FUNCTION_CALL>();

    let <VARIABLE>input</VARIABLE> = <ENUM>Option</ENUM>::<ENUM_VARIANT>None</ENUM_VARIANT>;
    let <VARIABLE>program</VARIABLE> = <VARIABLE>input</VARIABLE>.<METHOD_CALL>unwrap_or_else</METHOD_CALL>(|| "+ + * - /");
    let mut <MUT_BINDING><VARIABLE>accumulator</VARIABLE></MUT_BINDING> = 0;

    for <VARIABLE>token</VARIABLE> in <VARIABLE>program</VARIABLE>.<METHOD_CALL>chars</METHOD_CALL>() {
        match <VARIABLE>token</VARIABLE> {
            '+' => <MUT_BINDING><VARIABLE>accumulator</VARIABLE></MUT_BINDING> += 1,
            '-' => <MUT_BINDING><VARIABLE>accumulator</VARIABLE></MUT_BINDING> -= 1,
            '*' => <MUT_BINDING><VARIABLE>accumulator</VARIABLE></MUT_BINDING> *= 2,
            '/' => <MUT_BINDING><VARIABLE>accumulator</VARIABLE></MUT_BINDING> /= 2,
            _ => { /* ignore everything else */ }
        }
    }

    <MACRO>info!</MACRO>("The program \"{}\" calculates the value {}",
            <VARIABLE>program</VARIABLE>, <MUT_BINDING><VARIABLE>accumulator</VARIABLE></MUT_BINDING>);
}

<DOC_COMMENT>/// Some documentation <DOC_CODE>`with a code`</DOC_CODE>, <DOC_EMPHASIS>*an italic text*</DOC_EMPHASIS>
/// and <DOC_STRONG>**a bold text**</DOC_STRONG>
/// <DOC_HEADING># Heading</DOC_HEADING>
/// <DOC_LINK>[Rust](https://www.rust-lang.org/)</DOC_LINK></DOC_COMMENT>
<ATTRIBUTE>#[cfg(target_os=</ATTRIBUTE>"linux"<ATTRIBUTE>)]</ATTRIBUTE>
<KEYWORD_UNSAFE>unsafe</KEYWORD_UNSAFE> fn <FUNCTION>a_function</FUNCTION><<TYPE_PARAMETER>T</TYPE_PARAMETER>: <LIFETIME>'lifetime</LIFETIME>>(<MUT_PARAMETER>count</MUT_PARAMETER>: &mut i64) -> ! {
    <MUT_PARAMETER>count</MUT_PARAMETER> += 1;
    'label: loop {
        let <VARIABLE>str_with_escapes</VARIABLE> = "Hello\x20W\u{f3}rld!\u{abcdef}";
        <MACRO>println!</MACRO>("<FORMAT_PARAMETER>{}</FORMAT_PARAMETER> <FORMAT_PARAMETER>{<FORMAT_SPECIFIER>foo</FORMAT_SPECIFIER>:<<FORMAT_SPECIFIER>4</FORMAT_SPECIFIER>}</FORMAT_PARAMETER>", str_with_escapes, foo = 42);
    }
}

fn <FUNCTION>test</FUNCTION>() {
    <KEYWORD_UNSAFE>unsafe</KEYWORD_UNSAFE> {
        <UNSAFE_CODE>a_function</UNSAFE_CODE>(1);
    }
}

<CFG_DISABLED_CODE>#[cfg(feature = "disabled_feature")]
fn cfg_disabled_function() {}</CFG_DISABLED_CODE>
<commit_msg>Add macro demo to highlighterDemoText.<commit_after><ATTRIBUTE>#[macro_use]</ATTRIBUTE>
extern crate <CRATE>log</CRATE>;

use std::collections::<STRUCT>HashMap</STRUCT>;
use std::rc::<STRUCT>Rc</STRUCT>;

mod <MODULE>stuff</MODULE>;

pub enum <ENUM>Flag</ENUM> {
    <ENUM_VARIANT>Good</ENUM_VARIANT>,
    <ENUM_VARIANT>Bad</ENUM_VARIANT>,
    <ENUM_VARIANT>Ugly</ENUM_VARIANT>
}

const <CONSTANT>QUALITY</CONSTANT>: <ENUM>Flag</ENUM> = <ENUM>Flag</ENUM>::<ENUM_VARIANT>Good</ENUM_VARIANT>;

struct Table<const <CONST_PARAMETER>N</CONST_PARAMETER>: usize>([[i32; <CONST_PARAMETER>N</CONST_PARAMETER>]; <CONST_PARAMETER>N</CONST_PARAMETER>])

pub trait <TRAIT>Write</TRAIT> {
    fn <METHOD>write</METHOD>(&mut <SELF_PARAMETER>self</SELF_PARAMETER>, <PARAMETER>buf</PARAMETER>: &[<PRIMITIVE_TYPE>u8</PRIMITIVE_TYPE>]) -> <ENUM>Result</ENUM><usize>;
}

struct <STRUCT>Object</STRUCT><<TYPE_PARAMETER>T</TYPE_PARAMETER>> {
    <FIELD>flag</FIELD>: <ENUM>Flag</ENUM>,
    <FIELD>fields</FIELD>: <STRUCT>HashMap</STRUCT><<TYPE_PARAMETER>T</TYPE_PARAMETER>, <PRIMITIVE_TYPE>u64</PRIMITIVE_TYPE>>
}

<KEYWORD>union</KEYWORD> <UNION>MyUnion</UNION> {
    <FIELD>f1</FIELD>: <PRIMITIVE_TYPE>u32</PRIMITIVE_TYPE>,
    <FIELD>f2</FIELD>: <PRIMITIVE_TYPE>f32</PRIMITIVE_TYPE>,
}

type <TYPE_ALIAS>RcObject</TYPE_ALIAS><<TYPE_PARAMETER>T</TYPE_PARAMETER>> = <STRUCT>Rc</STRUCT><<STRUCT>Object</STRUCT><<TYPE_PARAMETER>T</TYPE_PARAMETER>>>;

impl<<TYPE_PARAMETER>T</TYPE_PARAMETER>> Write for <STRUCT>Object</STRUCT><<TYPE_PARAMETER>T</TYPE_PARAMETER>> {
    fn <METHOD>write</METHOD>(&mut <SELF_PARAMETER>self</SELF_PARAMETER>, <PARAMETER>buf</PARAMETER>: &[<PRIMITIVE_TYPE>u8</PRIMITIVE_TYPE>]) -> <ENUM>Result</ENUM><usize> {
        let <VARIABLE>s</VARIABLE> = stuff::<FUNCTION_CALL>write_map</FUNCTION_CALL>(&self.<FIELD>fields</FIELD>, <PARAMETER>buf</PARAMETER>)<Q_OPERATOR>?</Q_OPERATOR>;
        <MACRO>info!</MACRO>("{} byte(s) written", <VARIABLE>s</VARIABLE>);
        <ENUM_VARIANT>Ok</ENUM_VARIANT>(<VARIABLE>s</VARIABLE>)
    }
}

impl<<TYPE_PARAMETER>T</TYPE_PARAMETER>> <TRAIT>Default</TRAIT> for <STRUCT>Object</STRUCT><<TYPE_PARAMETER>T</TYPE_PARAMETER>> {
    fn <ASSOC_FUNCTION>default</ASSOC_FUNCTION>() -> Self {
        <STRUCT>Object</STRUCT> { <FIELD>flag</FIELD>: <ENUM>Flag</ENUM>::<ENUM_VARIANT>Good</ENUM_VARIANT>, <FIELD>fields</FIELD>: <STRUCT>HashMap</STRUCT>::<ASSOC_FUNCTION_CALL>new</ASSOC_FUNCTION_CALL>() }
    }
}

<MACRO>macro_rules</MACRO><MACRO>!</MACRO> make_wrapper {
    (<MACRO>$</MACRO> serde_ty<MACRO>:</MACRO><MACRO>ident</MACRO>, <MACRO>$</MACRO> base_ty<MACRO>:</MACRO><MACRO>ty</MACRO>
, <MACRO>$</MACRO> format_string<MACRO>:</MACRO><MACRO>literal</MACRO> <MACRO>$</MACRO><MACRO>(</MACRO>, <MACRO>$</MACRO> lu_ty<MACRO>:</MACRO><MACRO>ty</MACRO><MACRO>)</MACRO><MACRO>?</MACRO>) => {
        pub struct <MACRO>$</MACRO> serde_ty(<MACRO>$</MACRO> base_ty);
        impl From<<MACRO>$</MACRO> base_ty> for <MACRO>$</MACRO> serde_ty {
            fn from(base: <MACRO>$</MACRO> base_ty) -> Self {
                Self(base)
            }
        }
        <MACRO>$</MACRO><MACRO>(</MACRO>
            impl From<<MACRO>$</MACRO> lu_ty> for <MACRO>$</MACRO> serde_ty {
                fn from(lu: <MACRO>$</MACRO> lu_ty) -> Self {
                    Self(lu.get())
                }
            }
            impl From<<MACRO>$</MACRO> serde_ty> for <MACRO>$</MACRO> lu_ty {
                fn from(st: <MACRO>$</MACRO> serde_ty) -> Self {
                    Self::new(st.0)
                }
            }
        <MACRO>)</MACRO><MACRO>?</MACRO>
    }
}

/* Block comment */
fn <FUNCTION>main</FUNCTION>() {
    // A simple integer calculator:
    // `+` or `-` means add or subtract by 1
    // `*` or `/` means multiply or divide by 2
    <MODULE>stuff</MODULE>::<STRUCT>AppVersion</STRUCT>::<ASSOC_FUNCTION_CALL>print</ASSOC_FUNCTION_CALL>();

    let <VARIABLE>input</VARIABLE> = <ENUM>Option</ENUM>::<ENUM_VARIANT>None</ENUM_VARIANT>;
    let <VARIABLE>program</VARIABLE> = <VARIABLE>input</VARIABLE>.<METHOD_CALL>unwrap_or_else</METHOD_CALL>(|| "+ + * - /");
    let mut <MUT_BINDING><VARIABLE>accumulator</VARIABLE></MUT_BINDING> = 0;

    for <VARIABLE>token</VARIABLE> in <VARIABLE>program</VARIABLE>.<METHOD_CALL>chars</METHOD_CALL>() {
        match <VARIABLE>token</VARIABLE> {
            '+' => <MUT_BINDING><VARIABLE>accumulator</VARIABLE></MUT_BINDING> += 1,
            '-' => <MUT_BINDING><VARIABLE>accumulator</VARIABLE></MUT_BINDING> -= 1,
            '*' => <MUT_BINDING><VARIABLE>accumulator</VARIABLE></MUT_BINDING> *= 2,
            '/' => <MUT_BINDING><VARIABLE>accumulator</VARIABLE></MUT_BINDING> /= 2,
            _ => { /* ignore everything else */ }
        }
    }

    <MACRO>info!</MACRO>("The program \"{}\" calculates the value {}",
            <VARIABLE>program</VARIABLE>, <MUT_BINDING><VARIABLE>accumulator</VARIABLE></MUT_BINDING>);
}

<DOC_COMMENT>/// Some documentation <DOC_CODE>`with a code`</DOC_CODE>, <DOC_EMPHASIS>*an italic text*</DOC_EMPHASIS>
/// and <DOC_STRONG>**a bold text**</DOC_STRONG>
/// <DOC_HEADING># Heading</DOC_HEADING>
/// <DOC_LINK>[Rust](https://www.rust-lang.org/)</DOC_LINK></DOC_COMMENT>
<ATTRIBUTE>#[cfg(target_os=</ATTRIBUTE>"linux"<ATTRIBUTE>)]</ATTRIBUTE>
<KEYWORD_UNSAFE>unsafe</KEYWORD_UNSAFE> fn <FUNCTION>a_function</FUNCTION><<TYPE_PARAMETER>T</TYPE_PARAMETER>: <LIFETIME>'lifetime</LIFETIME>>(<MUT_PARAMETER>count</MUT_PARAMETER>: &mut i64) -> ! {
    <MUT_PARAMETER>count</MUT_PARAMETER> += 1;
    'label: loop {
        let <VARIABLE>str_with_escapes</VARIABLE> = "Hello\x20W\u{f3}rld!\u{abcdef}";
        <MACRO>println!</MACRO>("<FORMAT_PARAMETER>{}</FORMAT_PARAMETER> <FORMAT_PARAMETER>{<FORMAT_SPECIFIER>foo</FORMAT_SPECIFIER>:<<FORMAT_SPECIFIER>4</FORMAT_SPECIFIER>}</FORMAT_PARAMETER>", str_with_escapes, foo = 42);
    }
}

fn <FUNCTION>test</FUNCTION>() {
    <KEYWORD_UNSAFE>unsafe</KEYWORD_UNSAFE> {
        <UNSAFE_CODE>a_function</UNSAFE_CODE>(1);
    }
}

<CFG_DISABLED_CODE>#[cfg(feature = "disabled_feature")]
fn cfg_disabled_function() {}</CFG_DISABLED_CODE>
<|endoftext|>


<commit_before>// Copyright 2020 The Tink-Rust Authors
//
// 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.
//
////////////////////////////////////////////////////////////////////////////////

//! Factory methods for [`tink::Verifier`] instances.

use std::sync::Arc;
use tink::{utils::wrap_err, TinkError};

/// Return a [`tink::Verifier`] primitive from the given keyset handle.
pub fn new_verifier(h: &tink::keyset::Handle) -> Result<Box<dyn tink::Verifier>, TinkError> {
    new_verifier_with_key_manager(h, None)
}

/// Return a [`tink::Verifier`] primitive from the given keyset handle and custom key manager.
pub fn new_verifier_with_key_manager(
    h: &tink::keyset::Handle,
    km: Option<Arc<dyn tink::registry::KeyManager>>,
) -> Result<Box<dyn tink::Verifier>, TinkError> {
    let ps = h
        .primitives_with_key_manager(km)
        .map_err(|e| wrap_err("verifier::factory: cannot obtain primitive set", e))?;

    let ret = WrappedVerifier::new(ps)?;
    Ok(Box::new(ret))
}

/// A [`tink::Verifier`] implementation that uses the underlying primitive set for verifying.
struct WrappedVerifier {
    ps: tink::primitiveset::PrimitiveSet,
}

impl WrappedVerifier {
    pub fn new(ps: tink::primitiveset::PrimitiveSet) -> Result<WrappedVerifier, TinkError> {
        let primary = match &ps.primary {
            None => return Err("verifier::factory: no primary primitive".into()),
            Some(p) => p,
        };
        match primary.primitive {
            tink::Primitive::Verifier(_) => {}
            _ => return Err("verifier::factory: not a Verifier primitive".into()),
        };
        for (_, primitives) in ps.entries.iter() {
            for p in primitives {
                match p.primitive {
                    tink::Primitive::Verifier(_) => {}
                    _ => return Err("verifier::factory: not a Verifier primitive".into()),
                };
            }
        }
        Ok(WrappedVerifier { ps })
    }
}

impl tink::Verifier for WrappedVerifier {
    fn verify(&self, signature: &[u8], data: &[u8]) -> Result<(), TinkError> {
        let prefix_size = tink::cryptofmt::NON_RAW_PREFIX_SIZE;
        if signature.len() < prefix_size {
            return Err("verifier::factory: invalid signature".into());
        }

        // try non-raw keys
        let prefix = &signature[..prefix_size];
        let signature_no_prefix = &signature[prefix_size..];
        let entries = self.ps.entries_for_prefix(&prefix);
        for entry in &entries {
            if let tink::Primitive::Verifier(p) = &entry.primitive {
                let result = if entry.prefix_type == tink::proto::OutputPrefixType::Legacy {
                    let mut signed_data_copy = Vec::with_capacity(data.len() + 1);
                    signed_data_copy.extend_from_slice(data);
                    signed_data_copy.push(tink::cryptofmt::LEGACY_START_BYTE);
                    p.verify(signature_no_prefix, &signed_data_copy)
                } else {
                    p.verify(signature_no_prefix, data)
                };
                if result.is_ok() {
                    return Ok(());
                }
            } else {
                return Err("verifier::factory: not a Verifier primitive".into());
            }
        }

        // try raw keys
        let entries = self.ps.raw_entries();
        for entry in &entries {
            if let tink::Primitive::Verifier(p) = &entry.primitive {
                if p.verify(signature, data).is_ok() {
                    return Ok(());
                }
            } else {
                return Err("verifier::factory: not a Verifier primitive".into());
            }
        }

        Err("verifier::factory: invalid signature".into())
    }
}
<commit_msg>signature: WrappedVerifier::new need not be pub<commit_after>// Copyright 2020 The Tink-Rust Authors
//
// 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.
//
////////////////////////////////////////////////////////////////////////////////

//! Factory methods for [`tink::Verifier`] instances.

use std::sync::Arc;
use tink::{utils::wrap_err, TinkError};

/// Return a [`tink::Verifier`] primitive from the given keyset handle.
pub fn new_verifier(h: &tink::keyset::Handle) -> Result<Box<dyn tink::Verifier>, TinkError> {
    new_verifier_with_key_manager(h, None)
}

/// Return a [`tink::Verifier`] primitive from the given keyset handle and custom key manager.
pub fn new_verifier_with_key_manager(
    h: &tink::keyset::Handle,
    km: Option<Arc<dyn tink::registry::KeyManager>>,
) -> Result<Box<dyn tink::Verifier>, TinkError> {
    let ps = h
        .primitives_with_key_manager(km)
        .map_err(|e| wrap_err("verifier::factory: cannot obtain primitive set", e))?;

    let ret = WrappedVerifier::new(ps)?;
    Ok(Box::new(ret))
}

/// A [`tink::Verifier`] implementation that uses the underlying primitive set for verifying.
struct WrappedVerifier {
    ps: tink::primitiveset::PrimitiveSet,
}

impl WrappedVerifier {
    fn new(ps: tink::primitiveset::PrimitiveSet) -> Result<WrappedVerifier, TinkError> {
        let primary = match &ps.primary {
            None => return Err("verifier::factory: no primary primitive".into()),
            Some(p) => p,
        };
        match primary.primitive {
            tink::Primitive::Verifier(_) => {}
            _ => return Err("verifier::factory: not a Verifier primitive".into()),
        };
        for (_, primitives) in ps.entries.iter() {
            for p in primitives {
                match p.primitive {
                    tink::Primitive::Verifier(_) => {}
                    _ => return Err("verifier::factory: not a Verifier primitive".into()),
                };
            }
        }
        Ok(WrappedVerifier { ps })
    }
}

impl tink::Verifier for WrappedVerifier {
    fn verify(&self, signature: &[u8], data: &[u8]) -> Result<(), TinkError> {
        let prefix_size = tink::cryptofmt::NON_RAW_PREFIX_SIZE;
        if signature.len() < prefix_size {
            return Err("verifier::factory: invalid signature".into());
        }

        // try non-raw keys
        let prefix = &signature[..prefix_size];
        let signature_no_prefix = &signature[prefix_size..];
        let entries = self.ps.entries_for_prefix(&prefix);
        for entry in &entries {
            if let tink::Primitive::Verifier(p) = &entry.primitive {
                let result = if entry.prefix_type == tink::proto::OutputPrefixType::Legacy {
                    let mut signed_data_copy = Vec::with_capacity(data.len() + 1);
                    signed_data_copy.extend_from_slice(data);
                    signed_data_copy.push(tink::cryptofmt::LEGACY_START_BYTE);
                    p.verify(signature_no_prefix, &signed_data_copy)
                } else {
                    p.verify(signature_no_prefix, data)
                };
                if result.is_ok() {
                    return Ok(());
                }
            } else {
                return Err("verifier::factory: not a Verifier primitive".into());
            }
        }

        // try raw keys
        let entries = self.ps.raw_entries();
        for entry in &entries {
            if let tink::Primitive::Verifier(p) = &entry.primitive {
                if p.verify(signature, data).is_ok() {
                    return Ok(());
                }
            } else {
                return Err("verifier::factory: not a Verifier primitive".into());
            }
        }

        Err("verifier::factory: invalid signature".into())
    }
}
<|endoftext|>


<commit_before>use futures::sync::mpsc::{self, Sender};
use godcoin::{blockchain::ReindexOpts, get_epoch_ms, net::*, prelude::*};
use log::{error, info, warn, debug};
use std::{
    io::Cursor,
    net::SocketAddr,
    path::PathBuf,
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
    time::Duration,
};
use tokio::{net::TcpListener, prelude::*, timer::Interval};
use tokio_tungstenite::tungstenite::{protocol, Message as WsMessage};

mod block_range;
mod forever;
pub mod minter;
pub mod pool;

pub mod prelude {
    pub use super::minter::*;
    pub use super::pool::SubscriptionPool;
}

use block_range::AsyncBlockRange;
use prelude::*;

pub struct ServerOpts {
    pub blocklog_loc: PathBuf,
    pub index_loc: PathBuf,
    pub minter_key: KeyPair,
    pub bind_addr: String,
    pub reindex: Option<ReindexOpts>,
    pub enable_stale_production: bool,
}

#[derive(Clone)]
pub struct ServerData {
    pub chain: Arc<Blockchain>,
    pub minter: Minter,
    pub sub_pool: SubscriptionPool,
}

pub fn start(opts: ServerOpts) {
    let blockchain = Arc::new(Blockchain::new(&opts.blocklog_loc, &opts.index_loc));

    let is_empty = blockchain.is_empty();
    if !is_empty && blockchain.index_status() != IndexStatus::Complete {
        warn!(
            "Indexing not complete (status = {:?})",
            blockchain.index_status()
        );
        match opts.reindex {
            Some(opts) => blockchain.reindex(opts),
            None => panic!("index incomplete, aborting..."),
        }
    }

    if is_empty {
        let info = blockchain.create_genesis_block(opts.minter_key.clone());
        info!("=> Generated new block chain");
        info!("=> {:?}", info.script);
        for (index, key) in info.wallet_keys.iter().enumerate() {
            info!("=> Wallet key {}: {}", index + 1, key.1.to_wif());
        }
    }

    info!(
        "Using height in block log at {}",
        blockchain.get_chain_height()
    );

    let sub_pool = SubscriptionPool::new();
    let minter = Minter::new(
        Arc::clone(&blockchain),
        opts.minter_key,
        sub_pool.clone(),
        opts.enable_stale_production,
    );
    minter.clone().start_production_loop();

    let data = Arc::new(ServerData {
        chain: Arc::clone(&blockchain),
        minter,
        sub_pool,
    });

    let addr = opts.bind_addr.parse::<SocketAddr>().unwrap();
    start_server(addr, data);
}

fn start_server(server_addr: SocketAddr, data: Arc<ServerData>) {
    let server = TcpListener::bind(&server_addr).unwrap();
    let incoming = forever::ListenForever::new(server.incoming());
    tokio::spawn(incoming.for_each(move |stream| {
        let peer_addr = stream.peer_addr().unwrap();
        let data = Arc::clone(&data);
        let config = Some(protocol::WebSocketConfig {
            // # of protocol Message's
            max_send_queue: Some(16),
            // 64 MiB
            max_message_size: Some(64 << 20),
            // 16 MiB
            max_frame_size: Some(16 << 20),
        });
        tokio::spawn(
            tokio_tungstenite::accept_async_with_config(stream, config)
                .and_then(move |ws| {
                    info!("[{}] Connection opened", peer_addr);

                    let (tx, rx) = mpsc::channel(32);
                    let (sink, stream) = ws.split();
                    let mut state = WsState::new(peer_addr, tx.clone());
                    let needs_pong = state.needs_pong();

                    let ws_reader = stream.for_each({
                        let data = Arc::clone(&data);
                        let tx = tx.clone();
                        move |msg| {
                            let res = process_ws_message(&data, &mut state, msg);
                            if let Some(res) = res {
                                future::Either::A(tx.clone().send(res).then(move |res| {
                                    if res.is_err() {
                                        error!("[{}] Failed to send message", peer_addr);
                                    }
                                    Ok(())
                                }))
                            } else {
                                future::Either::B(future::ok(()))
                            }
                        }
                    });
                    let ws_writer = rx.forward(sink.sink_map_err(move |e| {
                        error!("[{}] Sink send error: {:?}", peer_addr, e);
                    }));

                    let heartbeat_interval = Interval::new_interval(Duration::from_secs(20))
                        .take_while(move |_| Ok(!needs_pong.swap(true, Ordering::AcqRel)))
                        .for_each(move |_| {
                            let nonce = get_epoch_ms();
                            let msg = Msg {
                                id: u32::max_value(),
                                body: Body::Ping(nonce),
                            };
                            debug!("[{}] Sending ping: {}", peer_addr, nonce);

                            let mut buf = Vec::with_capacity(16);
                            msg.serialize(&mut buf);
                            tx.clone().send(WsMessage::Binary(buf)).then(|_| Ok(()))
                        });

                    let conn = ws_reader.select2(ws_writer).select2(heartbeat_interval);
                    tokio::spawn(conn.then(move |_| {
                        info!("[{}] Connection closed", peer_addr);
                        // Remove block subscriptions if there are any
                        data.sub_pool.remove(peer_addr);
                        Ok(())
                    }));

                    Ok(())
                })
                .map_err(move |e| {
                    error!("[{}] WS accept error = {:?}", peer_addr, e);
                }),
        );
        Ok(())
    }));
}

pub fn process_ws_message(
    data: &ServerData,
    state: &mut WsState,
    msg: WsMessage,
) -> Option<WsMessage> {
    match msg {
        WsMessage::Binary(buf) => {
            state.set_needs_pong(false);

            let mut cur = Cursor::<&[u8]>::new(&buf);
            let msg = match Msg::deserialize(&mut cur) {
                Ok(msg) => {
                    let id = msg.id;
                    if cur.position() != buf.len() as u64 {
                        Msg {
                            id,
                            body: Body::Error(ErrorKind::BytesRemaining),
                        }
                    } else {
                        match handle_protocol_message(data, state, msg) {
                            Some(body) => Msg { id, body },
                            None => return None,
                        }
                    }
                }
                Err(e) => {
                    error!("Error occurred during deserialization: {:?}", e);
                    Msg {
                        id: u32::max_value(),
                        body: Body::Error(ErrorKind::Io),
                    }
                }
            };

            let mut buf = Vec::with_capacity(65536);
            msg.serialize(&mut buf);
            Some(WsMessage::Binary(buf))
        }
        WsMessage::Text(_) => Some(WsMessage::Close(Some(protocol::CloseFrame {
            code: protocol::frame::coding::CloseCode::Unsupported,
            reason: "text is not supported".into(),
        }))),
        _ => None,
    }
}

fn handle_protocol_message(data: &ServerData, state: &mut WsState, msg: Msg) -> Option<Body> {
    match msg.body {
        Body::Error(e) => {
            warn!(
                "[{}] Received error message from client: {:?}",
                state.addr(),
                e
            );
            None
        }
        Body::Request(req) => handle_rpc_request(data, state, msg.id, req),
        Body::Response(res) => {
            warn!(
                "[{}] Unexpected response from client: {:?}",
                state.addr(),
                res
            );
            None
        }
        Body::Ping(nonce) => {
            debug!("[{}] Received ping: {}", state.addr(), nonce);
            Some(Body::Pong(nonce))
        }
        Body::Pong(nonce) => {
            debug!("[{}] Received pong: {}", state.addr(), nonce);
            // We don't need to update the `needs_pong` state as it has already been updated when the message was
            // deserialized
            None
        }
    }
}

fn handle_rpc_request(
    data: &ServerData,
    state: &mut WsState,
    id: u32,
    req: rpc::Request,
) -> Option<Body> {
    Some(match req {
        rpc::Request::Broadcast(tx) => {
            let res = data.minter.push_tx(tx);
            match res {
                Ok(_) => Body::Response(rpc::Response::Broadcast),
                Err(e) => Body::Error(ErrorKind::TxValidation(e)),
            }
        }
        rpc::Request::SetBlockFilter(filter) => {
            if filter.len() > 16 {
                return Some(Body::Error(ErrorKind::InvalidRequest));
            }
            state.filter = Some(filter);
            Body::Response(rpc::Response::SetBlockFilter)
        }
        rpc::Request::ClearBlockFilter => {
            state.filter = None;
            Body::Response(rpc::Response::ClearBlockFilter)
        }
        rpc::Request::Subscribe => {
            data.sub_pool.insert(state.addr(), state.sender());
            Body::Response(rpc::Response::Subscribe)
        }
        rpc::Request::Unsubscribe => {
            data.sub_pool.remove(state.addr());
            Body::Response(rpc::Response::Unsubscribe)
        }
        rpc::Request::GetProperties => {
            let props = data.chain.get_properties();
            Body::Response(rpc::Response::GetProperties(props))
        }
        rpc::Request::GetBlock(height) => match &state.filter {
            Some(filter) => match data.chain.get_filtered_block(height, filter) {
                Some(block) => Body::Response(rpc::Response::GetBlock(block)),
                None => Body::Error(ErrorKind::InvalidHeight),
            },
            None => match data.chain.get_block(height) {
                Some(block) => Body::Response(rpc::Response::GetBlock(FilteredBlock::Block(block))),
                None => Body::Error(ErrorKind::InvalidHeight),
            },
        },
        rpc::Request::GetFullBlock(height) => match data.chain.get_block(height) {
            Some(block) => Body::Response(rpc::Response::GetFullBlock(block)),
            None => Body::Error(ErrorKind::InvalidHeight),
        },
        rpc::Request::GetBlockRange(min_height, max_height) => {
            let range = AsyncBlockRange::try_new(Arc::clone(&data.chain), min_height, max_height);
            match range {
                Some(mut range) => {
                    if let Some(filter) = state.filter() {
                        range.set_filter(Some(filter.clone()));
                    }

                    let peer_addr = state.addr();
                    let tx = state.sender();
                    tokio::spawn(
                        range
                            .map(move |block| {
                                let msg = Msg {
                                    id,
                                    body: Body::Response(rpc::Response::GetBlock(block)),
                                };

                                let mut buf = Vec::with_capacity(65536);
                                msg.serialize(&mut buf);
                                WsMessage::Binary(buf)
                            })
                            .forward(tx.clone().sink_map_err(move |_| {
                                error!("[{}] Failed to send block range update", peer_addr);
                            }))
                            .and_then(move |_| {
                                let msg = Msg {
                                    id,
                                    body: Body::Response(rpc::Response::GetBlockRange),
                                };

                                let mut buf = Vec::with_capacity(32);
                                msg.serialize(&mut buf);
                                tx.send(WsMessage::Binary(buf))
                                    .map(|_sink| ())
                                    .map_err(move |_| {
                                        error!(
                                            "[{}] Failed to send block range finalizer",
                                            peer_addr
                                        );
                                    })
                            }),
                    );

                    return None;
                }
                None => Body::Error(ErrorKind::InvalidHeight),
            }
        }
        rpc::Request::GetAddressInfo(addr) => {
            let res = data.minter.get_addr_info(&addr);
            match res {
                Ok(info) => Body::Response(rpc::Response::GetAddressInfo(info)),
                Err(e) => Body::Error(ErrorKind::TxValidation(e)),
            }
        }
    })
}

pub struct WsState {
    filter: Option<BlockFilter>,
    addr: SocketAddr,
    tx: Sender<WsMessage>,
    needs_pong: Arc<AtomicBool>,
}

impl WsState {
    #[inline]
    pub fn new(addr: SocketAddr, tx: Sender<WsMessage>) -> Self {
        Self {
            filter: None,
            addr,
            tx,
            needs_pong: Arc::new(AtomicBool::new(false)),
        }
    }

    #[inline]
    pub fn needs_pong(&self) -> Arc<AtomicBool> {
        Arc::clone(&self.needs_pong)
    }

    #[inline]
    pub fn set_needs_pong(&self, flag: bool) {
        self.needs_pong.store(flag, Ordering::Release);
    }

    #[inline]
    pub fn addr(&self) -> SocketAddr {
        self.addr
    }

    #[inline]
    pub fn filter(&self) -> Option<&BlockFilter> {
        self.filter.as_ref()
    }

    #[inline]
    pub fn sender(&self) -> Sender<WsMessage> {
        self.tx.clone()
    }
}
<commit_msg>Formatting<commit_after>use futures::sync::mpsc::{self, Sender};
use godcoin::{blockchain::ReindexOpts, get_epoch_ms, net::*, prelude::*};
use log::{debug, error, info, warn};
use std::{
    io::Cursor,
    net::SocketAddr,
    path::PathBuf,
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
    time::Duration,
};
use tokio::{net::TcpListener, prelude::*, timer::Interval};
use tokio_tungstenite::tungstenite::{protocol, Message as WsMessage};

mod block_range;
mod forever;
pub mod minter;
pub mod pool;

pub mod prelude {
    pub use super::minter::*;
    pub use super::pool::SubscriptionPool;
}

use block_range::AsyncBlockRange;
use prelude::*;

pub struct ServerOpts {
    pub blocklog_loc: PathBuf,
    pub index_loc: PathBuf,
    pub minter_key: KeyPair,
    pub bind_addr: String,
    pub reindex: Option<ReindexOpts>,
    pub enable_stale_production: bool,
}

#[derive(Clone)]
pub struct ServerData {
    pub chain: Arc<Blockchain>,
    pub minter: Minter,
    pub sub_pool: SubscriptionPool,
}

pub fn start(opts: ServerOpts) {
    let blockchain = Arc::new(Blockchain::new(&opts.blocklog_loc, &opts.index_loc));

    let is_empty = blockchain.is_empty();
    if !is_empty && blockchain.index_status() != IndexStatus::Complete {
        warn!(
            "Indexing not complete (status = {:?})",
            blockchain.index_status()
        );
        match opts.reindex {
            Some(opts) => blockchain.reindex(opts),
            None => panic!("index incomplete, aborting..."),
        }
    }

    if is_empty {
        let info = blockchain.create_genesis_block(opts.minter_key.clone());
        info!("=> Generated new block chain");
        info!("=> {:?}", info.script);
        for (index, key) in info.wallet_keys.iter().enumerate() {
            info!("=> Wallet key {}: {}", index + 1, key.1.to_wif());
        }
    }

    info!(
        "Using height in block log at {}",
        blockchain.get_chain_height()
    );

    let sub_pool = SubscriptionPool::new();
    let minter = Minter::new(
        Arc::clone(&blockchain),
        opts.minter_key,
        sub_pool.clone(),
        opts.enable_stale_production,
    );
    minter.clone().start_production_loop();

    let data = Arc::new(ServerData {
        chain: Arc::clone(&blockchain),
        minter,
        sub_pool,
    });

    let addr = opts.bind_addr.parse::<SocketAddr>().unwrap();
    start_server(addr, data);
}

fn start_server(server_addr: SocketAddr, data: Arc<ServerData>) {
    let server = TcpListener::bind(&server_addr).unwrap();
    let incoming = forever::ListenForever::new(server.incoming());
    tokio::spawn(incoming.for_each(move |stream| {
        let peer_addr = stream.peer_addr().unwrap();
        let data = Arc::clone(&data);
        let config = Some(protocol::WebSocketConfig {
            // # of protocol Message's
            max_send_queue: Some(16),
            // 64 MiB
            max_message_size: Some(64 << 20),
            // 16 MiB
            max_frame_size: Some(16 << 20),
        });
        tokio::spawn(
            tokio_tungstenite::accept_async_with_config(stream, config)
                .and_then(move |ws| {
                    info!("[{}] Connection opened", peer_addr);

                    let (tx, rx) = mpsc::channel(32);
                    let (sink, stream) = ws.split();
                    let mut state = WsState::new(peer_addr, tx.clone());
                    let needs_pong = state.needs_pong();

                    let ws_reader = stream.for_each({
                        let data = Arc::clone(&data);
                        let tx = tx.clone();
                        move |msg| {
                            let res = process_ws_message(&data, &mut state, msg);
                            if let Some(res) = res {
                                future::Either::A(tx.clone().send(res).then(move |res| {
                                    if res.is_err() {
                                        error!("[{}] Failed to send message", peer_addr);
                                    }
                                    Ok(())
                                }))
                            } else {
                                future::Either::B(future::ok(()))
                            }
                        }
                    });
                    let ws_writer = rx.forward(sink.sink_map_err(move |e| {
                        error!("[{}] Sink send error: {:?}", peer_addr, e);
                    }));

                    let heartbeat_interval = Interval::new_interval(Duration::from_secs(20))
                        .take_while(move |_| Ok(!needs_pong.swap(true, Ordering::AcqRel)))
                        .for_each(move |_| {
                            let nonce = get_epoch_ms();
                            let msg = Msg {
                                id: u32::max_value(),
                                body: Body::Ping(nonce),
                            };
                            debug!("[{}] Sending ping: {}", peer_addr, nonce);

                            let mut buf = Vec::with_capacity(16);
                            msg.serialize(&mut buf);
                            tx.clone().send(WsMessage::Binary(buf)).then(|_| Ok(()))
                        });

                    let conn = ws_reader.select2(ws_writer).select2(heartbeat_interval);
                    tokio::spawn(conn.then(move |_| {
                        info!("[{}] Connection closed", peer_addr);
                        // Remove block subscriptions if there are any
                        data.sub_pool.remove(peer_addr);
                        Ok(())
                    }));

                    Ok(())
                })
                .map_err(move |e| {
                    error!("[{}] WS accept error = {:?}", peer_addr, e);
                }),
        );
        Ok(())
    }));
}

pub fn process_ws_message(
    data: &ServerData,
    state: &mut WsState,
    msg: WsMessage,
) -> Option<WsMessage> {
    match msg {
        WsMessage::Binary(buf) => {
            state.set_needs_pong(false);

            let mut cur = Cursor::<&[u8]>::new(&buf);
            let msg = match Msg::deserialize(&mut cur) {
                Ok(msg) => {
                    let id = msg.id;
                    if cur.position() != buf.len() as u64 {
                        Msg {
                            id,
                            body: Body::Error(ErrorKind::BytesRemaining),
                        }
                    } else {
                        match handle_protocol_message(data, state, msg) {
                            Some(body) => Msg { id, body },
                            None => return None,
                        }
                    }
                }
                Err(e) => {
                    error!("Error occurred during deserialization: {:?}", e);
                    Msg {
                        id: u32::max_value(),
                        body: Body::Error(ErrorKind::Io),
                    }
                }
            };

            let mut buf = Vec::with_capacity(65536);
            msg.serialize(&mut buf);
            Some(WsMessage::Binary(buf))
        }
        WsMessage::Text(_) => Some(WsMessage::Close(Some(protocol::CloseFrame {
            code: protocol::frame::coding::CloseCode::Unsupported,
            reason: "text is not supported".into(),
        }))),
        _ => None,
    }
}

fn handle_protocol_message(data: &ServerData, state: &mut WsState, msg: Msg) -> Option<Body> {
    match msg.body {
        Body::Error(e) => {
            warn!(
                "[{}] Received error message from client: {:?}",
                state.addr(),
                e
            );
            None
        }
        Body::Request(req) => handle_rpc_request(data, state, msg.id, req),
        Body::Response(res) => {
            warn!(
                "[{}] Unexpected response from client: {:?}",
                state.addr(),
                res
            );
            None
        }
        Body::Ping(nonce) => {
            debug!("[{}] Received ping: {}", state.addr(), nonce);
            Some(Body::Pong(nonce))
        }
        Body::Pong(nonce) => {
            debug!("[{}] Received pong: {}", state.addr(), nonce);
            // We don't need to update the `needs_pong` state as it has already been updated when the message was
            // deserialized
            None
        }
    }
}

fn handle_rpc_request(
    data: &ServerData,
    state: &mut WsState,
    id: u32,
    req: rpc::Request,
) -> Option<Body> {
    Some(match req {
        rpc::Request::Broadcast(tx) => {
            let res = data.minter.push_tx(tx);
            match res {
                Ok(_) => Body::Response(rpc::Response::Broadcast),
                Err(e) => Body::Error(ErrorKind::TxValidation(e)),
            }
        }
        rpc::Request::SetBlockFilter(filter) => {
            if filter.len() > 16 {
                return Some(Body::Error(ErrorKind::InvalidRequest));
            }
            state.filter = Some(filter);
            Body::Response(rpc::Response::SetBlockFilter)
        }
        rpc::Request::ClearBlockFilter => {
            state.filter = None;
            Body::Response(rpc::Response::ClearBlockFilter)
        }
        rpc::Request::Subscribe => {
            data.sub_pool.insert(state.addr(), state.sender());
            Body::Response(rpc::Response::Subscribe)
        }
        rpc::Request::Unsubscribe => {
            data.sub_pool.remove(state.addr());
            Body::Response(rpc::Response::Unsubscribe)
        }
        rpc::Request::GetProperties => {
            let props = data.chain.get_properties();
            Body::Response(rpc::Response::GetProperties(props))
        }
        rpc::Request::GetBlock(height) => match &state.filter {
            Some(filter) => match data.chain.get_filtered_block(height, filter) {
                Some(block) => Body::Response(rpc::Response::GetBlock(block)),
                None => Body::Error(ErrorKind::InvalidHeight),
            },
            None => match data.chain.get_block(height) {
                Some(block) => Body::Response(rpc::Response::GetBlock(FilteredBlock::Block(block))),
                None => Body::Error(ErrorKind::InvalidHeight),
            },
        },
        rpc::Request::GetFullBlock(height) => match data.chain.get_block(height) {
            Some(block) => Body::Response(rpc::Response::GetFullBlock(block)),
            None => Body::Error(ErrorKind::InvalidHeight),
        },
        rpc::Request::GetBlockRange(min_height, max_height) => {
            let range = AsyncBlockRange::try_new(Arc::clone(&data.chain), min_height, max_height);
            match range {
                Some(mut range) => {
                    if let Some(filter) = state.filter() {
                        range.set_filter(Some(filter.clone()));
                    }

                    let peer_addr = state.addr();
                    let tx = state.sender();
                    tokio::spawn(
                        range
                            .map(move |block| {
                                let msg = Msg {
                                    id,
                                    body: Body::Response(rpc::Response::GetBlock(block)),
                                };

                                let mut buf = Vec::with_capacity(65536);
                                msg.serialize(&mut buf);
                                WsMessage::Binary(buf)
                            })
                            .forward(tx.clone().sink_map_err(move |_| {
                                error!("[{}] Failed to send block range update", peer_addr);
                            }))
                            .and_then(move |_| {
                                let msg = Msg {
                                    id,
                                    body: Body::Response(rpc::Response::GetBlockRange),
                                };

                                let mut buf = Vec::with_capacity(32);
                                msg.serialize(&mut buf);
                                tx.send(WsMessage::Binary(buf))
                                    .map(|_sink| ())
                                    .map_err(move |_| {
                                        error!(
                                            "[{}] Failed to send block range finalizer",
                                            peer_addr
                                        );
                                    })
                            }),
                    );

                    return None;
                }
                None => Body::Error(ErrorKind::InvalidHeight),
            }
        }
        rpc::Request::GetAddressInfo(addr) => {
            let res = data.minter.get_addr_info(&addr);
            match res {
                Ok(info) => Body::Response(rpc::Response::GetAddressInfo(info)),
                Err(e) => Body::Error(ErrorKind::TxValidation(e)),
            }
        }
    })
}

pub struct WsState {
    filter: Option<BlockFilter>,
    addr: SocketAddr,
    tx: Sender<WsMessage>,
    needs_pong: Arc<AtomicBool>,
}

impl WsState {
    #[inline]
    pub fn new(addr: SocketAddr, tx: Sender<WsMessage>) -> Self {
        Self {
            filter: None,
            addr,
            tx,
            needs_pong: Arc::new(AtomicBool::new(false)),
        }
    }

    #[inline]
    pub fn needs_pong(&self) -> Arc<AtomicBool> {
        Arc::clone(&self.needs_pong)
    }

    #[inline]
    pub fn set_needs_pong(&self, flag: bool) {
        self.needs_pong.store(flag, Ordering::Release);
    }

    #[inline]
    pub fn addr(&self) -> SocketAddr {
        self.addr
    }

    #[inline]
    pub fn filter(&self) -> Option<&BlockFilter> {
        self.filter.as_ref()
    }

    #[inline]
    pub fn sender(&self) -> Sender<WsMessage> {
        self.tx.clone()
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016, 2018 vergen developers
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

//! Output types
use crate::constants::*;
use chrono::Utc;
use std::collections::HashMap;
use std::env;
use std::error::Error;
use std::process::Command;

//pub mod codegen;
pub mod envvar;

pub fn generate_build_info(
  flags: ConstantsFlags,
) -> Result<HashMap<VergenKey, String>, Box<dyn Error>> {
  let mut build_info = HashMap::new();
  let now = Utc::now();

  if flags.contains(ConstantsFlags::BUILD_TIMESTAMP) {
    build_info.insert(VergenKey::BuildTimestamp, now.to_rfc3339());
  }

  if flags.contains(ConstantsFlags::BUILD_DATE) {
    build_info
      .insert(VergenKey::BuildDate, now.format("%Y-%m-%d").to_string());
  }

  if flags.contains(ConstantsFlags::SHA) {
    let sha = run_command(Command::new("git").args(&["rev-parse", "HEAD"]));
    build_info.insert(VergenKey::Sha, sha);
  }

  if flags.contains(ConstantsFlags::SHA_SHORT) {
    let sha =
      run_command(Command::new("git").args(&["rev-parse", "--short", "HEAD"]));
    build_info.insert(VergenKey::ShortSha, sha);
  }

  if flags.contains(ConstantsFlags::COMMIT_DATE) {
    let commit_date = run_command(Command::new("git").args(&[
      "log",
      "--pretty=format:'%ad'",
      "-n1",
      "--date=short",
    ]));
    build_info.insert(
      VergenKey::CommitDate,
      commit_date.trim_matches('\'').to_string(),
    );
  }

  if flags.contains(ConstantsFlags::TARGET_TRIPLE) {
    let target_triple =
      env::var("TARGET").unwrap_or_else(|_| "UNKNOWN".to_string());
    build_info.insert(VergenKey::TargetTriple, target_triple);
  }

  if flags.contains(ConstantsFlags::SEMVER) {
    let describe = run_command(Command::new("git").args(&["describe"]));

    let semver = if describe.is_empty() {
      env::var("CARGO_PKG_VERSION")?
    } else {
      describe
    };
    build_info.insert(VergenKey::Semver, semver);
  } else if flags.contains(ConstantsFlags::SEMVER_FROM_CARGO_PKG) {
    build_info.insert(VergenKey::Semver, env::var("CARGO_PKG_VERSION")?);
  }

  if flags.contains(ConstantsFlags::SEMVER_LIGHTWEIGHT) {
    let describe =
      run_command(Command::new("git").args(&["describe", "--tags"]));

    let semver = if describe.is_empty() {
      env::var("CARGO_PKG_VERSION")?
    } else {
      describe
    };
    build_info.insert(VergenKey::SemverLightweight, semver);
  }

  Ok(build_info)
}

fn run_command(command: &mut Command) -> String {
  if let Ok(o) = command.output() {
    if o.status.success() {
      return String::from_utf8_lossy(&o.stdout).trim().to_owned();
    }
  }
  "UNKNOWN".to_owned()
}

/// Build information keys.
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
pub enum VergenKey {
  /// The build timestamp. (VERGEN_BUILD_TIMESTAMP)
  BuildTimestamp,
  /// The build date. (VERGEN_BUILD_DATE)
  BuildDate,
  /// The latest commit SHA. (VERGEN_SHA)
  Sha,
  /// The latest commit short SHA. (VERGEN_SHA_SHORT)
  ShortSha,
  /// The commit date. (VERGEN_COMMIT_DATE).
  CommitDate,
  /// The target triple. (VERGEN_TARGET_TRIPLE)
  TargetTriple,
  /// The semver version from the last git tag. (VERGEN_SEMVER)
  Semver,
  /// The semver version from the last git tag, including lightweight.
  /// (VERGEN_SEMVER_LIGHTWEIGHT)
  SemverLightweight,
}

impl VergenKey {
  /// Get the name for the given key.
  pub fn name(self) -> &'static str {
    match self {
      VergenKey::BuildTimestamp => BUILD_TIMESTAMP_NAME,
      VergenKey::BuildDate => BUILD_DATE_NAME,
      VergenKey::Sha => SHA_NAME,
      VergenKey::ShortSha => SHA_SHORT_NAME,
      VergenKey::CommitDate => COMMIT_DATE_NAME,
      VergenKey::TargetTriple => TARGET_TRIPLE_NAME,
      VergenKey::Semver => SEMVER_NAME,
      VergenKey::SemverLightweight => SEMVER_TAGS_NAME,
    }
  }
}

#[cfg(test)]
mod test {}
<commit_msg>vergen: Fallback to the pkg version if .git is not present<commit_after>// Copyright (c) 2016, 2018 vergen developers
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

//! Output types
use crate::constants::*;
use chrono::Utc;
use std::collections::HashMap;
use std::env;
use std::error::Error;
use std::process::Command;

//pub mod codegen;
pub mod envvar;

pub fn generate_build_info(
  flags: ConstantsFlags,
) -> Result<HashMap<VergenKey, String>, Box<dyn Error>> {
  let mut build_info = HashMap::new();
  let now = Utc::now();

  if flags.contains(ConstantsFlags::BUILD_TIMESTAMP) {
    build_info.insert(VergenKey::BuildTimestamp, now.to_rfc3339());
  }

  if flags.contains(ConstantsFlags::BUILD_DATE) {
    build_info
      .insert(VergenKey::BuildDate, now.format("%Y-%m-%d").to_string());
  }

  if flags.contains(ConstantsFlags::SHA) {
    let sha = run_command(Command::new("git").args(&["rev-parse", "HEAD"]));
    build_info.insert(VergenKey::Sha, sha);
  }

  if flags.contains(ConstantsFlags::SHA_SHORT) {
    let sha =
      run_command(Command::new("git").args(&["rev-parse", "--short", "HEAD"]));
    build_info.insert(VergenKey::ShortSha, sha);
  }

  if flags.contains(ConstantsFlags::COMMIT_DATE) {
    let commit_date = run_command(Command::new("git").args(&[
      "log",
      "--pretty=format:'%ad'",
      "-n1",
      "--date=short",
    ]));
    build_info.insert(
      VergenKey::CommitDate,
      commit_date.trim_matches('\'').to_string(),
    );
  }

  if flags.contains(ConstantsFlags::TARGET_TRIPLE) {
    let target_triple =
      env::var("TARGET").unwrap_or_else(|_| "UNKNOWN".to_string());
    build_info.insert(VergenKey::TargetTriple, target_triple);
  }

  if flags.contains(ConstantsFlags::SEMVER) {
    let describe = run_command(Command::new("git").args(&["describe"]));

    let semver = if describe.eq_ignore_ascii_case(&"UNKNOWN") {
      env::var("CARGO_PKG_VERSION")?
    } else {
      describe
    };
    build_info.insert(VergenKey::Semver, semver);
  } else if flags.contains(ConstantsFlags::SEMVER_FROM_CARGO_PKG) {
    build_info.insert(VergenKey::Semver, env::var("CARGO_PKG_VERSION")?);
  }

  if flags.contains(ConstantsFlags::SEMVER_LIGHTWEIGHT) {
    let describe =
      run_command(Command::new("git").args(&["describe", "--tags"]));

    let semver = if describe.eq_ignore_ascii_case(&"UNKNOWN") {
      env::var("CARGO_PKG_VERSION")?
    } else {
      describe
    };
    build_info.insert(VergenKey::SemverLightweight, semver);
  }

  Ok(build_info)
}

fn run_command(command: &mut Command) -> String {
  if let Ok(o) = command.output() {
    if o.status.success() {
      return String::from_utf8_lossy(&o.stdout).trim().to_owned();
    }
  }
  "UNKNOWN".to_owned()
}

/// Build information keys.
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
pub enum VergenKey {
  /// The build timestamp. (VERGEN_BUILD_TIMESTAMP)
  BuildTimestamp,
  /// The build date. (VERGEN_BUILD_DATE)
  BuildDate,
  /// The latest commit SHA. (VERGEN_SHA)
  Sha,
  /// The latest commit short SHA. (VERGEN_SHA_SHORT)
  ShortSha,
  /// The commit date. (VERGEN_COMMIT_DATE).
  CommitDate,
  /// The target triple. (VERGEN_TARGET_TRIPLE)
  TargetTriple,
  /// The semver version from the last git tag. (VERGEN_SEMVER)
  Semver,
  /// The semver version from the last git tag, including lightweight.
  /// (VERGEN_SEMVER_LIGHTWEIGHT)
  SemverLightweight,
}

impl VergenKey {
  /// Get the name for the given key.
  pub fn name(self) -> &'static str {
    match self {
      VergenKey::BuildTimestamp => BUILD_TIMESTAMP_NAME,
      VergenKey::BuildDate => BUILD_DATE_NAME,
      VergenKey::Sha => SHA_NAME,
      VergenKey::ShortSha => SHA_SHORT_NAME,
      VergenKey::CommitDate => COMMIT_DATE_NAME,
      VergenKey::TargetTriple => TARGET_TRIPLE_NAME,
      VergenKey::Semver => SEMVER_NAME,
      VergenKey::SemverLightweight => SEMVER_TAGS_NAME,
    }
  }
}

#[cfg(test)]
mod test {}
<|endoftext|>


<commit_before>//! Records a WAV file (roughly 3 seconds long) using the default input device and config.
//!
//! The input data is recorded to "$CARGO_MANIFEST_DIR/recorded.wav".
use nannou::prelude::*;
use nannou_audio as audio;
use nannou_audio::Buffer;
use std::fs::File;
use std::io::BufWriter;
use std::sync::{Arc, Mutex};
extern crate hound;

type WavWriter = hound::WavWriter<BufWriter<File>>;

fn main() {
    nannou::app(model).run();
}

struct Model {
    stream: audio::Stream<CaptureModel>,
}

struct CaptureModel {
    writer: WavWriter,
}

fn model(app: &App) -> Model {
    app.new_window()
        .key_pressed(key_pressed)
        .view(view)
        .build()
        .unwrap();

    let audio_host = audio::Host::new();

    let spec = hound::WavSpec {
        channels: 1,
        sample_rate: 44100,
        bits_per_sample: 32,
        sample_format: hound::SampleFormat::Float,
    };
    let mut writer = hound::WavWriter::create("recorded.wav", spec).unwrap();
    let capture_model = CaptureModel { writer };

    let stream = audio_host
        .new_input_stream(capture_model)
        .capture(capture_fn)
        .build()
        .unwrap();

    Model { stream }
}

fn capture_fn(audio: &mut CaptureModel, buffer: &Buffer) {
    for frame in buffer.frames() {
        audio
            .writer
            .write_sample(frame[0] as f32)
            .expect("error while writing");
    }
}

fn key_pressed(_app: &App, model: &mut Model, key: Key) {
    match key {
        Key::R => {}
        Key::P => {}
        _ => {}
    }
}

fn view(_app: &App, _model: &Model, frame: Frame) {
    frame.clear(DIMGRAY);
}
<commit_msg>Add more comments<commit_after>//! Records a WAV file (roughly 3 seconds long) using the default input device and config.
//!
//! The input data is recorded to "$CARGO_MANIFEST_DIR/recorded.wav".
use nannou::prelude::*;
use nannou_audio as audio;
use nannou_audio::Buffer;
use std::fs::File;
use std::io::BufWriter;
extern crate hound;

type WavWriter = hound::WavWriter<BufWriter<File>>;

fn main() {
    nannou::app(model).run();
}

struct Model {
    stream: audio::Stream<CaptureModel>,
}

struct CaptureModel {
    writer: WavWriter,
}

fn model(app: &App) -> Model {
    // Create a window to receive key pressed events.
    app.new_window()
        .key_pressed(key_pressed)
        .view(view)
        .build()
        .unwrap();

    // Initialise the audio host so we can spawn an audio stream.
    let audio_host = audio::Host::new();

    // Get specs from device config.
    let spec = hound::WavSpec {
        channels: 1,
        sample_rate: 44100,
        bits_per_sample: 32,
        sample_format: hound::SampleFormat::Float,
    };
    let writer = hound::WavWriter::create("recorded.wav", spec).unwrap();
    let capture_model = CaptureModel { writer };

    let stream = audio_host
        .new_input_stream(capture_model)
        .capture(capture_fn)
        .build()
        .unwrap();

    Model { stream }
}

// A function that captures the audio from the buffer and
// writes it into the the WavWriter.
fn capture_fn(audio: &mut CaptureModel, buffer: &Buffer) {
    // when the program ends, writer is dropped and
    // when writer is dropped, it writes data to disk.
    for frame in buffer.frames() {
        audio
            .writer
            .write_sample(frame[0] as f32)
            .expect("error while writing");
    }
}

fn key_pressed(_app: &App, model: &mut Model, key: Key) {
    match key {
        Key::R => {}
        Key::P => {}
        _ => {}
    }
}

fn view(_app: &App, _model: &Model, frame: Frame) {
    frame.clear(DIMGRAY);
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use std::collections::HashMap;
use std::fs::{File, read_dir};
use std::io::Read;
use std::path::{Path, PathBuf};

pub struct Component {
    pub temperature: f32, // temperature is in celsius
    pub label: String,
    input_file: PathBuf,
    label_file: PathBuf,
}

fn append_files(components: &mut Vec<Component>, folder: &Path) {
    let mut matchings = HashMap::new();
    if let Ok(dir) = read_dir(folder) {
        for entry in dir {
            if let Ok(entry) = entry {
                let entry = entry.path();
                if entry.is_dir() || !entry.file_name().unwrap().to_str().unwrap_or("").starts_with("temp") {
                    continue;
                }
                if let Some(entry) = entry.file_name() {
                    let id = entry.to_str().unwrap()[4..5].parse::<u32>().unwrap();
                    if !matchings.contains_key(&id) {
                        matchings.insert(id, vec!(entry.to_str().unwrap()[6..].to_owned()));
                    } else {
                        matchings.get_mut(&id).unwrap()
                                 .push(entry.to_str().unwrap()[6..].to_owned());
                    }
                }
            }
        }
        for (key, val) in &matchings {
            let mut found_input = None;
            let mut found_label = None;
            for (pos, v) in val.iter().enumerate() {
                match v.as_str() {
                    "input" => { found_input = Some(pos); }
                    "label" => { found_label = Some(pos); }
                    _ => {}
                }
                if found_label.is_some() && found_input.is_some() {
                    let mut p_label = folder.to_path_buf();
                    let mut p_input = folder.to_path_buf();

                    p_label.push(&format!("temp{}_label", key));
                    p_input.push(&format!("temp{}_input", key));
                    components.push(Component::new(p_label.as_path(), p_input.as_path()));
                    break
                }
            }
        }
    }
}

impl Component {
    pub fn get_components() -> Vec<Component> {
        let mut ret = Vec::new();
        if let Ok(dir) = read_dir(&Path::new("/sys/class/hwmon/")) {
            for entry in dir {
                if let Ok(entry) = entry {
                    let entry = entry.path();
                    if !entry.is_dir() || !entry.file_name().unwrap().to_str().unwrap_or("").starts_with("hwmon") {
                        continue;
                    }
                    append_files(&mut ret, &entry);
                }
            }
        }
        ret
    }

    pub fn new(label_path: &Path, input_path: &Path) -> Component {
        let mut c = Component {
            temperature: 0f32,
            label: String::new(),
            input_file: input_path.to_path_buf(),
            label_file: label_path.to_path_buf(),
        };
        c.update();
        c
    }

    pub fn update(&mut self) {
        let mut f = File::open(self.label_file.as_path()).unwrap();
        let mut reader = String::new();
        f.read_to_string(&mut reader).unwrap();
        self.label = reader.replace("\n", "");
        let mut f = File::open(self.input_file.as_path()).unwrap();
        f.read_to_string(&mut reader).unwrap();
        self.temperature = reader.replace("\n", "").parse::<f32>().unwrap() / 1000f32;
    }
}<commit_msg>Reset reader when needed<commit_after>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use std::collections::HashMap;
use std::fs::{File, read_dir};
use std::io::Read;
use std::path::{Path, PathBuf};

pub struct Component {
    pub temperature: f32, // temperature is in celsius
    pub label: String,
    input_file: PathBuf,
    label_file: PathBuf,
}

fn append_files(components: &mut Vec<Component>, folder: &Path) {
    let mut matchings = HashMap::new();
    if let Ok(dir) = read_dir(folder) {
        for entry in dir {
            if let Ok(entry) = entry {
                let entry = entry.path();
                if entry.is_dir() || !entry.file_name().unwrap().to_str().unwrap_or("").starts_with("temp") {
                    continue;
                }
                if let Some(entry) = entry.file_name() {
                    let id = entry.to_str().unwrap()[4..5].parse::<u32>().unwrap();
                    if !matchings.contains_key(&id) {
                        matchings.insert(id, vec!(entry.to_str().unwrap()[6..].to_owned()));
                    } else {
                        matchings.get_mut(&id).unwrap()
                                 .push(entry.to_str().unwrap()[6..].to_owned());
                    }
                }
            }
        }
        for (key, val) in &matchings {
            let mut found_input = None;
            let mut found_label = None;
            for (pos, v) in val.iter().enumerate() {
                match v.as_str() {
                    "input" => { found_input = Some(pos); }
                    "label" => { found_label = Some(pos); }
                    _ => {}
                }
                if found_label.is_some() && found_input.is_some() {
                    let mut p_label = folder.to_path_buf();
                    let mut p_input = folder.to_path_buf();

                    p_label.push(&format!("temp{}_label", key));
                    p_input.push(&format!("temp{}_input", key));
                    components.push(Component::new(p_label.as_path(), p_input.as_path()));
                    break
                }
            }
        }
    }
}

impl Component {
    pub fn get_components() -> Vec<Component> {
        let mut ret = Vec::new();
        if let Ok(dir) = read_dir(&Path::new("/sys/class/hwmon/")) {
            for entry in dir {
                if let Ok(entry) = entry {
                    let entry = entry.path();
                    if !entry.is_dir() || !entry.file_name().unwrap().to_str().unwrap_or("").starts_with("hwmon") {
                        continue;
                    }
                    append_files(&mut ret, &entry);
                }
            }
        }
        ret
    }

    pub fn new(label_path: &Path, input_path: &Path) -> Component {
        let mut c = Component {
            temperature: 0f32,
            label: String::new(),
            input_file: input_path.to_path_buf(),
            label_file: label_path.to_path_buf(),
        };
        c.update();
        c
    }

    pub fn update(&mut self) {
        let mut f = File::open(self.label_file.as_path()).unwrap();
        let mut reader = String::new();
        f.read_to_string(&mut reader).unwrap();
        self.label = reader.replace("\n", "");
        let mut f = File::open(self.input_file.as_path()).unwrap();
        reader = String::new();
        f.read_to_string(&mut reader).unwrap();
        self.temperature = reader.replace("\n", "").parse::<f32>().unwrap() / 1000f32;
    }
}
<|endoftext|>