<commit_before>//! # Functions and types used by generated protobuf code
//!
//! These are not considered to be public API of rust-protobuf,
//! so they can be changed any time (provided compatibility with
//! previously generated code is preserved).

pub use crate::cached_size::CachedSize;
use crate::coded_input_stream::CodedInputStream;
use crate::coded_output_stream::CodedOutputStream;
use crate::enums::Enum;
use crate::error::Result;
pub use crate::lazy::Lazy;
pub use crate::wire_format::WireType;
use crate::zigzag::*;
use crate::EnumOrUnknown;
use crate::Message;
use crate::MessageField;

pub(crate) mod map;
pub(crate) mod repeated;
pub(crate) mod unsorted;
pub use map::compute_map_size;
pub use map::read_map_into;
pub use map::write_map_with_cached_sizes;
pub use repeated::read_repeated_packed_enum_or_unknown_into;
pub use unsorted::read_unknown_or_skip_group;
pub use unsorted::unknown_fields_size;

use crate::varint::encode::encoded_varint64_len;

/// Given `u64` value compute varint encoded length.
pub fn compute_raw_varint64_size(value: u64) -> u64 {
    encoded_varint64_len(value) as u64
}

/// Given `u32` value compute varint encoded length.
pub(crate) fn compute_raw_varint32_size(value: u32) -> u64 {
    compute_raw_varint64_size(value as u64)
}

/// Fixed size integers.
pub trait ProtobufFixed {
    /// Size of this fixed type in bytes.
    const LEN: u32;
}

/// Helper trait implemented by integer types which could be encoded as varint.
pub trait ProtobufVarint {
    /// Size of self when encoded as varint.
    fn len_varint(&self) -> u64;
}

/// Helper trait implemented by integer types which could be encoded as zigzag varint.
pub trait ProtobufVarintZigzag {
    /// Size of self when encoded as zigzag varint.
    fn len_varint_zigzag(&self) -> u64;
}

impl ProtobufVarint for u64 {
    fn len_varint(&self) -> u64 {
        compute_raw_varint64_size(*self)
    }
}

impl ProtobufVarint for u32 {
    fn len_varint(&self) -> u64 {
        (*self as u64).len_varint()
    }
}

impl ProtobufVarint for i64 {
    fn len_varint(&self) -> u64 {
        // same as length of u64
        (*self as u64).len_varint()
    }
}

impl ProtobufVarintZigzag for i64 {
    fn len_varint_zigzag(&self) -> u64 {
        compute_raw_varint64_size(encode_zig_zag_64(*self))
    }
}

impl ProtobufVarint for i32 {
    fn len_varint(&self) -> u64 {
        // sign-extend and then compute
        (*self as i64).len_varint()
    }
}

impl ProtobufVarintZigzag for i32 {
    fn len_varint_zigzag(&self) -> u64 {
        compute_raw_varint32_size(encode_zig_zag_32(*self))
    }
}

impl ProtobufVarint for bool {
    fn len_varint(&self) -> u64 {
        1
    }
}

impl ProtobufFixed for u32 {
    const LEN: u32 = 4;
}

impl ProtobufFixed for i32 {
    const LEN: u32 = 4;
}

impl ProtobufFixed for u64 {
    const LEN: u32 = 8;
}

impl ProtobufFixed for i64 {
    const LEN: u32 = 8;
}

impl ProtobufFixed for f32 {
    const LEN: u32 = 4;
}

impl ProtobufFixed for f64 {
    const LEN: u32 = 8;
}

/// Technically `bool` is not fixed, but it can be considered as fixed
/// for the purpose of encoding.
impl ProtobufFixed for bool {
    const LEN: u32 = 1;
}

/// Size of serialized repeated packed field, excluding length and tag.
pub fn vec_packed_varint_data_size<T: ProtobufVarint>(vec: &[T]) -> u64 {
    vec.iter()
        .map(|v| v.len_varint() as u64)
        .fold(0, |a, i| a + i)
}

/// Size of serialized repeated packed field, excluding length and tag.
pub fn vec_packed_varint_zigzag_data_size<T: ProtobufVarintZigzag>(vec: &[T]) -> u64 {
    vec.iter()
        .map(|v| v.len_varint_zigzag())
        .fold(0, |a, i| a + i)
}

/// Size of serialized repeated packed enum field, excluding length and tag.
pub fn vec_packed_enum_or_unknown_data_size<E: Enum>(vec: &[EnumOrUnknown<E>]) -> u64 {
    vec.iter()
        .map(|e| compute_raw_varint32_size(e.value() as u32))
        .fold(0, |a, i| a + i)
}

/// Size of serialized data with length prefix and tag
pub fn vec_packed_varint_size<T: ProtobufVarint>(field_number: u32, vec: &[T]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_varint_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Size of serialized data with length prefix and tag
pub fn vec_packed_varint_zigzag_size<T: ProtobufVarintZigzag>(field_number: u32, vec: &[T]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_varint_zigzag_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Size of serialized data with length prefix and tag
pub fn vec_packed_enum_or_unknown_size<E: Enum>(
    field_number: u32,
    vec: &[EnumOrUnknown<E>],
) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_enum_or_unknown_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Compute data size of fixed encoding of repeated field data.
pub(crate) fn vec_packed_fixed_data_size<V: ProtobufFixed>(vec: &[V]) -> u64 {
    (vec.len() as u64) * (V::LEN as u64)
}

/// Compute field size (data plus header) of fixed encoding of repeated field.
pub fn vec_packed_fixed_size<V: ProtobufFixed>(field_number: u32, vec: &[V]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_fixed_data_size::<V>(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Compute tag size. Size of tag does not depend on wire type.
pub fn tag_size(field_number: u32) -> u64 {
    encoded_varint64_len((field_number as u64) << 3) as u64
}

/// Size of encoded `sint32` value.
pub fn sint32_size_no_tag(value: i32) -> u64 {
    compute_raw_varint32_size(encode_zig_zag_32(value))
}

/// Size of encoded `sint64` value.
pub fn sint64_size_no_tag(value: i64) -> u64 {
    compute_raw_varint64_size(encode_zig_zag_64(value))
}

/// Size of encoded `int32` value.
pub fn int32_size_no_tag(value: i32) -> u64 {
    value.len_varint()
}

/// Size of encoded `int64` value.
pub fn int64_size_no_tag(value: i64) -> u64 {
    value.len_varint()
}

/// Size of encoded `uint32` value.
pub fn uint32_size_no_tag(value: u32) -> u64 {
    value.len_varint()
}

/// Size of encoded `uint64` value.
pub fn uint64_size_no_tag(value: u64) -> u64 {
    value.len_varint()
}

/// Size of encoded enum field value.
pub fn enum_or_unknown_size_no_tag<E: Enum>(value: EnumOrUnknown<E>) -> u64 {
    value.value().len_varint() as u64
}

/// Size of encoded bytes field.
pub fn bytes_size_no_tag(bytes: &[u8]) -> u64 {
    compute_raw_varint64_size(bytes.len() as u64) + bytes.len() as u64
}

/// Size of encoded string field.
pub fn string_size_no_tag(s: &str) -> u64 {
    bytes_size_no_tag(s.as_bytes())
}

/// Read singular `message` field.
pub fn read_singular_message_into_field<M>(
    is: &mut CodedInputStream,
    target: &mut MessageField<M>,
) -> Result<()>
where
    M: Message,
{
    let mut m = M::new();
    is.merge_message(&mut m)?;
    *target = MessageField::some(m);
    Ok(())
}

/// Write message with field number and length to the stream.
pub fn write_message_field_with_cached_size<M>(
    field_number: u32,
    message: &M,
    os: &mut CodedOutputStream,
) -> Result<()>
where
    M: Message,
{
    os.write_tag(field_number, WireType::LengthDelimited)?;
    os.write_raw_varint32(message.cached_size())?;
    message.write_to_with_cached_sizes(os)
}
<commit_msg>Revert "Dead code"<commit_after>//! # Functions and types used by generated protobuf code
//!
//! These are not considered to be public API of rust-protobuf,
//! so they can be changed any time (provided compatibility with
//! previously generated code is preserved).

pub use crate::cached_size::CachedSize;
use crate::coded_input_stream::CodedInputStream;
use crate::coded_output_stream::CodedOutputStream;
use crate::enums::Enum;
use crate::error::Result;
pub use crate::lazy::Lazy;
pub use crate::wire_format::WireType;
use crate::zigzag::*;
use crate::EnumOrUnknown;
use crate::Message;
use crate::MessageField;

pub(crate) mod map;
pub(crate) mod repeated;
pub(crate) mod unsorted;
pub use map::compute_map_size;
pub use map::read_map_into;
pub use map::write_map_with_cached_sizes;
pub use repeated::read_repeated_packed_enum_or_unknown_into;
pub use unsorted::read_unknown_or_skip_group;
pub use unsorted::unknown_fields_size;

use crate::varint::encode::encoded_varint64_len;

/// Given `u64` value compute varint encoded length.
pub fn compute_raw_varint64_size(value: u64) -> u64 {
    encoded_varint64_len(value) as u64
}

/// Given `u32` value compute varint encoded length.
pub(crate) fn compute_raw_varint32_size(value: u32) -> u64 {
    compute_raw_varint64_size(value as u64)
}

/// Fixed size integers.
pub trait ProtobufFixed {
    /// Size of this fixed type in bytes.
    const LEN: u32;
}

/// Helper trait implemented by integer types which could be encoded as varint.
pub trait ProtobufVarint {
    /// Size of self when encoded as varint.
    fn len_varint(&self) -> u64;
}

/// Helper trait implemented by integer types which could be encoded as zigzag varint.
pub trait ProtobufVarintZigzag {
    /// Size of self when encoded as zigzag varint.
    fn len_varint_zigzag(&self) -> u64;
}

impl ProtobufVarint for u64 {
    fn len_varint(&self) -> u64 {
        compute_raw_varint64_size(*self)
    }
}

impl ProtobufVarint for u32 {
    fn len_varint(&self) -> u64 {
        (*self as u64).len_varint()
    }
}

impl ProtobufVarint for i64 {
    fn len_varint(&self) -> u64 {
        // same as length of u64
        (*self as u64).len_varint()
    }
}

impl ProtobufVarintZigzag for i64 {
    fn len_varint_zigzag(&self) -> u64 {
        compute_raw_varint64_size(encode_zig_zag_64(*self))
    }
}

impl ProtobufVarint for i32 {
    fn len_varint(&self) -> u64 {
        // sign-extend and then compute
        (*self as i64).len_varint()
    }
}

impl ProtobufVarintZigzag for i32 {
    fn len_varint_zigzag(&self) -> u64 {
        compute_raw_varint32_size(encode_zig_zag_32(*self))
    }
}

impl ProtobufVarint for bool {
    fn len_varint(&self) -> u64 {
        1
    }
}

impl ProtobufFixed for u32 {
    const LEN: u32 = 4;
}

impl ProtobufFixed for i32 {
    const LEN: u32 = 4;
}

impl ProtobufFixed for u64 {
    const LEN: u32 = 8;
}

impl ProtobufFixed for i64 {
    const LEN: u32 = 8;
}

impl ProtobufFixed for f32 {
    const LEN: u32 = 4;
}

impl ProtobufFixed for f64 {
    const LEN: u32 = 8;
}

/// Technically `bool` is not fixed, but it can be considered as fixed
/// for the purpose of encoding.
impl ProtobufFixed for bool {
    const LEN: u32 = 1;
}

/// Size of serialized repeated packed field, excluding length and tag.
pub fn vec_packed_varint_data_size<T: ProtobufVarint>(vec: &[T]) -> u64 {
    vec.iter()
        .map(|v| v.len_varint() as u64)
        .fold(0, |a, i| a + i)
}

/// Size of serialized repeated packed field, excluding length and tag.
pub fn vec_packed_varint_zigzag_data_size<T: ProtobufVarintZigzag>(vec: &[T]) -> u64 {
    vec.iter()
        .map(|v| v.len_varint_zigzag())
        .fold(0, |a, i| a + i)
}

/// Size of serialized repeated packed enum field, excluding length and tag.
pub fn vec_packed_enum_or_unknown_data_size<E: Enum>(vec: &[EnumOrUnknown<E>]) -> u64 {
    vec.iter()
        .map(|e| compute_raw_varint32_size(e.value() as u32))
        .fold(0, |a, i| a + i)
}

/// Size of serialized data with length prefix and tag
pub fn vec_packed_varint_size<T: ProtobufVarint>(field_number: u32, vec: &[T]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_varint_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Size of serialized data with length prefix and tag
pub fn vec_packed_varint_zigzag_size<T: ProtobufVarintZigzag>(field_number: u32, vec: &[T]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_varint_zigzag_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Size of serialized data with length prefix and tag
pub fn vec_packed_enum_or_unknown_size<E: Enum>(
    field_number: u32,
    vec: &[EnumOrUnknown<E>],
) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_enum_or_unknown_data_size(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Compute data size of fixed encoding of repeated field data.
pub(crate) fn vec_packed_fixed_data_size<V: ProtobufFixed>(vec: &[V]) -> u64 {
    (vec.len() as u64) * (V::LEN as u64)
}

/// Compute field size (data plus header) of fixed encoding of repeated field.
pub fn vec_packed_fixed_size<V: ProtobufFixed>(field_number: u32, vec: &[V]) -> u64 {
    if vec.is_empty() {
        0
    } else {
        let data_size = vec_packed_fixed_data_size::<V>(vec);
        tag_size(field_number) + data_size.len_varint() + data_size
    }
}

/// Compute tag size. Size of tag does not depend on wire type.
pub fn tag_size(field_number: u32) -> u64 {
    encoded_varint64_len((field_number as u64) << 3) as u64
}

/// Size of encoded `sint32` value.
pub fn sint32_size_no_tag(value: i32) -> u64 {
    compute_raw_varint32_size(encode_zig_zag_32(value))
}

/// Size of encoded `sint64` value.
pub fn sint64_size_no_tag(value: i64) -> u64 {
    compute_raw_varint64_size(encode_zig_zag_64(value))
}

/// Size of encoded `int32` value.
pub fn int32_size_no_tag(value: i32) -> u64 {
    value.len_varint()
}

/// Size of encoded `int64` value.
pub fn int64_size_no_tag(value: i64) -> u64 {
    value.len_varint()
}

/// Size of encoded `uint32` value.
pub fn uint32_size_no_tag(value: u32) -> u64 {
    value.len_varint()
}

/// Size of encoded `uint64` value.
pub fn uint64_size_no_tag(value: u64) -> u64 {
    value.len_varint()
}

/// Integer value size when encoded as specified wire type.
pub fn varint_size_no_tag<T: ProtobufVarint>(value: T) -> u64 {
    value.len_varint()
}

/// Size of encoded enum field value.
pub fn enum_or_unknown_size_no_tag<E: Enum>(value: EnumOrUnknown<E>) -> u64 {
    value.value().len_varint() as u64
}

/// Size of encoded bytes field.
pub fn bytes_size_no_tag(bytes: &[u8]) -> u64 {
    compute_raw_varint64_size(bytes.len() as u64) + bytes.len() as u64
}

/// Size of encoded string field.
pub fn string_size_no_tag(s: &str) -> u64 {
    bytes_size_no_tag(s.as_bytes())
}

/// Read singular `message` field.
pub fn read_singular_message_into_field<M>(
    is: &mut CodedInputStream,
    target: &mut MessageField<M>,
) -> Result<()>
where
    M: Message,
{
    let mut m = M::new();
    is.merge_message(&mut m)?;
    *target = MessageField::some(m);
    Ok(())
}

/// Write message with field number and length to the stream.
pub fn write_message_field_with_cached_size<M>(
    field_number: u32,
    message: &M,
    os: &mut CodedOutputStream,
) -> Result<()>
where
    M: Message,
{
    os.write_tag(field_number, WireType::LengthDelimited)?;
    os.write_raw_varint32(message.cached_size())?;
    message.write_to_with_cached_sizes(os)
}
<|endoftext|>


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

// High-level interface to CSS selector matching.

use css::node_style::StyledNode;
use layout::incremental;
use layout::util::LayoutDataAccess;
use layout::wrapper::LayoutNode;

use extra::arc::{Arc, RWArc};
use std::cast;
use std::cell::Cell;
use std::comm;
use std::libc::uintptr_t;
use std::rt;
use std::task;
use std::vec;
use style::{TNode, Stylist, cascade};
use style::{Before, After};

pub trait MatchMethods {
    fn match_node(&self, stylist: &Stylist);
    fn match_subtree(&self, stylist: RWArc<Stylist>);

    fn cascade_before_node(&self, parent: Option<LayoutNode>);
    fn cascade_node(&self, parent: Option<LayoutNode>);
    fn cascade_after_node(&self, parent: Option<LayoutNode>);
    fn cascade_subtree(&self, parent: Option<LayoutNode>);
}

impl<'self> MatchMethods for LayoutNode<'self> {
    fn match_node(&self, stylist: &Stylist) {
        let style_attribute = do self.with_element |element| {
            match *element.style_attribute() {
                None => None,
                Some(ref style_attribute) => Some(style_attribute)
            }
        };

        match *self.mutate_layout_data().ptr {
            Some(ref mut layout_data) => {
                layout_data.applicable_declarations = stylist.get_applicable_declarations(
                    self, style_attribute, None);
                layout_data.before_applicable_declarations = stylist.get_applicable_declarations(
                    self, None, Some(Before));
                layout_data.after_applicable_declarations = stylist.get_applicable_declarations(
                    self, None, Some(After));
            }
            None => fail!("no layout data")
        }
    }
    fn match_subtree(&self, stylist: RWArc<Stylist>) {
        let num_tasks = rt::default_sched_threads() * 2;
        let mut node_count = 0;
        let mut nodes_per_task = vec::from_elem(num_tasks, ~[]);

        for node in self.traverse_preorder() {
            if node.is_element() {
                nodes_per_task[node_count % num_tasks].push(node);
                node_count += 1;
            }
        }

        let (port, chan) = comm::stream();
        let chan = comm::SharedChan::new(chan);
        let mut num_spawned = 0;

        for nodes in nodes_per_task.move_iter() {
            if nodes.len() > 0 {
                let chan = chan.clone();
                let stylist = stylist.clone();

                // FIXME(pcwalton): This transmute is to work around the fact that we have no
                // mechanism for safe fork/join parallelism. If we had such a thing, then we could
                // close over the lifetime-bounded `LayoutNode`. But we can't, so we force it with
                // a transmute.
                let evil: uintptr_t = unsafe {
                    cast::transmute(nodes)
                };

                do task::spawn_with((evil, stylist)) |(evil, stylist)| {
                    let nodes: ~[LayoutNode] = unsafe {
                        cast::transmute(evil)
                    };

                    let nodes = Cell::new(nodes);
                    do stylist.read |stylist| {
                        let nodes = nodes.take();
                        for node in nodes.iter() {
                            node.match_node(stylist);
                        }
                    }
                    chan.send(());
                }
                num_spawned += 1;
            }
        }
        for _ in range(0, num_spawned) {
            port.recv();
        }
    }

    fn cascade_before_node(&self, parent: Option<LayoutNode>) {
        let parent_style = match parent {
            Some(ref parent) => Some(parent.style()),
            None => None
        };

        let computed_values = unsafe {
            Arc::new(cascade(self.borrow_layout_data_unchecked()
                                 .as_ref()
                                 .unwrap()
                                 .before_applicable_declarations,
                             parent_style.map(|parent_style| parent_style.get())))
        };

        match *self.mutate_layout_data().ptr {
            None => fail!("no layout data"),
            Some(ref mut layout_data) => {
                let style = &mut layout_data.before_style;
                match *style {
                    None => (),
                    Some(ref previous_style) => {
                        layout_data.restyle_damage =
                            Some(incremental::compute_damage(previous_style.get(),
                                                             computed_values.get()).to_int())
                    }
                }
                *style = Some(computed_values)
            }
        }
    }

    fn cascade_node(&self, parent: Option<LayoutNode>) {
        let parent_style = match parent {
            Some(ref parent) => Some(parent.style()),
            None => None
        };

        let computed_values = unsafe {
            Arc::new(cascade(self.borrow_layout_data_unchecked()
                                 .as_ref()
                                 .unwrap()
                                 .applicable_declarations,
                             parent_style.map(|parent_style| parent_style.get())))
        };

        match *self.mutate_layout_data().ptr {
            None => fail!("no layout data"),
            Some(ref mut layout_data) => {
                let style = &mut layout_data.style;
                match *style {
                    None => (),
                    Some(ref previous_style) => {
                        layout_data.restyle_damage =
                            Some(incremental::compute_damage(previous_style.get(),
                                                             computed_values.get()).to_int())
                    }
                }
                *style = Some(computed_values)
            }
        }
    }

    fn cascade_after_node(&self, parent: Option<LayoutNode>) {
        let parent_style = match parent {
            Some(ref parent) => Some(parent.style()),
            None => None
        };

        let computed_values = unsafe {
            Arc::new(cascade(self.borrow_layout_data_unchecked()
                                 .as_ref()
                                 .unwrap()
                                 .after_applicable_declarations,
                             parent_style.map(|parent_style| parent_style.get())))
        };

        match *self.mutate_layout_data().ptr {
            None => fail!("no layout data"),
            Some(ref mut layout_data) => {
                let style = &mut layout_data.after_style;
                match *style {
                    None => (),
                    Some(ref previous_style) => {
                        layout_data.restyle_damage =
                            Some(incremental::compute_damage(previous_style.get(),
                                                             computed_values.get()).to_int())
                    }
                }
                *style = Some(computed_values)
            }
        }
    }

    fn cascade_subtree(&self, parent: Option<LayoutNode>) {
        unsafe {
            if self.borrow_layout_data_unchecked().as_ref().unwrap().before_applicable_declarations.len() > 0 {
                self.cascade_before_node(parent);
            }
        }
        self.cascade_node(parent);
        unsafe {
            if self.borrow_layout_data_unchecked().as_ref().unwrap().after_applicable_declarations.len() > 0 {
                self.cascade_after_node(parent);
            }
        }

        for kid in self.children() {
            if kid.is_element() {
                kid.cascade_subtree(Some(*self));
            }
        }
    }
}
<commit_msg>De-duplicate some redundant code with a macro.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// High-level interface to CSS selector matching.

use css::node_style::StyledNode;
use layout::incremental;
use layout::util::LayoutDataAccess;
use layout::wrapper::LayoutNode;

use extra::arc::{Arc, RWArc};
use std::cast;
use std::cell::Cell;
use std::comm;
use std::libc::uintptr_t;
use std::rt;
use std::task;
use std::vec;
use style::{TNode, Stylist, cascade};
use style::{Before, After};

pub trait MatchMethods {
    fn match_node(&self, stylist: &Stylist);
    fn match_subtree(&self, stylist: RWArc<Stylist>);

    fn cascade_subtree(&self, parent: Option<LayoutNode>);
}

impl<'self> MatchMethods for LayoutNode<'self> {
    fn match_node(&self, stylist: &Stylist) {
        let style_attribute = do self.with_element |element| {
            match *element.style_attribute() {
                None => None,
                Some(ref style_attribute) => Some(style_attribute)
            }
        };

        match *self.mutate_layout_data().ptr {
            Some(ref mut layout_data) => {
                layout_data.applicable_declarations = stylist.get_applicable_declarations(
                    self, style_attribute, None);
                layout_data.before_applicable_declarations = stylist.get_applicable_declarations(
                    self, None, Some(Before));
                layout_data.after_applicable_declarations = stylist.get_applicable_declarations(
                    self, None, Some(After));
            }
            None => fail!("no layout data")
        }
    }
    fn match_subtree(&self, stylist: RWArc<Stylist>) {
        let num_tasks = rt::default_sched_threads() * 2;
        let mut node_count = 0;
        let mut nodes_per_task = vec::from_elem(num_tasks, ~[]);

        for node in self.traverse_preorder() {
            if node.is_element() {
                nodes_per_task[node_count % num_tasks].push(node);
                node_count += 1;
            }
        }

        let (port, chan) = comm::stream();
        let chan = comm::SharedChan::new(chan);
        let mut num_spawned = 0;

        for nodes in nodes_per_task.move_iter() {
            if nodes.len() > 0 {
                let chan = chan.clone();
                let stylist = stylist.clone();

                // FIXME(pcwalton): This transmute is to work around the fact that we have no
                // mechanism for safe fork/join parallelism. If we had such a thing, then we could
                // close over the lifetime-bounded `LayoutNode`. But we can't, so we force it with
                // a transmute.
                let evil: uintptr_t = unsafe {
                    cast::transmute(nodes)
                };

                do task::spawn_with((evil, stylist)) |(evil, stylist)| {
                    let nodes: ~[LayoutNode] = unsafe {
                        cast::transmute(evil)
                    };

                    let nodes = Cell::new(nodes);
                    do stylist.read |stylist| {
                        let nodes = nodes.take();
                        for node in nodes.iter() {
                            node.match_node(stylist);
                        }
                    }
                    chan.send(());
                }
                num_spawned += 1;
            }
        }
        for _ in range(0, num_spawned) {
            port.recv();
        }
    }

    fn cascade_subtree(&self, parent: Option<LayoutNode>) {
        let layout_data = unsafe {
            self.borrow_layout_data_unchecked().as_ref().unwrap()
        };
        macro_rules! cascade_node(
            ($applicable_declarations: ident, $style: ident) => {{
                let parent_style = match parent {
                    Some(ref parent) => Some(parent.style()),
                    None => None
                };

                let computed_values = Arc::new(cascade(
                    layout_data.$applicable_declarations,
                    parent_style.map(|parent_style| parent_style.get())));

                match *self.mutate_layout_data().ptr {
                    None => fail!("no layout data"),
                    Some(ref mut layout_data) => {
                        let style = &mut layout_data.$style;
                        match *style {
                            None => (),
                            Some(ref previous_style) => {
                                layout_data.restyle_damage = Some(incremental::compute_damage(
                                    previous_style.get(), computed_values.get()).to_int())
                            }
                        }
                        *style = Some(computed_values)
                    }
                }
            }}
        );

        unsafe {
            if self.borrow_layout_data_unchecked().as_ref().unwrap().before_applicable_declarations.len() > 0 {
                cascade_node!(before_applicable_declarations, before_style);
            }
        }
        cascade_node!(applicable_declarations, style);
        unsafe {
            if self.borrow_layout_data_unchecked().as_ref().unwrap().after_applicable_declarations.len() > 0 {
                cascade_node!(after_applicable_declarations, after_style);
            }
        }

        for kid in self.children() {
            if kid.is_element() {
                kid.cascade_subtree(Some(*self));
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Refactored the movement loop out of a foreach to satisfy the borrow checker<commit_after><|endoftext|>


<commit_before>use std::io;
use std::fmt::Display;
use std::net::SocketAddr;
use std::time::{SystemTime, Duration};
use std::cmp::Ordering;

use mio;

use super::messages::RawMessage;

mod network;
mod connection;
#[cfg(test)]
mod tests;

pub use self::network::{Network, NetworkConfiguration, PeerId, EventSet};

pub type EventsConfiguration = mio::EventLoopConfig;

pub type EventLoop<H> = mio::EventLoop<MioAdapter<H>>;

#[derive(Debug)]
pub enum Event {
    Incoming(RawMessage),
    Connected(SocketAddr),
    Disconnected(SocketAddr),
    Error(io::Error),
}

#[derive(Debug)]
pub enum InternalEvent<A: Send, T: Send> {
    Node(Event),
    Application(A),
    Invoke(Invoke<T>),
}

#[derive(Debug)]
pub enum InternalTimeout {
    Reconnect(SocketAddr, u64),
}

#[derive(Debug)]
pub enum Timeout<N: Send> {
    Node(N),
    Internal(InternalTimeout),
}

#[derive(Debug)]
pub enum Invoke<T: Send> {
    SendTo(SocketAddr, RawMessage),
    Connect(SocketAddr),
    AddTimeout(T, SystemTime),
}

pub trait EventHandler {
    type Timeout: Send;
    type ApplicationEvent: Send;

    fn handle_event(&mut self, event: Event);
    fn handle_timeout(&mut self, timeout: Self::Timeout);
    fn handle_application_event(&mut self, event: Self::ApplicationEvent);
}

pub trait Channel: Sync + Send + Clone {
    type ApplicationEvent: Send;
    type Timeout: Send;

    fn get_time(&self) -> SystemTime;
    fn address(&self) -> SocketAddr;

    fn post_event(&self, msg: Self::ApplicationEvent) -> Result<()>;
    fn send_to(&mut self, address: &SocketAddr, message: RawMessage);
    fn connect(&mut self, address: &SocketAddr);
    fn add_timeout(&mut self, timeout: Self::Timeout, time: SystemTime);
}

pub trait Reactor<H: EventHandler> {
    type Channel: Channel<ApplicationEvent = H::ApplicationEvent, Timeout = H::Timeout>;

    fn bind(&mut self) -> ::std::io::Result<()>;
    fn run(&mut self) -> ::std::io::Result<()>;
    fn run_once(&mut self, timeout: Option<usize>) -> ::std::io::Result<()>;
    fn get_time(&self) -> SystemTime;
    fn channel(&self) -> Self::Channel;
}

pub struct MioAdapter<H: EventHandler> {
    network: Network,
    handler: H,
}

pub struct Events<H: EventHandler> {
    inner: MioAdapter<H>,
    event_loop: EventLoop<H>,
}

pub struct MioChannel<E: Send, T: Send> {
    address: SocketAddr,
    inner: mio::Sender<InternalEvent<E, T>>,
}

impl<E: Send, T: Send> MioChannel<E, T> {
    pub fn new(addr: SocketAddr, inner: mio::Sender<InternalEvent<E, T>>) -> MioChannel<E, T> {
        MioChannel {
            address: addr,
            inner: inner.clone(),
        }
    }
}

impl<E: Send, T: Send> Clone for MioChannel<E, T> {
    fn clone(&self) -> MioChannel<E, T> {
        MioChannel {
            address: self.address,
            inner: self.inner.clone(),
        }
    }
}

impl<E: Send, T: Send> Channel for MioChannel<E, T> {
    type ApplicationEvent = E;
    type Timeout = T;

    fn address(&self) -> SocketAddr {
        self.address
    }

    fn get_time(&self) -> SystemTime {
        SystemTime::now()
    }

    fn post_event(&self, event: Self::ApplicationEvent) -> Result<()> {
        let msg = InternalEvent::Application(event);
        self.inner
            .send(msg)
            .map_err(|e| {
                error!("An error occured: {}", e);
                Error::new(e.to_string())
            })
    }

    fn send_to(&mut self, address: &SocketAddr, message: RawMessage) {
        self.inner
            .send(InternalEvent::Invoke(Invoke::SendTo(*address, message)))
            .log_error("Unable to send to");
    }

    fn connect(&mut self, address: &SocketAddr) {
        self.inner
            .send(InternalEvent::Invoke(Invoke::Connect(*address)))
            .log_error("Unable to connect");
    }

    fn add_timeout(&mut self, timeout: Self::Timeout, time: SystemTime) {
        self.inner
            .send(InternalEvent::Invoke(Invoke::AddTimeout(timeout, time)))
            .log_error("Unable to add timeout");
    }
}

// TODO think about more ergonomic design with ChannelFactory or other solution

impl<H: EventHandler> Events<H> {
    pub fn new(network: Network, handler: H) -> io::Result<Events<H>> {
        let event_loop = EventLoop::<H>::new()?;
        let events = Events {
            inner: MioAdapter {
                network: network,
                handler: handler,
            },
            event_loop: event_loop,
        };
        Ok(events)
    }

    pub fn with_event_loop(network: Network, handler: H, event_loop: EventLoop<H>) -> Events<H> {
        Events {
            inner: MioAdapter {
                network: network,
                handler: handler,
            },
            event_loop: event_loop,
        }
    }

    pub fn handler(&self) -> &H {
        &self.inner.handler
    }

    pub fn handler_mut(&mut self) -> &mut H {
        &mut self.inner.handler
    }
}

impl<H: EventHandler> MioAdapter<H> {
    fn handle_invoke(&mut self, event_loop: &mut EventLoop<H>, method: Invoke<H::Timeout>) {
        match method {
            Invoke::Connect(address) => self.handle_connect(event_loop, &address),
            Invoke::SendTo(address, message) => self.handle_send_to(event_loop, &address, message),
            Invoke::AddTimeout(timeout, time) => self.handle_add_timeout(event_loop, timeout, time),
        }
    }

    fn handle_send_to(&mut self,
                      event_loop: &mut EventLoop<H>,
                      address: &SocketAddr,
                      message: RawMessage) {
        if self.network.is_connected(address) {
            if let Err(e) = self.network.send_to(event_loop, address, message) {
                error!("{}: An error during send_to occured {:?}",
                       self.network.address(),
                       e);
                self.handler.handle_event(Event::Disconnected(*address));
            }
        } else {
            warn!("{}: Unable to send message to {}, connection does not established",
                  self.network.address(),
                  address);
        }
    }

    fn handle_connect(&mut self, event_loop: &mut EventLoop<H>, address: &SocketAddr) {
        self.network
            .connect(event_loop, address)
            .log_error(format!("Unable to connect with {}", address));
    }

    fn handle_add_timeout(&mut self,
                          event_loop: &mut EventLoop<H>,
                          timeout: H::Timeout,
                          time: SystemTime) {
        let now = SystemTime::now();
        match time.cmp(&now) {
            Ordering::Less | Ordering::Equal => self.handler.handle_timeout(timeout),
            Ordering::Greater => {
                let duration = time.duration_since(now).unwrap();
                // TODO: use mio::Timeout
                event_loop.timeout_ms(Timeout::Node(timeout), num_milliseconds(&duration))
                    .map(|_| ())
                    .map_err(|x| format!("{:?}", x))
                    .log_error("Unable to add timeout to event loop");
            }
        }
    }
}

impl<H: EventHandler> mio::Handler for MioAdapter<H> {
    type Timeout = Timeout<H::Timeout>;
    type Message = InternalEvent<H::ApplicationEvent, H::Timeout>;

    fn ready(&mut self, event_loop: &mut EventLoop<H>, token: mio::Token, events: mio::EventSet) {
        self.network
            .io(event_loop, &mut self.handler, token, events)
            .log_error(format!("{}", self.network.address()));
    }

    fn notify(&mut self, event_loop: &mut EventLoop<H>, msg: Self::Message) {
        match msg {
            InternalEvent::Node(event) => self.handler.handle_event(event),
            InternalEvent::Invoke(args) => self.handle_invoke(event_loop, args),
            InternalEvent::Application(event) => self.handler.handle_application_event(event),
        }
    }

    fn timeout(&mut self, event_loop: &mut EventLoop<H>, timeout: Self::Timeout) {
        match timeout {
            Timeout::Node(timeout) => {
                self.handler.handle_timeout(timeout);
            }
            Timeout::Internal(timeout) => {
                self.network.handle_timeout(event_loop, timeout);
            }
        }
    }

    // TODO think about interrupted handlers
    // fn interrupted(&mut self, _: &mut EventLoop) {
    //     self.push(Event::Terminate);
    // }

    fn tick(&mut self, event_loop: &mut EventLoop<H>) {
        self.network.tick(event_loop);
    }
}

impl<H: EventHandler> Reactor<H> for Events<H> {
    type Channel = MioChannel<H::ApplicationEvent, H::Timeout>;

    fn bind(&mut self) -> ::std::io::Result<()> {
        self.inner.network.bind(&mut self.event_loop)
    }
    fn run(&mut self) -> ::std::io::Result<()> {
        self.event_loop.run(&mut self.inner)
    }
    fn run_once(&mut self, timeout: Option<usize>) -> ::std::io::Result<()> {
        self.event_loop.run_once(&mut self.inner, timeout)
    }
    fn get_time(&self) -> SystemTime {
        SystemTime::now()
    }
    fn channel(&self) -> MioChannel<H::ApplicationEvent, H::Timeout> {
        MioChannel {
            inner: self.event_loop.channel(),
            address: *self.inner.network.address(),
        }
    }
}

trait LogError {
    fn log_error<S: AsRef<str>>(self, msg: S);
}

impl<E> LogError for ::std::result::Result<(), E>
    where E: Display
{
    fn log_error<S: AsRef<str>>(self, msg: S) {
        if let Err(error) = self {
            error!("{}, an error occured: {}", msg.as_ref(), error);
        }
    }
}

#[derive(Debug)]
pub struct Error {
    message: String,
}

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

impl Error {
    pub fn new<T: Into<String>>(message: T) -> Error {
        Error { message: message.into() }
    }
}

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

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

fn num_milliseconds(duration: &Duration) -> u64 {
    const MILLIS_PER_SEC: u64 = 1000;
    const NANOS_PER_MILLI: u32 = 1000_000;

    let secs_part = duration.as_secs() * MILLIS_PER_SEC;
    let nanos_part = duration.subsec_nanos() / NANOS_PER_MILLI;
    secs_part + nanos_part as u64
}
<commit_msg>Refactor handle_add_timeout function (time comparison)<commit_after>use std::io;
use std::fmt::Display;
use std::net::SocketAddr;
use std::time::{SystemTime, Duration};
use std::cmp::Ordering;

use mio;

use super::messages::RawMessage;

mod network;
mod connection;
#[cfg(test)]
mod tests;

pub use self::network::{Network, NetworkConfiguration, PeerId, EventSet};

pub type EventsConfiguration = mio::EventLoopConfig;

pub type EventLoop<H> = mio::EventLoop<MioAdapter<H>>;

#[derive(Debug)]
pub enum Event {
    Incoming(RawMessage),
    Connected(SocketAddr),
    Disconnected(SocketAddr),
    Error(io::Error),
}

#[derive(Debug)]
pub enum InternalEvent<A: Send, T: Send> {
    Node(Event),
    Application(A),
    Invoke(Invoke<T>),
}

#[derive(Debug)]
pub enum InternalTimeout {
    Reconnect(SocketAddr, u64),
}

#[derive(Debug)]
pub enum Timeout<N: Send> {
    Node(N),
    Internal(InternalTimeout),
}

#[derive(Debug)]
pub enum Invoke<T: Send> {
    SendTo(SocketAddr, RawMessage),
    Connect(SocketAddr),
    AddTimeout(T, SystemTime),
}

pub trait EventHandler {
    type Timeout: Send;
    type ApplicationEvent: Send;

    fn handle_event(&mut self, event: Event);
    fn handle_timeout(&mut self, timeout: Self::Timeout);
    fn handle_application_event(&mut self, event: Self::ApplicationEvent);
}

pub trait Channel: Sync + Send + Clone {
    type ApplicationEvent: Send;
    type Timeout: Send;

    fn get_time(&self) -> SystemTime;
    fn address(&self) -> SocketAddr;

    fn post_event(&self, msg: Self::ApplicationEvent) -> Result<()>;
    fn send_to(&mut self, address: &SocketAddr, message: RawMessage);
    fn connect(&mut self, address: &SocketAddr);
    fn add_timeout(&mut self, timeout: Self::Timeout, time: SystemTime);
}

pub trait Reactor<H: EventHandler> {
    type Channel: Channel<ApplicationEvent = H::ApplicationEvent, Timeout = H::Timeout>;

    fn bind(&mut self) -> ::std::io::Result<()>;
    fn run(&mut self) -> ::std::io::Result<()>;
    fn run_once(&mut self, timeout: Option<usize>) -> ::std::io::Result<()>;
    fn get_time(&self) -> SystemTime;
    fn channel(&self) -> Self::Channel;
}

pub struct MioAdapter<H: EventHandler> {
    network: Network,
    handler: H,
}

pub struct Events<H: EventHandler> {
    inner: MioAdapter<H>,
    event_loop: EventLoop<H>,
}

pub struct MioChannel<E: Send, T: Send> {
    address: SocketAddr,
    inner: mio::Sender<InternalEvent<E, T>>,
}

impl<E: Send, T: Send> MioChannel<E, T> {
    pub fn new(addr: SocketAddr, inner: mio::Sender<InternalEvent<E, T>>) -> MioChannel<E, T> {
        MioChannel {
            address: addr,
            inner: inner.clone(),
        }
    }
}

impl<E: Send, T: Send> Clone for MioChannel<E, T> {
    fn clone(&self) -> MioChannel<E, T> {
        MioChannel {
            address: self.address,
            inner: self.inner.clone(),
        }
    }
}

impl<E: Send, T: Send> Channel for MioChannel<E, T> {
    type ApplicationEvent = E;
    type Timeout = T;

    fn address(&self) -> SocketAddr {
        self.address
    }

    fn get_time(&self) -> SystemTime {
        SystemTime::now()
    }

    fn post_event(&self, event: Self::ApplicationEvent) -> Result<()> {
        let msg = InternalEvent::Application(event);
        self.inner
            .send(msg)
            .map_err(|e| {
                error!("An error occured: {}", e);
                Error::new(e.to_string())
            })
    }

    fn send_to(&mut self, address: &SocketAddr, message: RawMessage) {
        self.inner
            .send(InternalEvent::Invoke(Invoke::SendTo(*address, message)))
            .log_error("Unable to send to");
    }

    fn connect(&mut self, address: &SocketAddr) {
        self.inner
            .send(InternalEvent::Invoke(Invoke::Connect(*address)))
            .log_error("Unable to connect");
    }

    fn add_timeout(&mut self, timeout: Self::Timeout, time: SystemTime) {
        self.inner
            .send(InternalEvent::Invoke(Invoke::AddTimeout(timeout, time)))
            .log_error("Unable to add timeout");
    }
}

// TODO think about more ergonomic design with ChannelFactory or other solution

impl<H: EventHandler> Events<H> {
    pub fn new(network: Network, handler: H) -> io::Result<Events<H>> {
        let event_loop = EventLoop::<H>::new()?;
        let events = Events {
            inner: MioAdapter {
                network: network,
                handler: handler,
            },
            event_loop: event_loop,
        };
        Ok(events)
    }

    pub fn with_event_loop(network: Network, handler: H, event_loop: EventLoop<H>) -> Events<H> {
        Events {
            inner: MioAdapter {
                network: network,
                handler: handler,
            },
            event_loop: event_loop,
        }
    }

    pub fn handler(&self) -> &H {
        &self.inner.handler
    }

    pub fn handler_mut(&mut self) -> &mut H {
        &mut self.inner.handler
    }
}

impl<H: EventHandler> MioAdapter<H> {
    fn handle_invoke(&mut self, event_loop: &mut EventLoop<H>, method: Invoke<H::Timeout>) {
        match method {
            Invoke::Connect(address) => self.handle_connect(event_loop, &address),
            Invoke::SendTo(address, message) => self.handle_send_to(event_loop, &address, message),
            Invoke::AddTimeout(timeout, time) => self.handle_add_timeout(event_loop, timeout, time),
        }
    }

    fn handle_send_to(&mut self,
                      event_loop: &mut EventLoop<H>,
                      address: &SocketAddr,
                      message: RawMessage) {
        if self.network.is_connected(address) {
            if let Err(e) = self.network.send_to(event_loop, address, message) {
                error!("{}: An error during send_to occured {:?}",
                       self.network.address(),
                       e);
                self.handler.handle_event(Event::Disconnected(*address));
            }
        } else {
            warn!("{}: Unable to send message to {}, connection does not established",
                  self.network.address(),
                  address);
        }
    }

    fn handle_connect(&mut self, event_loop: &mut EventLoop<H>, address: &SocketAddr) {
        self.network
            .connect(event_loop, address)
            .log_error(format!("Unable to connect with {}", address));
    }

    fn handle_add_timeout(&mut self,
                          event_loop: &mut EventLoop<H>,
                          timeout: H::Timeout,
                          time: SystemTime) {
        match time.duration_since(SystemTime::now()) {
            Ok(duration) =>
                event_loop.timeout_ms(Timeout::Node(timeout), num_milliseconds(&duration))
                    .map(|_| ())
                    .map_err(|x| format!("{:?}", x))
                    .log_error("Unable to add timeout to event loop"),
            Err(_) => self.handler.handle_timeout(timeout),
        }
    }
}

impl<H: EventHandler> mio::Handler for MioAdapter<H> {
    type Timeout = Timeout<H::Timeout>;
    type Message = InternalEvent<H::ApplicationEvent, H::Timeout>;

    fn ready(&mut self, event_loop: &mut EventLoop<H>, token: mio::Token, events: mio::EventSet) {
        self.network
            .io(event_loop, &mut self.handler, token, events)
            .log_error(format!("{}", self.network.address()));
    }

    fn notify(&mut self, event_loop: &mut EventLoop<H>, msg: Self::Message) {
        match msg {
            InternalEvent::Node(event) => self.handler.handle_event(event),
            InternalEvent::Invoke(args) => self.handle_invoke(event_loop, args),
            InternalEvent::Application(event) => self.handler.handle_application_event(event),
        }
    }

    fn timeout(&mut self, event_loop: &mut EventLoop<H>, timeout: Self::Timeout) {
        match timeout {
            Timeout::Node(timeout) => {
                self.handler.handle_timeout(timeout);
            }
            Timeout::Internal(timeout) => {
                self.network.handle_timeout(event_loop, timeout);
            }
        }
    }

    // TODO think about interrupted handlers
    // fn interrupted(&mut self, _: &mut EventLoop) {
    //     self.push(Event::Terminate);
    // }

    fn tick(&mut self, event_loop: &mut EventLoop<H>) {
        self.network.tick(event_loop);
    }
}

impl<H: EventHandler> Reactor<H> for Events<H> {
    type Channel = MioChannel<H::ApplicationEvent, H::Timeout>;

    fn bind(&mut self) -> ::std::io::Result<()> {
        self.inner.network.bind(&mut self.event_loop)
    }
    fn run(&mut self) -> ::std::io::Result<()> {
        self.event_loop.run(&mut self.inner)
    }
    fn run_once(&mut self, timeout: Option<usize>) -> ::std::io::Result<()> {
        self.event_loop.run_once(&mut self.inner, timeout)
    }
    fn get_time(&self) -> SystemTime {
        SystemTime::now()
    }
    fn channel(&self) -> MioChannel<H::ApplicationEvent, H::Timeout> {
        MioChannel {
            inner: self.event_loop.channel(),
            address: *self.inner.network.address(),
        }
    }
}

trait LogError {
    fn log_error<S: AsRef<str>>(self, msg: S);
}

impl<E> LogError for ::std::result::Result<(), E>
    where E: Display
{
    fn log_error<S: AsRef<str>>(self, msg: S) {
        if let Err(error) = self {
            error!("{}, an error occured: {}", msg.as_ref(), error);
        }
    }
}

#[derive(Debug)]
pub struct Error {
    message: String,
}

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

impl Error {
    pub fn new<T: Into<String>>(message: T) -> Error {
        Error { message: message.into() }
    }
}

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

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

fn num_milliseconds(duration: &Duration) -> u64 {
    const MILLIS_PER_SEC: u64 = 1000;
    const NANOS_PER_MILLI: u32 = 1000_000;

    let secs_part = duration.as_secs() * MILLIS_PER_SEC;
    let nanos_part = duration.subsec_nanos() / NANOS_PER_MILLI;
    secs_part + nanos_part as u64
}
<|endoftext|>


<commit_before>// Copyright 2017 The Grin Developers
//
// 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.
//

//! Tests for async mode.. should be run with RUST_TEST_THREADS=1

extern crate cuckoo_miner as cuckoo;
extern crate time;

pub mod common;
use common::{SAMPLE_GRIN_PRE_HEADER_1, SAMPLE_GRIN_POST_HEADER_1};

use cuckoo::{CuckooMinerConfig, CuckooMiner};

// Helper function, tests a particular miner implementation against a known set
fn mine_async_for_duration(full_paths: Vec<&str>, duration_in_seconds: i64) {
	let mut config_vec=Vec::new();
	for p in full_paths.into_iter() {
		let mut config = CuckooMinerConfig::new();
		config.plugin_full_path = String::from(p);
		config_vec.push(config);
	}

	let stat_check_interval = 3;
	let mut deadline = time::get_time().sec + duration_in_seconds;
	let mut next_stat_check = time::get_time().sec + stat_check_interval;
	let mut stats_updated=false;
	//for CI testing on slower servers
	//if we're trying to quit and there are no stats yet, keep going for a bit
	let mut extra_time=false;
	let extra_time_value=180;

	while time::get_time().sec < deadline {

		println!("Test mining for {} seconds, looking for difficulty > 0", duration_in_seconds);
		let mut i=0;
		for c in config_vec.clone().into_iter(){
			println!("Plugin {}: {}", i, c.plugin_full_path);
			i+=1;
		}

		// these always get consumed after a notify
		let miner = CuckooMiner::new(config_vec.clone()).expect("");
		let job_handle = miner.notify(1, SAMPLE_GRIN_PRE_HEADER_1, SAMPLE_GRIN_POST_HEADER_1, 0).unwrap();

		loop {
			if let Some(s) = job_handle.get_solution() {
				println!("Sol found: {}, {:?}", s.get_nonce_as_u64(), s);
				// up to you to read it and check difficulty
				continue;
			}
			if time::get_time().sec >= next_stat_check {
				let mut sps_total=0.0;
				for index in 0..config_vec.len() {
					let stats_vec=job_handle.get_stats(index);
					if let Err(e) = stats_vec {
						panic!("Error getting stats: {:?}", e);
					}
					for s in stats_vec.unwrap().into_iter() {
						let last_solution_time_secs = s.last_solution_time as f64 / 1000.0;
						let last_hashes_per_sec = 1.0 / last_solution_time_secs;
						println!("Plugin {} - Device {} ({}) - Last Solution time: {}; Solutions per second: {:.*}",
						index,s.device_id, s.device_name, last_solution_time_secs, 3, last_hashes_per_sec);
						if last_hashes_per_sec.is_finite() {
							sps_total+=last_hashes_per_sec;
						}
						if last_solution_time_secs > 0.0 {
							stats_updated = true;
							if extra_time {
								break;
							}
						}
						i+=1;
					}
				}
				println!("Total solutions per second: {}", sps_total);
				next_stat_check = time::get_time().sec + stat_check_interval;
			}
			if time::get_time().sec > deadline {
				if !stats_updated && !extra_time {
					extra_time=true;
					deadline+=extra_time_value;
				}
				println!("Stopping jobs and waiting for cleanup");
				job_handle.stop_jobs();
				break;
			}
		}
	}
	assert!(stats_updated==true);
}

//mines for a bit on each available plugin, one after the other
#[test]
fn on_commit_mine_single_plugin_async() {
	let caps = common::get_plugin_vec("");
	for c in &caps {
	 let mut plugin_path_vec:Vec<&str> = Vec::new();
		plugin_path_vec.push(&c.full_path);
		mine_async_for_duration(plugin_path_vec, 180);
	}
}

//Same as above, but only for cuda
#[test]
fn on_cuda_commit_mine_single_plugin_async() {
	let caps = common::get_plugin_vec("cuda");
	for c in &caps {
	 let mut plugin_path_vec:Vec<&str> = Vec::new();
		plugin_path_vec.push(&c.full_path);
		mine_async_for_duration(plugin_path_vec, 180);
	}
}

//mine cuda and matrix (mean) miner for a bit
#[test]
fn on_cuda_commit_mine_mean_cpu_and_lean_cuda_async() {
	let caps = common::get_plugin_vec("");
	let mut plugin_path_vec:Vec<&str> = Vec::new();
	for c in &caps {
		if c.full_path.contains("lean_cuda_30") || c.full_path.contains("mean_cpu_30"){
			plugin_path_vec.push(&c.full_path);
		}
	}
	mine_async_for_duration(plugin_path_vec, 180);
}

//Mines for a bit on all available plugins at once
//(won't be efficient, but should stress-tes plugins nicely)
#[test]
fn on_commit_mine_all_plugins_async() {
	// Get a list of installed plugins and capabilities
	// only do cuckoo 30s
	let caps = common::get_plugin_vec("30");
	let mut plugin_path_vec:Vec<&str> = Vec::new();
	for c in &caps {
		plugin_path_vec.push(&c.full_path);
	}
	mine_async_for_duration(plugin_path_vec, 120);
}
<commit_msg>even more time allowed for travis tests<commit_after>// Copyright 2017 The Grin Developers
//
// 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.
//

//! Tests for async mode.. should be run with RUST_TEST_THREADS=1

extern crate cuckoo_miner as cuckoo;
extern crate time;

pub mod common;
use common::{SAMPLE_GRIN_PRE_HEADER_1, SAMPLE_GRIN_POST_HEADER_1};

use cuckoo::{CuckooMinerConfig, CuckooMiner};

// Helper function, tests a particular miner implementation against a known set
fn mine_async_for_duration(full_paths: Vec<&str>, duration_in_seconds: i64) {
	let mut config_vec=Vec::new();
	for p in full_paths.into_iter() {
		let mut config = CuckooMinerConfig::new();
		config.plugin_full_path = String::from(p);
		config_vec.push(config);
	}

	let stat_check_interval = 3;
	let mut deadline = time::get_time().sec + duration_in_seconds;
	let mut next_stat_check = time::get_time().sec + stat_check_interval;
	let mut stats_updated=false;
	//for CI testing on slower servers
	//if we're trying to quit and there are no stats yet, keep going for a bit
	let mut extra_time=false;
	let extra_time_value=600;

	while time::get_time().sec < deadline {

		println!("Test mining for {} seconds, looking for difficulty > 0", duration_in_seconds);
		let mut i=0;
		for c in config_vec.clone().into_iter(){
			println!("Plugin {}: {}", i, c.plugin_full_path);
			i+=1;
		}

		// these always get consumed after a notify
		let miner = CuckooMiner::new(config_vec.clone()).expect("");
		let job_handle = miner.notify(1, SAMPLE_GRIN_PRE_HEADER_1, SAMPLE_GRIN_POST_HEADER_1, 0).unwrap();

		loop {
			if let Some(s) = job_handle.get_solution() {
				println!("Sol found: {}, {:?}", s.get_nonce_as_u64(), s);
				// up to you to read it and check difficulty
				continue;
			}
			if time::get_time().sec >= next_stat_check {
				let mut sps_total=0.0;
				for index in 0..config_vec.len() {
					let stats_vec=job_handle.get_stats(index);
					if let Err(e) = stats_vec {
						panic!("Error getting stats: {:?}", e);
					}
					for s in stats_vec.unwrap().into_iter() {
						let last_solution_time_secs = s.last_solution_time as f64 / 1000.0;
						let last_hashes_per_sec = 1.0 / last_solution_time_secs;
						println!("Plugin {} - Device {} ({}) - Last Solution time: {}; Solutions per second: {:.*}",
						index,s.device_id, s.device_name, last_solution_time_secs, 3, last_hashes_per_sec);
						if last_hashes_per_sec.is_finite() {
							sps_total+=last_hashes_per_sec;
						}
						if last_solution_time_secs > 0.0 {
							stats_updated = true;
							if extra_time {
								break;
							}
						}
						i+=1;
					}
				}
				println!("Total solutions per second: {}", sps_total);
				next_stat_check = time::get_time().sec + stat_check_interval;
			}
			if time::get_time().sec > deadline {
				if !stats_updated && !extra_time {
					extra_time=true;
					deadline+=extra_time_value;
				}
				println!("Stopping jobs and waiting for cleanup");
				job_handle.stop_jobs();
				break;
			}
		}
	}
	assert!(stats_updated==true);
}

//mines for a bit on each available plugin, one after the other
#[test]
fn on_commit_mine_single_plugin_async() {
	let caps = common::get_plugin_vec("");
	for c in &caps {
	 let mut plugin_path_vec:Vec<&str> = Vec::new();
		plugin_path_vec.push(&c.full_path);
		mine_async_for_duration(plugin_path_vec, 180);
	}
}

//Same as above, but only for cuda
#[test]
fn on_cuda_commit_mine_single_plugin_async() {
	let caps = common::get_plugin_vec("cuda");
	for c in &caps {
	 let mut plugin_path_vec:Vec<&str> = Vec::new();
		plugin_path_vec.push(&c.full_path);
		mine_async_for_duration(plugin_path_vec, 180);
	}
}

//mine cuda and matrix (mean) miner for a bit
#[test]
fn on_cuda_commit_mine_mean_cpu_and_lean_cuda_async() {
	let caps = common::get_plugin_vec("");
	let mut plugin_path_vec:Vec<&str> = Vec::new();
	for c in &caps {
		if c.full_path.contains("lean_cuda_30") || c.full_path.contains("mean_cpu_30"){
			plugin_path_vec.push(&c.full_path);
		}
	}
	mine_async_for_duration(plugin_path_vec, 180);
}

//Mines for a bit on all available plugins at once
//(won't be efficient, but should stress-tes plugins nicely)
#[test]
fn on_commit_mine_all_plugins_async() {
	// Get a list of installed plugins and capabilities
	// only do cuckoo 30s
	let caps = common::get_plugin_vec("30");
	let mut plugin_path_vec:Vec<&str> = Vec::new();
	for c in &caps {
		plugin_path_vec.push(&c.full_path);
	}
	mine_async_for_duration(plugin_path_vec, 120);
}
<|endoftext|>


<commit_before>// Copyright 2017 The Grin Developers
//
// 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.
//

//! Tests for async mode.. should be run with RUST_TEST_THREADS=1

extern crate cuckoo_miner as cuckoo;
extern crate time;

pub mod common;
use common::{SAMPLE_GRIN_PRE_HEADER_1, SAMPLE_GRIN_POST_HEADER_1};

use cuckoo::{CuckooMinerConfig, CuckooMiner};

// Helper function, tests a particular miner implementation against a known set
fn mine_async_for_duration(full_paths: Vec<&str>, duration_in_seconds: i64) {
	let mut config_vec=Vec::new();
	for p in full_paths.into_iter() {
		let mut config = CuckooMinerConfig::new();
		config.plugin_full_path = String::from(p);
		config_vec.push(config);
	}

	let stat_check_interval = 3;
	let mut deadline = time::get_time().sec + duration_in_seconds;
	let mut next_stat_check = time::get_time().sec + stat_check_interval;
	let mut stats_updated=false;
	//for CI testing on slower servers
	//if we're trying to quit and there are no stats yet, keep going for a bit
	let mut extra_time=false;
	let extra_time_value=600;

	while time::get_time().sec < deadline {

		println!("Test mining for {} seconds, looking for difficulty > 0", duration_in_seconds);
		let mut i=0;
		for c in config_vec.clone().into_iter(){
			println!("Plugin {}: {}", i, c.plugin_full_path);
			i+=1;
		}

		// these always get consumed after a notify
		let miner = CuckooMiner::new(config_vec.clone()).expect("");
		let job_handle = miner.notify(1, SAMPLE_GRIN_PRE_HEADER_1, SAMPLE_GRIN_POST_HEADER_1, 0).unwrap();

		loop {
			if let Some(s) = job_handle.get_solution() {
				println!("Sol found: {}, {:?}", s.get_nonce_as_u64(), s);
				// up to you to read it and check difficulty
				continue;
			}
			if time::get_time().sec >= next_stat_check {
				let mut sps_total=0.0;
				for index in 0..config_vec.len() {
					let stats_vec=job_handle.get_stats(index);
					if let Err(e) = stats_vec {
						panic!("Error getting stats: {:?}", e);
					}
					for s in stats_vec.unwrap().into_iter() {
						let last_solution_time_secs = s.last_solution_time as f64 / 1000.0;
						let last_hashes_per_sec = 1.0 / last_solution_time_secs;
						println!("Plugin {} - Device {} ({}) - Last Solution time: {}; Solutions per second: {:.*}",
						index,s.device_id, s.device_name, last_solution_time_secs, 3, last_hashes_per_sec);
						if last_hashes_per_sec.is_finite() {
							sps_total+=last_hashes_per_sec;
						}
						if last_solution_time_secs > 0.0 {
							stats_updated = true;
							if extra_time {
								break;
							}
						}
						i+=1;
					}
				}
				println!("Total solutions per second: {}", sps_total);
				next_stat_check = time::get_time().sec + stat_check_interval;
			}
			if time::get_time().sec > deadline {
				if !stats_updated && !extra_time {
					extra_time=true;
					deadline+=extra_time_value;
					println!("More time needed");
				} else {
					println!("Stopping jobs and waiting for cleanup");
					job_handle.stop_jobs();
					break;
				}
			}
		}
	}
	assert!(stats_updated==true);
}

//mines for a bit on each available plugin, one after the other
#[test]
fn on_commit_mine_single_plugin_async() {
	let caps = common::get_plugin_vec("");
	for c in &caps {
	 let mut plugin_path_vec:Vec<&str> = Vec::new();
		plugin_path_vec.push(&c.full_path);
		mine_async_for_duration(plugin_path_vec, 60);
	}
}

//Same as above, but only for cuda
#[test]
fn on_cuda_commit_mine_single_plugin_async() {
	let caps = common::get_plugin_vec("cuda");
	for c in &caps {
	 let mut plugin_path_vec:Vec<&str> = Vec::new();
		plugin_path_vec.push(&c.full_path);
		mine_async_for_duration(plugin_path_vec, 60);
	}
}

//mine cuda and matrix (mean) miner for a bit
#[test]
fn on_cuda_commit_mine_mean_cpu_and_lean_cuda_async() {
	let caps = common::get_plugin_vec("");
	let mut plugin_path_vec:Vec<&str> = Vec::new();
	for c in &caps {
		if c.full_path.contains("lean_cuda_30") || c.full_path.contains("mean_cpu_30"){
			plugin_path_vec.push(&c.full_path);
		}
	}
	mine_async_for_duration(plugin_path_vec, 180);
}

//Mines for a bit on all available plugins at once
//(won't be efficient, but should stress-tes plugins nicely)
#[test]
fn on_commit_mine_all_plugins_async() {
	// Get a list of installed plugins and capabilities
	// only do cuckoo 30s
	let caps = common::get_plugin_vec("30");
	let mut plugin_path_vec:Vec<&str> = Vec::new();
	for c in &caps {
		plugin_path_vec.push(&c.full_path);
	}
	mine_async_for_duration(plugin_path_vec, 120);
}
<commit_msg>more travis testing<commit_after>// Copyright 2017 The Grin Developers
//
// 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.
//

//! Tests for async mode.. should be run with RUST_TEST_THREADS=1

extern crate cuckoo_miner as cuckoo;
extern crate time;

pub mod common;
use common::{SAMPLE_GRIN_PRE_HEADER_1, SAMPLE_GRIN_POST_HEADER_1};

use cuckoo::{CuckooMinerConfig, CuckooMiner};

// Helper function, tests a particular miner implementation against a known set
fn mine_async_for_duration(full_paths: Vec<&str>, duration_in_seconds: i64) {
	let mut config_vec=Vec::new();
	for p in full_paths.into_iter() {
		let mut config = CuckooMinerConfig::new();
		config.plugin_full_path = String::from(p);
		config_vec.push(config);
	}

	let stat_check_interval = 3;
	let mut deadline = time::get_time().sec + duration_in_seconds;
	let mut next_stat_check = time::get_time().sec + stat_check_interval;
	let mut stats_updated=false;
	//for CI testing on slower servers
	//if we're trying to quit and there are no stats yet, keep going for a bit
	let mut extra_time=false;
	let extra_time_value=600;

	while time::get_time().sec < deadline {

		println!("Test mining for {} seconds, looking for difficulty > 0", duration_in_seconds);
		let mut i=0;
		for c in config_vec.clone().into_iter(){
			println!("Plugin {}: {}", i, c.plugin_full_path);
			i+=1;
		}

		// these always get consumed after a notify
		let miner = CuckooMiner::new(config_vec.clone()).expect("");
		let job_handle = miner.notify(1, SAMPLE_GRIN_PRE_HEADER_1, SAMPLE_GRIN_POST_HEADER_1, 0).unwrap();

		loop {
			if let Some(s) = job_handle.get_solution() {
				println!("Sol found: {}, {:?}", s.get_nonce_as_u64(), s);
				// up to you to read it and check difficulty
				continue;
			}
			if time::get_time().sec >= next_stat_check {
				let mut sps_total=0.0;
				for index in 0..config_vec.len() {
					let stats_vec=job_handle.get_stats(index);
					if let Err(e) = stats_vec {
						panic!("Error getting stats: {:?}", e);
					}
					for s in stats_vec.unwrap().into_iter() {
						let last_solution_time_secs = s.last_solution_time as f64 / 1000.0;
						let last_hashes_per_sec = 1.0 / last_solution_time_secs;
						println!("Plugin {} - Device {} ({}) - Last Solution time: {}; Solutions per second: {:.*}",
						index,s.device_id, s.device_name, last_solution_time_secs, 3, last_hashes_per_sec);
						if last_hashes_per_sec.is_finite() {
							sps_total+=last_hashes_per_sec;
						}
						if last_solution_time_secs > 0.0 {
							stats_updated = true;
						}
						i+=1;
					}
				}
				println!("Total solutions per second: {}", sps_total);
				next_stat_check = time::get_time().sec + stat_check_interval;
			}
			if time::get_time().sec > deadline {
				if !stats_updated && !extra_time {
					extra_time=true;
					deadline+=extra_time_value;
					println!("More time needed");
				} else {
					println!("Stopping jobs and waiting for cleanup");
					job_handle.stop_jobs();
					break;
				}
			}
			if stats_updated && extra_time {
				break;
			}
		}
		if stats_updated && extra_time {
			break;
		}
}
	assert!(stats_updated==true);
}

//mines for a bit on each available plugin, one after the other
#[test]
fn on_commit_mine_single_plugin_async() {
	let caps = common::get_plugin_vec("");
	for c in &caps {
	 let mut plugin_path_vec:Vec<&str> = Vec::new();
		plugin_path_vec.push(&c.full_path);
		mine_async_for_duration(plugin_path_vec, 10);
	}
}

//Same as above, but only for cuda
#[test]
fn on_cuda_commit_mine_single_plugin_async() {
	let caps = common::get_plugin_vec("cuda");
	for c in &caps {
	 let mut plugin_path_vec:Vec<&str> = Vec::new();
		plugin_path_vec.push(&c.full_path);
		mine_async_for_duration(plugin_path_vec, 60);
	}
}

//mine cuda and matrix (mean) miner for a bit
#[test]
fn on_cuda_commit_mine_mean_cpu_and_lean_cuda_async() {
	let caps = common::get_plugin_vec("");
	let mut plugin_path_vec:Vec<&str> = Vec::new();
	for c in &caps {
		if c.full_path.contains("lean_cuda_30") || c.full_path.contains("mean_cpu_30"){
			plugin_path_vec.push(&c.full_path);
		}
	}
	mine_async_for_duration(plugin_path_vec, 180);
}

//Mines for a bit on all available plugins at once
//(won't be efficient, but should stress-tes plugins nicely)
#[test]
fn on_commit_mine_all_plugins_async() {
	// Get a list of installed plugins and capabilities
	// only do cuckoo 30s
	let caps = common::get_plugin_vec("30");
	let mut plugin_path_vec:Vec<&str> = Vec::new();
	for c in &caps {
		plugin_path_vec.push(&c.full_path);
	}
	mine_async_for_duration(plugin_path_vec, 120);
}
<|endoftext|>


<commit_before>use anyhow::Error;
use flate2::read::GzDecoder;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use tar::Archive;

const DEFAULT_TARGET: &str = "x86_64-unknown-linux-gnu";
const RUSTC_VERSION: &str = include_str!("../../../version");

#[derive(Debug, Hash, Eq, PartialEq, Clone)]
pub(crate) enum PkgType {
    Rust,
    RustSrc,
    Rustc,
    Cargo,
    Rls,
    RustAnalyzer,
    Clippy,
    Rustfmt,
    LlvmTools,
    Miri,
    Other(String),
}

impl PkgType {
    pub(crate) fn from_component(component: &str) -> Self {
        match component {
            "rust" => PkgType::Rust,
            "rust-src" => PkgType::RustSrc,
            "rustc" => PkgType::Rustc,
            "cargo" => PkgType::Cargo,
            "rls" | "rls-preview" => PkgType::Rls,
            "rust-analyzer" | "rust-analyzer-preview" => PkgType::RustAnalyzer,
            "clippy" | "clippy-preview" => PkgType::Clippy,
            "rustfmt" | "rustfmt-preview" => PkgType::Rustfmt,
            "llvm-tools" | "llvm-tools-preview" => PkgType::LlvmTools,
            "miri" | "miri-preview" => PkgType::Miri,
            other => PkgType::Other(other.into()),
        }
    }

    /// First part of the tarball name.
    fn tarball_component_name(&self) -> &str {
        match self {
            PkgType::Rust => "rust",
            PkgType::RustSrc => "rust-src",
            PkgType::Rustc => "rustc",
            PkgType::Cargo => "cargo",
            PkgType::Rls => "rls",
            PkgType::RustAnalyzer => "rust-analyzer",
            PkgType::Clippy => "clippy",
            PkgType::Rustfmt => "rustfmt",
            PkgType::LlvmTools => "llvm-tools",
            PkgType::Miri => "miri",
            PkgType::Other(component) => component,
        }
    }

    /// Whether this package has the same version as Rust itself, or has its own `version` and
    /// `git-commit-hash` files inside the tarball.
    fn should_use_rust_version(&self) -> bool {
        match self {
            PkgType::Cargo => false,
            PkgType::Rls => false,
            PkgType::RustAnalyzer => false,
            PkgType::Clippy => false,
            PkgType::Rustfmt => false,
            PkgType::LlvmTools => false,
            PkgType::Miri => false,

            PkgType::Rust => true,
            PkgType::RustSrc => true,
            PkgType::Rustc => true,
            PkgType::Other(_) => true,
        }
    }

    /// Whether this package is target-independent or not.
    fn target_independent(&self) -> bool {
        *self == PkgType::RustSrc
    }
}

#[derive(Debug, Default, Clone)]
pub(crate) struct VersionInfo {
    pub(crate) version: Option<String>,
    pub(crate) git_commit: Option<String>,
    pub(crate) present: bool,
}

pub(crate) struct Versions {
    channel: String,
    dist_path: PathBuf,
    versions: HashMap<PkgType, VersionInfo>,
}

impl Versions {
    pub(crate) fn new(channel: &str, dist_path: &Path) -> Result<Self, Error> {
        Ok(Self { channel: channel.into(), dist_path: dist_path.into(), versions: HashMap::new() })
    }

    pub(crate) fn channel(&self) -> &str {
        &self.channel
    }

    pub(crate) fn version(&mut self, mut package: &PkgType) -> Result<VersionInfo, Error> {
        if package.should_use_rust_version() {
            package = &PkgType::Rust;
        }

        match self.versions.get(package) {
            Some(version) => Ok(version.clone()),
            None => {
                let version_info = self.load_version_from_tarball(package)?;
                self.versions.insert(package.clone(), version_info.clone());
                Ok(version_info)
            }
        }
    }

    fn load_version_from_tarball(&mut self, package: &PkgType) -> Result<VersionInfo, Error> {
        let tarball_name = self.tarball_name(package, DEFAULT_TARGET)?;
        let tarball = self.dist_path.join(tarball_name);

        let file = match File::open(&tarball) {
            Ok(file) => file,
            Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
                // Missing tarballs do not return an error, but return empty data.
                return Ok(VersionInfo::default());
            }
            Err(err) => return Err(err.into()),
        };
        let mut tar = Archive::new(GzDecoder::new(file));

        let mut version = None;
        let mut git_commit = None;
        for entry in tar.entries()? {
            let mut entry = entry?;

            let dest;
            match entry.path()?.components().nth(1).and_then(|c| c.as_os_str().to_str()) {
                Some("version") => dest = &mut version,
                Some("git-commit-hash") => dest = &mut git_commit,
                _ => continue,
            }
            let mut buf = String::new();
            entry.read_to_string(&mut buf)?;
            *dest = Some(buf);

            // Short circuit to avoid reading the whole tar file if not necessary.
            if version.is_some() && git_commit.is_some() {
                break;
            }
        }

        Ok(VersionInfo { version, git_commit, present: true })
    }

    pub(crate) fn disable_version(&mut self, package: &PkgType) {
        match self.versions.get_mut(package) {
            Some(version) => {
                *version = VersionInfo::default();
            }
            None => {
                self.versions.insert(package.clone(), VersionInfo::default());
            }
        }
    }

    pub(crate) fn archive_name(
        &mut self,
        package: &PkgType,
        target: &str,
        extension: &str,
    ) -> Result<String, Error> {
        let component_name = package.tarball_component_name();
        let version = match self.channel.as_str() {
            "stable" => RUSTC_VERSION.into(),
            "beta" => "beta".into(),
            "nightly" => "nightly".into(),
            _ => format!("{}-dev", RUSTC_VERSION),
        };

        if package.target_independent() {
            Ok(format!("{}-{}.{}", component_name, version, extension))
        } else {
            Ok(format!("{}-{}-{}.{}", component_name, version, target, extension))
        }
    }

    pub(crate) fn tarball_name(
        &mut self,
        package: &PkgType,
        target: &str,
    ) -> Result<String, Error> {
        self.archive_name(package, target, "tar.gz")
    }

    pub(crate) fn rustc_version(&self) -> &str {
        RUSTC_VERSION
    }
}
<commit_msg>build-manifest: strip newline from rustc version<commit_after>use anyhow::Error;
use flate2::read::GzDecoder;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use tar::Archive;

const DEFAULT_TARGET: &str = "x86_64-unknown-linux-gnu";

#[derive(Debug, Hash, Eq, PartialEq, Clone)]
pub(crate) enum PkgType {
    Rust,
    RustSrc,
    Rustc,
    Cargo,
    Rls,
    RustAnalyzer,
    Clippy,
    Rustfmt,
    LlvmTools,
    Miri,
    Other(String),
}

impl PkgType {
    pub(crate) fn from_component(component: &str) -> Self {
        match component {
            "rust" => PkgType::Rust,
            "rust-src" => PkgType::RustSrc,
            "rustc" => PkgType::Rustc,
            "cargo" => PkgType::Cargo,
            "rls" | "rls-preview" => PkgType::Rls,
            "rust-analyzer" | "rust-analyzer-preview" => PkgType::RustAnalyzer,
            "clippy" | "clippy-preview" => PkgType::Clippy,
            "rustfmt" | "rustfmt-preview" => PkgType::Rustfmt,
            "llvm-tools" | "llvm-tools-preview" => PkgType::LlvmTools,
            "miri" | "miri-preview" => PkgType::Miri,
            other => PkgType::Other(other.into()),
        }
    }

    /// First part of the tarball name.
    fn tarball_component_name(&self) -> &str {
        match self {
            PkgType::Rust => "rust",
            PkgType::RustSrc => "rust-src",
            PkgType::Rustc => "rustc",
            PkgType::Cargo => "cargo",
            PkgType::Rls => "rls",
            PkgType::RustAnalyzer => "rust-analyzer",
            PkgType::Clippy => "clippy",
            PkgType::Rustfmt => "rustfmt",
            PkgType::LlvmTools => "llvm-tools",
            PkgType::Miri => "miri",
            PkgType::Other(component) => component,
        }
    }

    /// Whether this package has the same version as Rust itself, or has its own `version` and
    /// `git-commit-hash` files inside the tarball.
    fn should_use_rust_version(&self) -> bool {
        match self {
            PkgType::Cargo => false,
            PkgType::Rls => false,
            PkgType::RustAnalyzer => false,
            PkgType::Clippy => false,
            PkgType::Rustfmt => false,
            PkgType::LlvmTools => false,
            PkgType::Miri => false,

            PkgType::Rust => true,
            PkgType::RustSrc => true,
            PkgType::Rustc => true,
            PkgType::Other(_) => true,
        }
    }

    /// Whether this package is target-independent or not.
    fn target_independent(&self) -> bool {
        *self == PkgType::RustSrc
    }
}

#[derive(Debug, Default, Clone)]
pub(crate) struct VersionInfo {
    pub(crate) version: Option<String>,
    pub(crate) git_commit: Option<String>,
    pub(crate) present: bool,
}

pub(crate) struct Versions {
    channel: String,
    dist_path: PathBuf,
    versions: HashMap<PkgType, VersionInfo>,
}

impl Versions {
    pub(crate) fn new(channel: &str, dist_path: &Path) -> Result<Self, Error> {
        Ok(Self { channel: channel.into(), dist_path: dist_path.into(), versions: HashMap::new() })
    }

    pub(crate) fn channel(&self) -> &str {
        &self.channel
    }

    pub(crate) fn version(&mut self, mut package: &PkgType) -> Result<VersionInfo, Error> {
        if package.should_use_rust_version() {
            package = &PkgType::Rust;
        }

        match self.versions.get(package) {
            Some(version) => Ok(version.clone()),
            None => {
                let version_info = self.load_version_from_tarball(package)?;
                self.versions.insert(package.clone(), version_info.clone());
                Ok(version_info)
            }
        }
    }

    fn load_version_from_tarball(&mut self, package: &PkgType) -> Result<VersionInfo, Error> {
        let tarball_name = self.tarball_name(package, DEFAULT_TARGET)?;
        let tarball = self.dist_path.join(tarball_name);

        let file = match File::open(&tarball) {
            Ok(file) => file,
            Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
                // Missing tarballs do not return an error, but return empty data.
                return Ok(VersionInfo::default());
            }
            Err(err) => return Err(err.into()),
        };
        let mut tar = Archive::new(GzDecoder::new(file));

        let mut version = None;
        let mut git_commit = None;
        for entry in tar.entries()? {
            let mut entry = entry?;

            let dest;
            match entry.path()?.components().nth(1).and_then(|c| c.as_os_str().to_str()) {
                Some("version") => dest = &mut version,
                Some("git-commit-hash") => dest = &mut git_commit,
                _ => continue,
            }
            let mut buf = String::new();
            entry.read_to_string(&mut buf)?;
            *dest = Some(buf);

            // Short circuit to avoid reading the whole tar file if not necessary.
            if version.is_some() && git_commit.is_some() {
                break;
            }
        }

        Ok(VersionInfo { version, git_commit, present: true })
    }

    pub(crate) fn disable_version(&mut self, package: &PkgType) {
        match self.versions.get_mut(package) {
            Some(version) => {
                *version = VersionInfo::default();
            }
            None => {
                self.versions.insert(package.clone(), VersionInfo::default());
            }
        }
    }

    pub(crate) fn archive_name(
        &mut self,
        package: &PkgType,
        target: &str,
        extension: &str,
    ) -> Result<String, Error> {
        let component_name = package.tarball_component_name();
        let version = match self.channel.as_str() {
            "stable" => self.rustc_version().into(),
            "beta" => "beta".into(),
            "nightly" => "nightly".into(),
            _ => format!("{}-dev", self.rustc_version()),
        };

        if package.target_independent() {
            Ok(format!("{}-{}.{}", component_name, version, extension))
        } else {
            Ok(format!("{}-{}-{}.{}", component_name, version, target, extension))
        }
    }

    pub(crate) fn tarball_name(
        &mut self,
        package: &PkgType,
        target: &str,
    ) -> Result<String, Error> {
        self.archive_name(package, target, "tar.gz")
    }

    pub(crate) fn rustc_version(&self) -> &str {
        const RUSTC_VERSION: &str = include_str!("../../../version");
        RUSTC_VERSION.trim()
    }
}
<|endoftext|>


<commit_before>#![allow(unused_imports)]
#![allow(non_snake_case)]

use std::cmp::{max, min, Ordering};
use std::collections::*;
use std::fmt::{Debug, Formatter};
use std::io::*;
use std::ops::*;
use std::*;

// -----------------------------------------------
// Framework
// -----------------------------------------------

#[allow(unused_macros)]
macro_rules! read {
    ([$t:ty] ; $n:expr) =>
        ((0..$n).map(|_| read!([$t])).collect::<Vec<_>>());
    ($($t:ty),+ ; $n:expr) =>
        ((0..$n).map(|_| read!($($t),+)).collect::<Vec<_>>());
    ([$t:ty]) =>
        (rl().split_whitespace().map(|w| w.parse().unwrap()).collect::<Vec<$t>>());
    ($t:ty) =>
        (rl().parse::<$t>().unwrap());
    ($($t:ty),*) => {{
        let buf = rl();
        let mut w = buf.split_whitespace();
        ($(w.next().unwrap().parse::<$t>().unwrap()),*)
    }};
}

#[allow(unused_macros)]
macro_rules! debug {
    ($($arg:expr),*) => {
        #[cfg(debug_assertions)]
        {
            let entries = [$(&stringify!([$arg]:), &$arg as &Debug),*];
            stderr().write_fmt(format_args!("{:#?}\n", entries)).unwrap();
        }
    };
}

#[allow(dead_code)]
fn rl() -> String {
    let mut buf = String::new();
    io::stdin().read_line(&mut buf).unwrap();
    buf.trim_right().to_owned()
}

trait IteratorExt: Iterator + Sized {
    fn vec(self) -> Vec<Self::Item> {
        self.collect()
    }
}

impl<T: Iterator> IteratorExt for T {}

// -----------------------------------------------
// Solution
// -----------------------------------------------

pub fn main() {
    return;
}
<commit_msg>Update imports<commit_after>#![allow(unused_imports)]
#![allow(non_snake_case)]

use std::cell::RefCell;
use std::cmp::{max, min, Ordering};
use std::collections::*;
use std::fmt::{Debug, Formatter};
use std::io::*;
use std::mem::{replace, swap};
use std::ops::*;
use std::rc::Rc;

// -----------------------------------------------
// Framework
// -----------------------------------------------

#[allow(unused_macros)]
macro_rules! read {
    ([$t:ty] ; $n:expr) =>
        ((0..$n).map(|_| read!([$t])).collect::<Vec<_>>());
    ($($t:ty),+ ; $n:expr) =>
        ((0..$n).map(|_| read!($($t),+)).collect::<Vec<_>>());
    ([$t:ty]) =>
        (rl().split_whitespace().map(|w| w.parse().unwrap()).collect::<Vec<$t>>());
    ($t:ty) =>
        (rl().parse::<$t>().unwrap());
    ($($t:ty),*) => {{
        let buf = rl();
        let mut w = buf.split_whitespace();
        ($(w.next().unwrap().parse::<$t>().unwrap()),*)
    }};
}

#[allow(unused_macros)]
macro_rules! debug {
    ($($arg:expr),*) => {
        #[cfg(debug_assertions)]
        {
            let entries = [$(&stringify!([$arg]:), &$arg as &Debug),*];
            stderr().write_fmt(format_args!("{:#?}\n", entries)).unwrap();
        }
    };
}

#[allow(dead_code)]
fn rl() -> String {
    let mut buf = String::new();
    stdin().read_line(&mut buf).unwrap();
    buf.trim_right().to_owned()
}

trait IteratorExt: Iterator + Sized {
    fn vec(self) -> Vec<Self::Item> {
        self.collect()
    }
}

impl<T: Iterator> IteratorExt for T {}

// -----------------------------------------------
// Solution
// -----------------------------------------------

pub fn main() {
    return;
}
<|endoftext|>


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

use dom::bindings::callback::ExceptionHandling::Report;
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::InheritTypes::{EventTargetCast, NodeCast};
use dom::bindings::global::{GlobalRoot, global_object_for_reflector};
use dom::bindings::js::{JS, Root, RootedReference};
use dom::bindings::trace::RootedVec;
use dom::event::{Event, EventPhase};
use dom::eventtarget::{EventTarget, ListenerPhase, EventListenerType};
use dom::node::Node;
use dom::virtualmethods::vtable_for;
use dom::window::Window;

use devtools_traits::{StartedTimelineMarker, TimelineMarker, TimelineMarkerType};

struct AutoDOMEventMarker {
    window: Root<Window>,
    marker: Option<StartedTimelineMarker>,
}

impl AutoDOMEventMarker {
    fn new(window: &Window) -> AutoDOMEventMarker {
        AutoDOMEventMarker {
            window: Root::from_ref(window),
            marker: Some(TimelineMarker::start("DOMEvent".to_owned())),
        }
    }
}

impl Drop for AutoDOMEventMarker {
    fn drop(&mut self) {
        self.window.emit_timeline_marker(self.marker.take().unwrap().end());
    }
}

fn handle_event(window: Option<&Window>, listener: &EventListenerType,
                current_target: &EventTarget, event: &Event) {
    let _marker;
    if let Some(window) = window {
        _marker = AutoDOMEventMarker::new(window);
    }

    listener.call_or_handle_event(current_target, event, Report);
}

fn dispatch_to_listeners(event: &Event, target: &EventTarget, chain: &[&EventTarget]) {
    assert!(!event.stop_propagation());
    assert!(!event.stop_immediate());

    let window = match global_object_for_reflector(target) {
        GlobalRoot::Window(window) => {
            if window.need_emit_timeline_marker(TimelineMarkerType::DOMEvent) {
                Some(window)
            } else {
                None
            }
        },
        _ => None,
    };

    let type_ = event.Type();

    /* capturing */
    event.set_phase(EventPhase::Capturing);
    for cur_target in chain.iter().rev() {
        if let Some(listeners) = cur_target.get_listeners_for(&type_, ListenerPhase::Capturing) {
            event.set_current_target(cur_target);
            for listener in &listeners {
                handle_event(window.r(), listener, *cur_target, event);

                if event.stop_immediate() {
                    return;
                }
            }

            if event.stop_propagation() {
                return;
            }
        }
    }

    assert!(!event.stop_propagation());
    assert!(!event.stop_immediate());

    /* at target */
    event.set_phase(EventPhase::AtTarget);
    event.set_current_target(target.clone());

    if let Some(listeners) = target.get_listeners(&type_) {
        for listener in listeners {
            handle_event(window.r(), &listener, target, event);

            if event.stop_immediate() {
                return;
            }
        }
        if event.stop_propagation() {
            return;
        }
    }

    assert!(!event.stop_propagation());
    assert!(!event.stop_immediate());

    /* bubbling */
    if event.bubbles() {
        event.set_phase(EventPhase::Bubbling);

        for cur_target in chain {
            if let Some(listeners) = cur_target.get_listeners_for(&type_, ListenerPhase::Bubbling) {
                event.set_current_target(cur_target);
                for listener in &listeners {
                    handle_event(window.r(), listener, *cur_target, event);

                    if event.stop_immediate() {
                        return;
                    }
                }

                if event.stop_propagation() {
                    return;
                }
            }
        }
    }
}

// See https://dom.spec.whatwg.org/#concept-event-dispatch for the full dispatch algorithm
pub fn dispatch_event(target: &EventTarget, pseudo_target: Option<&EventTarget>,
                      event: &Event) -> bool {
    assert!(!event.dispatching());
    assert!(event.initialized());
    assert_eq!(event.phase(), EventPhase::None);
    assert!(event.GetCurrentTarget().is_none());

    event.set_target(match pseudo_target {
        Some(pseudo_target) => pseudo_target,
        None => target.clone(),
    });

    if event.stop_propagation() {
        return !event.DefaultPrevented();
    }

    event.set_dispatching(true);

    //TODO: no chain if not participating in a tree
    let mut chain: RootedVec<JS<EventTarget>> = RootedVec::new();
    if let Some(target_node) = NodeCast::to_ref(target) {
        for ancestor in target_node.ancestors() {
            let ancestor_target = EventTargetCast::from_ref(ancestor.r());
            chain.push(JS::from_ref(ancestor_target))
        }
    }

    dispatch_to_listeners(event, target, chain.r());

    /* default action */
    let target = event.GetTarget();
    match target {
        Some(ref target) => {
            let node: Option<&Node> = NodeCast::to_ref(target.r());
            match node {
                Some(node) => {
                    let vtable = vtable_for(&node);
                    vtable.handle_event(event);
                }
                None => {}
            }
        }
        None => {}
    }

    event.set_dispatching(false);
    event.set_phase(EventPhase::None);
    event.clear_current_target();

    !event.DefaultPrevented()
}
<commit_msg>Use an early return in dispatch_to_listeners.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::callback::ExceptionHandling::Report;
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::InheritTypes::{EventTargetCast, NodeCast};
use dom::bindings::global::{GlobalRoot, global_object_for_reflector};
use dom::bindings::js::{JS, Root, RootedReference};
use dom::bindings::trace::RootedVec;
use dom::event::{Event, EventPhase};
use dom::eventtarget::{EventTarget, ListenerPhase, EventListenerType};
use dom::node::Node;
use dom::virtualmethods::vtable_for;
use dom::window::Window;

use devtools_traits::{StartedTimelineMarker, TimelineMarker, TimelineMarkerType};

struct AutoDOMEventMarker {
    window: Root<Window>,
    marker: Option<StartedTimelineMarker>,
}

impl AutoDOMEventMarker {
    fn new(window: &Window) -> AutoDOMEventMarker {
        AutoDOMEventMarker {
            window: Root::from_ref(window),
            marker: Some(TimelineMarker::start("DOMEvent".to_owned())),
        }
    }
}

impl Drop for AutoDOMEventMarker {
    fn drop(&mut self) {
        self.window.emit_timeline_marker(self.marker.take().unwrap().end());
    }
}

fn handle_event(window: Option<&Window>, listener: &EventListenerType,
                current_target: &EventTarget, event: &Event) {
    let _marker;
    if let Some(window) = window {
        _marker = AutoDOMEventMarker::new(window);
    }

    listener.call_or_handle_event(current_target, event, Report);
}

fn dispatch_to_listeners(event: &Event, target: &EventTarget, chain: &[&EventTarget]) {
    assert!(!event.stop_propagation());
    assert!(!event.stop_immediate());

    let window = match global_object_for_reflector(target) {
        GlobalRoot::Window(window) => {
            if window.need_emit_timeline_marker(TimelineMarkerType::DOMEvent) {
                Some(window)
            } else {
                None
            }
        },
        _ => None,
    };

    let type_ = event.Type();

    /* capturing */
    event.set_phase(EventPhase::Capturing);
    for cur_target in chain.iter().rev() {
        if let Some(listeners) = cur_target.get_listeners_for(&type_, ListenerPhase::Capturing) {
            event.set_current_target(cur_target);
            for listener in &listeners {
                handle_event(window.r(), listener, *cur_target, event);

                if event.stop_immediate() {
                    return;
                }
            }

            if event.stop_propagation() {
                return;
            }
        }
    }

    assert!(!event.stop_propagation());
    assert!(!event.stop_immediate());

    /* at target */
    event.set_phase(EventPhase::AtTarget);
    event.set_current_target(target.clone());

    if let Some(listeners) = target.get_listeners(&type_) {
        for listener in listeners {
            handle_event(window.r(), &listener, target, event);

            if event.stop_immediate() {
                return;
            }
        }
        if event.stop_propagation() {
            return;
        }
    }

    assert!(!event.stop_propagation());
    assert!(!event.stop_immediate());

    /* bubbling */
    if !event.bubbles() {
        return;
    }

    event.set_phase(EventPhase::Bubbling);
    for cur_target in chain {
        if let Some(listeners) = cur_target.get_listeners_for(&type_, ListenerPhase::Bubbling) {
            event.set_current_target(cur_target);
            for listener in &listeners {
                handle_event(window.r(), listener, *cur_target, event);

                if event.stop_immediate() {
                    return;
                }
            }

            if event.stop_propagation() {
                return;
            }
        }
    }
}

// See https://dom.spec.whatwg.org/#concept-event-dispatch for the full dispatch algorithm
pub fn dispatch_event(target: &EventTarget, pseudo_target: Option<&EventTarget>,
                      event: &Event) -> bool {
    assert!(!event.dispatching());
    assert!(event.initialized());
    assert_eq!(event.phase(), EventPhase::None);
    assert!(event.GetCurrentTarget().is_none());

    event.set_target(match pseudo_target {
        Some(pseudo_target) => pseudo_target,
        None => target.clone(),
    });

    if event.stop_propagation() {
        return !event.DefaultPrevented();
    }

    event.set_dispatching(true);

    //TODO: no chain if not participating in a tree
    let mut chain: RootedVec<JS<EventTarget>> = RootedVec::new();
    if let Some(target_node) = NodeCast::to_ref(target) {
        for ancestor in target_node.ancestors() {
            let ancestor_target = EventTargetCast::from_ref(ancestor.r());
            chain.push(JS::from_ref(ancestor_target))
        }
    }

    dispatch_to_listeners(event, target, chain.r());

    /* default action */
    let target = event.GetTarget();
    match target {
        Some(ref target) => {
            let node: Option<&Node> = NodeCast::to_ref(target.r());
            match node {
                Some(node) => {
                    let vtable = vtable_for(&node);
                    vtable.handle_event(event);
                }
                None => {}
            }
        }
        None => {}
    }

    event.set_dispatching(false);
    event.set_phase(EventPhase::None);
    event.clear_current_target();

    !event.DefaultPrevented()
}
<|endoftext|>