<commit_before>use log::trace;

use super::value::Value;
use crate::compiler::lir::ChunkIndex;
use std::collections::HashMap;

#[derive(Debug)]
pub struct Heap {
    objects: HashMap<ObjectPointer, Object>,
    next_address: ObjectPointer,
}

pub type ObjectPointer = usize;

#[derive(Debug, Clone)] // TODO: remove Clone once it's no longer needed
pub struct Object {
    reference_count: usize,
    pub data: ObjectData,
}
#[derive(Clone, Debug)] // TODO: remove Clone once it's no longer needed
pub enum ObjectData {
    Int(u64),
    Text(String),
    Symbol(String),
    Struct(HashMap<ObjectPointer, ObjectPointer>),
    Closure {
        captured: Vec<ObjectPointer>,
        body: ChunkIndex,
    },
}

impl Heap {
    pub fn new() -> Self {
        Self {
            objects: HashMap::new(),
            next_address: 0,
        }
    }

    pub fn get(&self, address: ObjectPointer) -> &Object {
        self.objects
            .get(&address)
            .expect(&format!("Couldn't get object {}.", address))
    }
    pub fn get_mut(&mut self, address: ObjectPointer) -> &mut Object {
        self.objects
            .get_mut(&address)
            .expect(&format!("Couldn't get object {}.", address))
    }

    pub fn dup(&mut self, address: ObjectPointer) {
        self.get_mut(address).reference_count += 1;
        trace!(
            "RefCount of {} increased to {}. Value: {}",
            address,
            self.get(address).reference_count,
            self.export_without_dropping(address),
        );
    }
    pub fn drop(&mut self, address: ObjectPointer) {
        let value = self.export_without_dropping(address); // TODO: Only for logging
        let object = self.get_mut(address);
        object.reference_count -= 1;
        trace!(
            "RefCount of {} reduced to {}. Value: {}",
            address,
            object.reference_count,
            value,
        );
        if object.reference_count == 0 {
            self.free(address);
        }
    }

    pub fn create(&mut self, object: ObjectData) -> ObjectPointer {
        let address = self.next_address;
        trace!("Creating object {:?} at {}.", object, address);
        self.objects.insert(
            address,
            Object {
                reference_count: 1,
                data: object,
            },
        );
        self.next_address += 1;
        address
    }
    pub fn free(&mut self, address: ObjectPointer) {
        let object = self.objects.remove(&address).unwrap();
        trace!("Freeing object {:?} at {}.", object, address);
        assert_eq!(object.reference_count, 0);
        match object.data {
            ObjectData::Int(_) => {}
            ObjectData::Text(_) => {}
            ObjectData::Symbol(_) => {}
            ObjectData::Struct(entries) => {
                for (key, value) in entries {
                    self.drop(key);
                    self.drop(value);
                }
            }
            ObjectData::Closure { captured, .. } => {
                for object in captured {
                    self.drop(object);
                }
            }
        }
    }

    pub(super) fn import(&mut self, value: Value) -> ObjectPointer {
        let value = match value {
            Value::Int(int) => ObjectData::Int(int),
            Value::Text(text) => ObjectData::Text(text),
            Value::Symbol(symbol) => ObjectData::Symbol(symbol),
            Value::Struct(struct_) => {
                let mut entries = HashMap::new();
                for (key, value) in struct_ {
                    let key = self.import(key);
                    let value = self.import(value);
                    entries.insert(key, value);
                }
                ObjectData::Struct(entries)
            }
            Value::Closure { captured, body } => ObjectData::Closure { captured, body },
        };
        self.create(value)
    }
    pub(super) fn export(&mut self, address: ObjectPointer) -> Value {
        let value = self.export_without_dropping(address);
        self.drop(address);
        value
    }
    pub fn export_without_dropping(&self, address: ObjectPointer) -> Value {
        match &self.get(address).data {
            ObjectData::Int(int) => Value::Int(*int),
            ObjectData::Text(text) => Value::Text(text.clone()),
            ObjectData::Symbol(symbol) => Value::Symbol(symbol.clone()),
            ObjectData::Struct(struct_) => {
                let mut entries = im::HashMap::new();
                for (key, value) in struct_ {
                    let key = self.export_without_dropping(*key);
                    let value = self.export_without_dropping(*value);
                    entries.insert(key, value);
                }
                Value::Struct(entries)
            }
            ObjectData::Closure { captured, body } => Value::Closure {
                captured: captured.clone(),
                body: *body,
            },
        }
    }
}
<commit_msg>Fix importing of closures<commit_after>use log::trace;

use super::value::Value;
use crate::compiler::lir::ChunkIndex;
use std::collections::HashMap;

#[derive(Debug)]
pub struct Heap {
    objects: HashMap<ObjectPointer, Object>,
    next_address: ObjectPointer,
}

pub type ObjectPointer = usize;

#[derive(Debug, Clone)] // TODO: remove Clone once it's no longer needed
pub struct Object {
    reference_count: usize,
    pub data: ObjectData,
}
#[derive(Clone, Debug)] // TODO: remove Clone once it's no longer needed
pub enum ObjectData {
    Int(u64),
    Text(String),
    Symbol(String),
    Struct(HashMap<ObjectPointer, ObjectPointer>),
    Closure {
        captured: Vec<ObjectPointer>,
        body: ChunkIndex,
    },
}

impl Heap {
    pub fn new() -> Self {
        Self {
            objects: HashMap::new(),
            next_address: 0,
        }
    }

    pub fn get(&self, address: ObjectPointer) -> &Object {
        self.objects
            .get(&address)
            .expect(&format!("Couldn't get object {}.", address))
    }
    pub fn get_mut(&mut self, address: ObjectPointer) -> &mut Object {
        self.objects
            .get_mut(&address)
            .expect(&format!("Couldn't get object {}.", address))
    }

    pub fn dup(&mut self, address: ObjectPointer) {
        self.get_mut(address).reference_count += 1;
        trace!(
            "RefCount of {} increased to {}. Value: {}",
            address,
            self.get(address).reference_count,
            self.export_without_dropping(address),
        );
    }
    pub fn drop(&mut self, address: ObjectPointer) {
        let value = self.export_without_dropping(address); // TODO: Only for logging
        let object = self.get_mut(address);
        object.reference_count -= 1;
        trace!(
            "RefCount of {} reduced to {}. Value: {}",
            address,
            object.reference_count,
            value,
        );
        if object.reference_count == 0 {
            self.free(address);
        }
    }

    pub fn create(&mut self, object: ObjectData) -> ObjectPointer {
        let address = self.next_address;
        trace!("Creating object {:?} at {}.", object, address);
        // TODO: Remove this special case once closures are self-contained.
        if let ObjectData::Closure { captured, .. } = &object {
            for captured in captured {
                self.dup(*captured);
            }
        }
        self.objects.insert(
            address,
            Object {
                reference_count: 1,
                data: object,
            },
        );
        self.next_address += 1;
        address
    }
    pub fn free(&mut self, address: ObjectPointer) {
        let object = self.objects.remove(&address).unwrap();
        trace!("Freeing object {:?} at {}.", object, address);
        assert_eq!(object.reference_count, 0);
        match object.data {
            ObjectData::Int(_) => {}
            ObjectData::Text(_) => {}
            ObjectData::Symbol(_) => {}
            ObjectData::Struct(entries) => {
                for (key, value) in entries {
                    self.drop(key);
                    self.drop(value);
                }
            }
            ObjectData::Closure { captured, .. } => {
                for object in captured {
                    self.drop(object);
                }
            }
        }
    }

    pub(super) fn import(&mut self, value: Value) -> ObjectPointer {
        let value = match value {
            Value::Int(int) => ObjectData::Int(int),
            Value::Text(text) => ObjectData::Text(text),
            Value::Symbol(symbol) => ObjectData::Symbol(symbol),
            Value::Struct(struct_) => {
                let mut entries = HashMap::new();
                for (key, value) in struct_ {
                    let key = self.import(key);
                    let value = self.import(value);
                    entries.insert(key, value);
                }
                ObjectData::Struct(entries)
            }
            Value::Closure { captured, body } => ObjectData::Closure { captured, body },
        };
        self.create(value)
    }
    pub(super) fn export(&mut self, address: ObjectPointer) -> Value {
        let value = self.export_without_dropping(address);
        self.drop(address);
        value
    }
    pub fn export_without_dropping(&self, address: ObjectPointer) -> Value {
        match &self.get(address).data {
            ObjectData::Int(int) => Value::Int(*int),
            ObjectData::Text(text) => Value::Text(text.clone()),
            ObjectData::Symbol(symbol) => Value::Symbol(symbol.clone()),
            ObjectData::Struct(struct_) => {
                let mut entries = im::HashMap::new();
                for (key, value) in struct_ {
                    let key = self.export_without_dropping(*key);
                    let value = self.export_without_dropping(*value);
                    entries.insert(key, value);
                }
                Value::Struct(entries)
            }
            ObjectData::Closure { captured, body } => Value::Closure {
                captured: captured.clone(),
                body: *body,
            },
        }
    }
}
<|endoftext|>


<commit_before>use std::{cmp, mem, raw};
use {Vector, Bitcast};

pub unsafe trait Convert<Out> {
    fn convert(self) -> Out;
}

unsafe impl<'a, In, Out> Convert<&'a [Out]> for &'a [In]
    where In: Vector, Out: Vector,
          <In as Vector>::Item: Bitcast<<Out as Vector>::Item> {
        #[inline]
        fn convert(self) -> &'a [Out] {
            // we need to ensure that the pointer has valid alignment
            // and that the slice has correct length to fit `Out`s
            // exactly; the first checks in each `assert` are
            // statically checkable, and so hopefully results in the
            // asserts being removed for "downcasts" (e.g. [u32x4] to
            // [u32]).
            assert!(mem::align_of::<In>() >= mem::align_of::<Out>() ||
                    self.as_ptr() as usize % mem::align_of::<Out>() == 0);
            assert!(mem::size_of::<In>() % mem::size_of::<Out>() == 0 ||
                    (self.len() * Vector::count(None::<In>)) % Vector::count(None::<Out>) == 0);

            unsafe {
                mem::transmute(raw::Slice {
                    data: self.as_ptr() as *mut Out,
                    len: self.len() * Vector::count(None::<In>) / Vector::count(None::<Out>)
                })
            }
        }
}
unsafe impl<'a, In, Out> Convert<&'a mut [Out]> for &'a mut [In]
    where In: Vector, Out: Vector,
          <In as Vector>::Item: Bitcast<<Out as Vector>::Item> {
        #[inline]
        fn convert(self) -> &'a mut [Out] {
            // we need to ensure that the pointer has valid alignment
            // and that the slice has correct length to fit `Out`s
            // exactly; the first checks in each `assert` are
            // statically checkable, and so hopefully results in the
            // asserts being removed for "downcasts" (e.g. [u32x4] to
            // [u32]).
            assert!(mem::align_of::<In>() >= mem::align_of::<Out>() ||
                    self.as_ptr() as usize % mem::align_of::<Out>() == 0);
            assert!(mem::size_of::<In>() % mem::size_of::<Out>() == 0 ||
                    (self.len() * Vector::count(None::<In>)) % Vector::count(None::<Out>) == 0);

            unsafe {
                mem::transmute(raw::Slice {
                    data: self.as_ptr() as *mut Out,
                    len: self.len() * Vector::count(None::<In>) / Vector::count(None::<Out>)
                })
            }
        }
}

/// A type that repesents a `&[U]` converted from a `&[T]`, where the
/// conversion may be forced to leave leading/trailing elements (due
/// to alignment/size mismatches).
pub struct Tails<'a,T:'a,U:'a> {
    pub start: &'a [T],
    pub middle: &'a [U],
    pub end: &'a [T],
}
/// A type that repesents a `&mut [U]` converted from a `&mut [T]`,
/// where the conversion may be forced to leave leading/trailing
/// elements (due to alignment/size mismatches).
pub struct TailsMut<'a,T:'a,U:'a> {
    pub start: &'a mut [T],
    pub middle: &'a mut [U],
    pub end: &'a mut [T],
}

unsafe impl<'a, In, Out> Convert<Tails<'a, In, Out>> for &'a [In]
    where In: Vector, Out: Vector,
          <In as Vector>::Item: Bitcast<<Out as Vector>::Item>
{
    #[inline]
    fn convert(self) -> Tails<'a,In,Out> {
        let isize = mem::size_of::<In>();
        let osize = mem::size_of::<Out>();
        let oalign = mem::align_of::<Out>();

        let start = self.as_ptr() as usize;
        let len = self.len();

        let offset = start % oalign;
        let slen = if offset == 0 {
            0
        } else {
            cmp::min(len, (oalign - offset) / isize)
        };
        let remaining = len - slen;
        let mlen_in_outs = remaining * isize / osize;
        let mlen_in_ins = mlen_in_outs * osize / isize;

        let (initial, tail) = self.split_at(slen);
        Tails {
            start: initial,
            middle: unsafe {mem::transmute(raw::Slice {
                data: tail.as_ptr() as *mut Out,
                len: mlen_in_outs,
            })},
            end: &tail[mlen_in_ins..]
        }
    }
}
unsafe impl<'a, In, Out> Convert<TailsMut<'a, In, Out>> for &'a mut [In]
    where In: Vector, Out: Vector,
          <In as Vector>::Item: Bitcast<<Out as Vector>::Item>
{
    #[inline]
    fn convert(self) -> TailsMut<'a,In,Out> {
        let isize = mem::size_of::<In>();
        let osize = mem::size_of::<Out>();
        let oalign = mem::align_of::<Out>();

        let start = self.as_ptr() as usize;
        let len = self.len();

        let offset = start % oalign;
        let slen = if offset == 0 {
            0
        } else {
            cmp::min(len, (oalign - offset) / isize)
        };
        let remaining = len - slen;

        let mlen_in_outs = remaining * isize / osize;
        let mlen_in_ins = mlen_in_outs * osize / isize;

        let (start, tail) = self.split_at_mut(slen);
        TailsMut {
            start: start,
            middle: unsafe {mem::transmute(raw::Slice {
                data: tail.as_ptr() as *mut Out,
                len: mlen_in_outs,
            })},
            end: &mut tail[mlen_in_ins..]
        }
    }
}
<commit_msg>Implement Copy/Clone for Tails.<commit_after>use std::{cmp, mem, raw};
use {Vector, Bitcast};

pub unsafe trait Convert<Out> {
    fn convert(self) -> Out;
}

unsafe impl<'a, In, Out> Convert<&'a [Out]> for &'a [In]
    where In: Vector, Out: Vector,
          <In as Vector>::Item: Bitcast<<Out as Vector>::Item> {
        #[inline]
        fn convert(self) -> &'a [Out] {
            // we need to ensure that the pointer has valid alignment
            // and that the slice has correct length to fit `Out`s
            // exactly; the first checks in each `assert` are
            // statically checkable, and so hopefully results in the
            // asserts being removed for "downcasts" (e.g. [u32x4] to
            // [u32]).
            assert!(mem::align_of::<In>() >= mem::align_of::<Out>() ||
                    self.as_ptr() as usize % mem::align_of::<Out>() == 0);
            assert!(mem::size_of::<In>() % mem::size_of::<Out>() == 0 ||
                    (self.len() * Vector::count(None::<In>)) % Vector::count(None::<Out>) == 0);

            unsafe {
                mem::transmute(raw::Slice {
                    data: self.as_ptr() as *mut Out,
                    len: self.len() * Vector::count(None::<In>) / Vector::count(None::<Out>)
                })
            }
        }
}
unsafe impl<'a, In, Out> Convert<&'a mut [Out]> for &'a mut [In]
    where In: Vector, Out: Vector,
          <In as Vector>::Item: Bitcast<<Out as Vector>::Item> {
        #[inline]
        fn convert(self) -> &'a mut [Out] {
            // we need to ensure that the pointer has valid alignment
            // and that the slice has correct length to fit `Out`s
            // exactly; the first checks in each `assert` are
            // statically checkable, and so hopefully results in the
            // asserts being removed for "downcasts" (e.g. [u32x4] to
            // [u32]).
            assert!(mem::align_of::<In>() >= mem::align_of::<Out>() ||
                    self.as_ptr() as usize % mem::align_of::<Out>() == 0);
            assert!(mem::size_of::<In>() % mem::size_of::<Out>() == 0 ||
                    (self.len() * Vector::count(None::<In>)) % Vector::count(None::<Out>) == 0);

            unsafe {
                mem::transmute(raw::Slice {
                    data: self.as_ptr() as *mut Out,
                    len: self.len() * Vector::count(None::<In>) / Vector::count(None::<Out>)
                })
            }
        }
}

/// A type that repesents a `&[U]` converted from a `&[T]`, where the
/// conversion may be forced to leave leading/trailing elements (due
/// to alignment/size mismatches).
pub struct Tails<'a,T:'a,U:'a> {
    pub start: &'a [T],
    pub middle: &'a [U],
    pub end: &'a [T],
}
impl<'a, T, U> Copy for Tails<'a, T, U> {}
impl<'a, T, U> Clone for Tails<'a, T, U> {
    fn clone(&self) -> Tails<'a, T, U> { *self }
}

/// A type that repesents a `&mut [U]` converted from a `&mut [T]`,
/// where the conversion may be forced to leave leading/trailing
/// elements (due to alignment/size mismatches).
pub struct TailsMut<'a,T:'a,U:'a> {
    pub start: &'a mut [T],
    pub middle: &'a mut [U],
    pub end: &'a mut [T],
}

unsafe impl<'a, In, Out> Convert<Tails<'a, In, Out>> for &'a [In]
    where In: Vector, Out: Vector,
          <In as Vector>::Item: Bitcast<<Out as Vector>::Item>
{
    #[inline]
    fn convert(self) -> Tails<'a,In,Out> {
        let isize = mem::size_of::<In>();
        let osize = mem::size_of::<Out>();
        let oalign = mem::align_of::<Out>();

        let start = self.as_ptr() as usize;
        let len = self.len();

        let offset = start % oalign;
        let slen = if offset == 0 {
            0
        } else {
            cmp::min(len, (oalign - offset) / isize)
        };
        let remaining = len - slen;
        let mlen_in_outs = remaining * isize / osize;
        let mlen_in_ins = mlen_in_outs * osize / isize;

        let (initial, tail) = self.split_at(slen);
        Tails {
            start: initial,
            middle: unsafe {mem::transmute(raw::Slice {
                data: tail.as_ptr() as *mut Out,
                len: mlen_in_outs,
            })},
            end: &tail[mlen_in_ins..]
        }
    }
}
unsafe impl<'a, In, Out> Convert<TailsMut<'a, In, Out>> for &'a mut [In]
    where In: Vector, Out: Vector,
          <In as Vector>::Item: Bitcast<<Out as Vector>::Item>
{
    #[inline]
    fn convert(self) -> TailsMut<'a,In,Out> {
        let isize = mem::size_of::<In>();
        let osize = mem::size_of::<Out>();
        let oalign = mem::align_of::<Out>();

        let start = self.as_ptr() as usize;
        let len = self.len();

        let offset = start % oalign;
        let slen = if offset == 0 {
            0
        } else {
            cmp::min(len, (oalign - offset) / isize)
        };
        let remaining = len - slen;

        let mlen_in_outs = remaining * isize / osize;
        let mlen_in_ins = mlen_in_outs * osize / isize;

        let (start, tail) = self.split_at_mut(slen);
        TailsMut {
            start: start,
            middle: unsafe {mem::transmute(raw::Slice {
                data: tail.as_ptr() as *mut Out,
                len: mlen_in_outs,
            })},
            end: &mut tail[mlen_in_ins..]
        }
    }
}
<|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/. */

//! Calculate [specified][specified] and [computed values][computed] from a
//! tree of DOM nodes and a set of stylesheets.
//!
//! [computed]: https://drafts.csswg.org/css-cascade/#computed
//! [specified]: https://drafts.csswg.org/css-cascade/#specified
//!
//! In particular, this crate contains the definitions of supported properties,
//! the code to parse them into specified values and calculate the computed
//! values based on the specified values, as well as the code to serialize both
//! specified and computed values.
//!
//! The main entry point is [`recalc_style_at`][recalc_style_at].
//!
//! [recalc_style_at]: traversal/fn.recalc_style_at.html
//!
//! Major dependencies are the [cssparser][cssparser] and [selectors][selectors]
//! crates.
//!
//! [cssparser]: ../cssparser/index.html
//! [selectors]: ../selectors/index.html

#![cfg_attr(feature = "servo", feature(proc_macro))]

#![deny(warnings)]

// FIXME(bholley): We need to blanket-allow unsafe code in order to make the
// gecko atom!() macro work. When Rust 1.14 is released [1], we can uncomment
// the commented-out attributes in regen_atoms.py and go back to denying unsafe
// code by default.
//
// [1] https://github.com/rust-lang/rust/issues/15701#issuecomment-251900615
//#![deny(unsafe_code)]
#![allow(unused_unsafe)]

#![recursion_limit = "500"]  // For define_css_keyword_enum! in -moz-appearance

extern crate app_units;
#[allow(unused_extern_crates)]
#[macro_use]
extern crate bitflags;
#[macro_use] #[no_link]
extern crate cfg_if;
extern crate core;
#[macro_use]
extern crate cssparser;
extern crate encoding;
extern crate euclid;
extern crate fnv;
#[cfg(feature = "gecko")] #[macro_use] pub mod gecko_string_cache;
extern crate heapsize;
#[cfg(feature = "servo")] #[macro_use] extern crate heapsize_derive;
#[cfg(feature = "servo")] #[macro_use] extern crate html5ever_atoms;
#[allow(unused_extern_crates)]
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[allow(unused_extern_crates)]
#[macro_use]
extern crate matches;
#[cfg(feature = "gecko")] extern crate nsstring_vendor as nsstring;
extern crate num_integer;
extern crate num_traits;
#[cfg(feature = "gecko")] extern crate num_cpus;
extern crate ordered_float;
extern crate owning_ref;
extern crate parking_lot;
extern crate phf;
extern crate quickersort;
extern crate rayon;
extern crate rustc_serialize;
extern crate selectors;
#[cfg(feature = "servo")]
extern crate serde;
#[cfg(feature = "servo")] #[macro_use] extern crate serde_derive;
#[cfg(feature = "servo")] #[macro_use] extern crate servo_atoms;
extern crate servo_config;
extern crate servo_url;
extern crate smallvec;
#[macro_use]
extern crate style_traits;
extern crate time;
#[allow(unused_extern_crates)]
extern crate unicode_segmentation;

pub mod animation;
#[allow(missing_docs)] // TODO: Under a rewrite.
pub mod atomic_refcell;
pub mod attr;
pub mod bezier;
pub mod bloom;
pub mod cache;
pub mod cascade_info;
pub mod context;
pub mod custom_properties;
pub mod data;
pub mod dom;
pub mod element_state;
pub mod error_reporting;
pub mod font_face;
pub mod font_metrics;
#[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko;
#[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko_bindings;
pub mod keyframes;
#[allow(missing_docs)] // TODO.
pub mod logical_geometry;
pub mod matching;
#[allow(missing_docs)]
pub mod media_queries;
pub mod owning_handle;
pub mod parallel;
pub mod parser;
pub mod restyle_hints;
pub mod rule_tree;
pub mod scoped_tls;
pub mod selector_parser;
pub mod stylist;
#[cfg(feature = "servo")] #[allow(unsafe_code)] pub mod servo;
pub mod sequential;
pub mod sink;
pub mod str;
pub mod stylesheets;
pub mod thread_state;
pub mod timer;
pub mod traversal;
#[macro_use]
#[allow(non_camel_case_types)]
pub mod values;
pub mod viewport;

use std::fmt;
use std::sync::Arc;
use style_traits::ToCss;

#[cfg(feature = "gecko")] pub use gecko_string_cache as string_cache;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Atom;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Namespace;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Atom as Prefix;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Atom as LocalName;

#[cfg(feature = "servo")] pub use servo_atoms::Atom;
#[cfg(feature = "servo")] pub use html5ever_atoms::Prefix;
#[cfg(feature = "servo")] pub use html5ever_atoms::LocalName;
#[cfg(feature = "servo")] pub use html5ever_atoms::Namespace;

/// The CSS properties supported by the style system.
// Generated from the properties.mako.rs template by build.rs
#[macro_use]
#[allow(unsafe_code)]
#[deny(missing_docs)]
pub mod properties {
    include!(concat!(env!("OUT_DIR"), "/properties.rs"));
}

#[cfg(feature = "gecko")]
#[allow(unsafe_code)]
pub mod gecko_properties {
    include!(concat!(env!("OUT_DIR"), "/gecko_properties.rs"));
}

macro_rules! reexport_computed_values {
    ( $( $name: ident )+ ) => {
        /// Types for [computed values][computed].
        ///
        /// [computed]: https://drafts.csswg.org/css-cascade/#computed
        pub mod computed_values {
            $(
                pub use properties::longhands::$name::computed_value as $name;
            )+
            // Don't use a side-specific name needlessly:
            pub use properties::longhands::border_top_style::computed_value as border_style;
        }
    }
}
longhand_properties_idents!(reexport_computed_values);

/// Returns whether the two arguments point to the same value.
#[inline]
pub fn arc_ptr_eq<T: 'static>(a: &Arc<T>, b: &Arc<T>) -> bool {
    let a: &T = &**a;
    let b: &T = &**b;
    (a as *const T) == (b as *const T)
}

/// Serializes as CSS a comma-separated list of any `T` that supports being
/// serialized as CSS.
pub fn serialize_comma_separated_list<W, T>(dest: &mut W,
                                            list: &[T])
                                            -> fmt::Result
    where W: fmt::Write,
          T: ToCss,
{
    if list.is_empty() {
        return Ok(());
    }

    try!(list[0].to_css(dest));

    for item in list.iter().skip(1) {
        try!(write!(dest, ", "));
        try!(item.to_css(dest));
    }

    Ok(())
}
<commit_msg>style: Allow the attr module to be without documentation, for now.<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/. */

//! Calculate [specified][specified] and [computed values][computed] from a
//! tree of DOM nodes and a set of stylesheets.
//!
//! [computed]: https://drafts.csswg.org/css-cascade/#computed
//! [specified]: https://drafts.csswg.org/css-cascade/#specified
//!
//! In particular, this crate contains the definitions of supported properties,
//! the code to parse them into specified values and calculate the computed
//! values based on the specified values, as well as the code to serialize both
//! specified and computed values.
//!
//! The main entry point is [`recalc_style_at`][recalc_style_at].
//!
//! [recalc_style_at]: traversal/fn.recalc_style_at.html
//!
//! Major dependencies are the [cssparser][cssparser] and [selectors][selectors]
//! crates.
//!
//! [cssparser]: ../cssparser/index.html
//! [selectors]: ../selectors/index.html

#![cfg_attr(feature = "servo", feature(proc_macro))]

#![deny(warnings)]

// FIXME(bholley): We need to blanket-allow unsafe code in order to make the
// gecko atom!() macro work. When Rust 1.14 is released [1], we can uncomment
// the commented-out attributes in regen_atoms.py and go back to denying unsafe
// code by default.
//
// [1] https://github.com/rust-lang/rust/issues/15701#issuecomment-251900615
//#![deny(unsafe_code)]
#![allow(unused_unsafe)]

#![recursion_limit = "500"]  // For define_css_keyword_enum! in -moz-appearance

extern crate app_units;
#[allow(unused_extern_crates)]
#[macro_use]
extern crate bitflags;
#[macro_use] #[no_link]
extern crate cfg_if;
extern crate core;
#[macro_use]
extern crate cssparser;
extern crate encoding;
extern crate euclid;
extern crate fnv;
#[cfg(feature = "gecko")] #[macro_use] pub mod gecko_string_cache;
extern crate heapsize;
#[cfg(feature = "servo")] #[macro_use] extern crate heapsize_derive;
#[cfg(feature = "servo")] #[macro_use] extern crate html5ever_atoms;
#[allow(unused_extern_crates)]
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[allow(unused_extern_crates)]
#[macro_use]
extern crate matches;
#[cfg(feature = "gecko")] extern crate nsstring_vendor as nsstring;
extern crate num_integer;
extern crate num_traits;
#[cfg(feature = "gecko")] extern crate num_cpus;
extern crate ordered_float;
extern crate owning_ref;
extern crate parking_lot;
extern crate phf;
extern crate quickersort;
extern crate rayon;
extern crate rustc_serialize;
extern crate selectors;
#[cfg(feature = "servo")]
extern crate serde;
#[cfg(feature = "servo")] #[macro_use] extern crate serde_derive;
#[cfg(feature = "servo")] #[macro_use] extern crate servo_atoms;
extern crate servo_config;
extern crate servo_url;
extern crate smallvec;
#[macro_use]
extern crate style_traits;
extern crate time;
#[allow(unused_extern_crates)]
extern crate unicode_segmentation;

pub mod animation;
#[allow(missing_docs)] // TODO: Under a rewrite.
pub mod atomic_refcell;
#[allow(missing_docs)] // TODO.
pub mod attr;
pub mod bezier;
pub mod bloom;
pub mod cache;
pub mod cascade_info;
pub mod context;
pub mod custom_properties;
pub mod data;
pub mod dom;
pub mod element_state;
pub mod error_reporting;
pub mod font_face;
pub mod font_metrics;
#[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko;
#[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko_bindings;
pub mod keyframes;
#[allow(missing_docs)] // TODO.
pub mod logical_geometry;
pub mod matching;
#[allow(missing_docs)]
pub mod media_queries;
pub mod owning_handle;
pub mod parallel;
pub mod parser;
pub mod restyle_hints;
pub mod rule_tree;
pub mod scoped_tls;
pub mod selector_parser;
pub mod stylist;
#[cfg(feature = "servo")] #[allow(unsafe_code)] pub mod servo;
pub mod sequential;
pub mod sink;
pub mod str;
pub mod stylesheets;
pub mod thread_state;
pub mod timer;
pub mod traversal;
#[macro_use]
#[allow(non_camel_case_types)]
pub mod values;
pub mod viewport;

use std::fmt;
use std::sync::Arc;
use style_traits::ToCss;

#[cfg(feature = "gecko")] pub use gecko_string_cache as string_cache;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Atom;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Namespace;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Atom as Prefix;
#[cfg(feature = "gecko")] pub use gecko_string_cache::Atom as LocalName;

#[cfg(feature = "servo")] pub use servo_atoms::Atom;
#[cfg(feature = "servo")] pub use html5ever_atoms::Prefix;
#[cfg(feature = "servo")] pub use html5ever_atoms::LocalName;
#[cfg(feature = "servo")] pub use html5ever_atoms::Namespace;

/// The CSS properties supported by the style system.
// Generated from the properties.mako.rs template by build.rs
#[macro_use]
#[allow(unsafe_code)]
#[deny(missing_docs)]
pub mod properties {
    include!(concat!(env!("OUT_DIR"), "/properties.rs"));
}

#[cfg(feature = "gecko")]
#[allow(unsafe_code)]
pub mod gecko_properties {
    include!(concat!(env!("OUT_DIR"), "/gecko_properties.rs"));
}

macro_rules! reexport_computed_values {
    ( $( $name: ident )+ ) => {
        /// Types for [computed values][computed].
        ///
        /// [computed]: https://drafts.csswg.org/css-cascade/#computed
        pub mod computed_values {
            $(
                pub use properties::longhands::$name::computed_value as $name;
            )+
            // Don't use a side-specific name needlessly:
            pub use properties::longhands::border_top_style::computed_value as border_style;
        }
    }
}
longhand_properties_idents!(reexport_computed_values);

/// Returns whether the two arguments point to the same value.
#[inline]
pub fn arc_ptr_eq<T: 'static>(a: &Arc<T>, b: &Arc<T>) -> bool {
    let a: &T = &**a;
    let b: &T = &**b;
    (a as *const T) == (b as *const T)
}

/// Serializes as CSS a comma-separated list of any `T` that supports being
/// serialized as CSS.
pub fn serialize_comma_separated_list<W, T>(dest: &mut W,
                                            list: &[T])
                                            -> fmt::Result
    where W: fmt::Write,
          T: ToCss,
{
    if list.is_empty() {
        return Ok(());
    }

    try!(list[0].to_css(dest));

    for item in list.iter().skip(1) {
        try!(write!(dest, ", "));
        try!(item.to_css(dest));
    }

    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use crate::{wrap_descriptor, AsRawDescriptor, MappedRegion, MmapError, Protection, SharedMemory};
use data_model::volatile_memory::*;
use data_model::DataInit;
use std::fs::File;
use sys_util::MemoryMapping as SysUtilMmap;

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

/// See [MemoryMapping](sys_util::MemoryMapping) for struct- and method-level
/// documentation.
#[derive(Debug)]
pub struct MemoryMapping {
    mapping: SysUtilMmap,
}

impl MemoryMapping {
    pub fn write_slice(&self, buf: &[u8], offset: usize) -> Result<usize> {
        self.mapping.write_slice(buf, offset)
    }

    pub fn read_slice(&self, buf: &mut [u8], offset: usize) -> Result<usize> {
        self.mapping.read_slice(buf, offset)
    }

    pub fn write_obj<T: DataInit>(&self, val: T, offset: usize) -> Result<()> {
        self.mapping.write_obj(val, offset)
    }

    pub fn read_obj<T: DataInit>(&self, offset: usize) -> Result<T> {
        self.mapping.read_obj(offset)
    }

    pub fn msync(&self) -> Result<()> {
        self.mapping.msync()
    }

    pub fn use_hugepages(&self) -> Result<()> {
        self.mapping.use_hugepages()
    }

    pub fn read_to_memory(
        &self,
        mem_offset: usize,
        src: &dyn AsRawDescriptor,
        count: usize,
    ) -> Result<()> {
        self.mapping
            .read_to_memory(mem_offset, &wrap_descriptor(src), count)
    }

    pub fn write_from_memory(
        &self,
        mem_offset: usize,
        dst: &dyn AsRawDescriptor,
        count: usize,
    ) -> Result<()> {
        self.mapping
            .write_from_memory(mem_offset, &wrap_descriptor(dst), count)
    }
}

pub trait Unix {
    fn remove_range(&self, mem_offset: usize, count: usize) -> Result<()>;
}

impl Unix for MemoryMapping {
    fn remove_range(&self, mem_offset: usize, count: usize) -> Result<()> {
        self.mapping.remove_range(mem_offset, count)
    }
}

pub trait MemoryMappingBuilderUnix<'a> {
    #[allow(clippy::wrong_self_convention)]
    fn from_descriptor(self, descriptor: &'a dyn AsRawDescriptor) -> MemoryMappingBuilder;
}

pub struct MemoryMappingBuilder<'a> {
    descriptor: Option<&'a dyn AsRawDescriptor>,
    size: usize,
    offset: Option<u64>,
    protection: Option<Protection>,
    populate: bool,
}

impl<'a> MemoryMappingBuilderUnix<'a> for MemoryMappingBuilder<'a> {
    /// Build the memory mapping given the specified descriptor to mapped memory
    ///
    /// Default: Create a new memory mapping.
    #[allow(clippy::wrong_self_convention)]
    fn from_descriptor(mut self, descriptor: &'a dyn AsRawDescriptor) -> MemoryMappingBuilder {
        self.descriptor = Some(descriptor);
        self
    }
}

/// Builds a MemoryMapping object from the specified arguments.
impl<'a> MemoryMappingBuilder<'a> {
    /// Creates a new builder specifying size of the memory region in bytes.
    pub fn new(size: usize) -> MemoryMappingBuilder<'a> {
        MemoryMappingBuilder {
            descriptor: None,
            size,
            offset: None,
            protection: None,
            populate: false,
        }
    }

    /// Build the memory mapping given the specified File to mapped memory
    ///
    /// Default: Create a new memory mapping.
    ///
    /// Note: this is a forward looking interface to accomodate platforms that
    /// require special handling for file backed mappings.
    #[allow(clippy::wrong_self_convention, unused_mut)]
    pub fn from_file(mut self, file: &'a File) -> MemoryMappingBuilder {
        self.descriptor = Some(file as &dyn AsRawDescriptor);
        self
    }

    /// Build the memory mapping given the specified SharedMemory to mapped memory
    ///
    /// Default: Create a new memory mapping.
    pub fn from_shared_memory(mut self, shm: &'a SharedMemory) -> MemoryMappingBuilder {
        self.descriptor = Some(shm as &dyn AsRawDescriptor);
        self
    }

    /// Offset in bytes from the beginning of the mapping to start the mmap.
    ///
    /// Default: No offset
    pub fn offset(mut self, offset: u64) -> MemoryMappingBuilder<'a> {
        self.offset = Some(offset);
        self
    }

    /// Protection (e.g. readable/writable) of the memory region.
    ///
    /// Default: Read/write
    pub fn protection(mut self, protection: Protection) -> MemoryMappingBuilder<'a> {
        self.protection = Some(protection);
        self
    }

    /// Request that the mapped pages are pre-populated
    ///
    /// Default: Do not populate
    pub fn populate(mut self) -> MemoryMappingBuilder<'a> {
        self.populate = true;
        self
    }

    /// Build a MemoryMapping from the provided options.
    pub fn build(self) -> Result<MemoryMapping> {
        match self.descriptor {
            None => {
                if self.populate {
                    // Population not supported for new mmaps
                    return Err(MmapError::InvalidArgument);
                }
                MemoryMappingBuilder::wrap(SysUtilMmap::new_protection(
                    self.size,
                    self.protection.unwrap_or_else(Protection::read_write),
                ))
            }
            Some(descriptor) => {
                MemoryMappingBuilder::wrap(SysUtilMmap::from_fd_offset_protection_populate(
                    &wrap_descriptor(descriptor),
                    self.size,
                    self.offset.unwrap_or(0),
                    self.protection.unwrap_or_else(Protection::read_write),
                    self.populate,
                ))
            }
        }
    }

    /// Build a MemoryMapping from the provided options at a fixed address. Note this
    /// is a separate function from build in order to isolate unsafe behavior.
    ///
    /// # Safety
    ///
    /// Function should not be called before the caller unmaps any mmap'd regions already
    /// present at `(addr..addr+size)`. If another MemoryMapping object holds the same
    /// address space, the destructors of those objects will conflict and the space could
    /// be unmapped while still in use.
    pub unsafe fn build_fixed(self, addr: *mut u8) -> Result<MemoryMapping> {
        if self.populate {
            // Population not supported for fixed mapping.
            return Err(MmapError::InvalidArgument);
        }
        match self.descriptor {
            None => MemoryMappingBuilder::wrap(SysUtilMmap::new_protection_fixed(
                addr,
                self.size,
                self.protection.unwrap_or_else(Protection::read_write),
            )),
            Some(descriptor) => {
                MemoryMappingBuilder::wrap(SysUtilMmap::from_fd_offset_protection_fixed(
                    addr,
                    &wrap_descriptor(descriptor),
                    self.size,
                    self.offset.unwrap_or(0),
                    self.protection.unwrap_or_else(Protection::read_write),
                ))
            }
        }
    }

    fn wrap(result: Result<SysUtilMmap>) -> Result<MemoryMapping> {
        result.map(|mapping| MemoryMapping { mapping })
    }
}

impl VolatileMemory for MemoryMapping {
    fn get_slice(&self, offset: usize, count: usize) -> VolatileMemoryResult<VolatileSlice> {
        self.mapping.get_slice(offset, count)
    }
}

// Safe because it exclusively forwards calls to a safe implementation.
unsafe impl MappedRegion for MemoryMapping {
    fn as_ptr(&self) -> *mut u8 {
        self.mapping.as_ptr()
    }

    fn size(&self) -> usize {
        self.mapping.size()
    }
}
<commit_msg>base: allow creating Arena from base::MemoryMapping<commit_after>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use crate::{
    wrap_descriptor, AsRawDescriptor, MappedRegion, MemoryMappingArena, MmapError, Protection,
    SharedMemory,
};
use data_model::volatile_memory::*;
use data_model::DataInit;
use std::fs::File;
use sys_util::MemoryMapping as SysUtilMmap;

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

/// See [MemoryMapping](sys_util::MemoryMapping) for struct- and method-level
/// documentation.
#[derive(Debug)]
pub struct MemoryMapping {
    mapping: SysUtilMmap,
}

impl MemoryMapping {
    pub fn write_slice(&self, buf: &[u8], offset: usize) -> Result<usize> {
        self.mapping.write_slice(buf, offset)
    }

    pub fn read_slice(&self, buf: &mut [u8], offset: usize) -> Result<usize> {
        self.mapping.read_slice(buf, offset)
    }

    pub fn write_obj<T: DataInit>(&self, val: T, offset: usize) -> Result<()> {
        self.mapping.write_obj(val, offset)
    }

    pub fn read_obj<T: DataInit>(&self, offset: usize) -> Result<T> {
        self.mapping.read_obj(offset)
    }

    pub fn msync(&self) -> Result<()> {
        self.mapping.msync()
    }

    pub fn use_hugepages(&self) -> Result<()> {
        self.mapping.use_hugepages()
    }

    pub fn read_to_memory(
        &self,
        mem_offset: usize,
        src: &dyn AsRawDescriptor,
        count: usize,
    ) -> Result<()> {
        self.mapping
            .read_to_memory(mem_offset, &wrap_descriptor(src), count)
    }

    pub fn write_from_memory(
        &self,
        mem_offset: usize,
        dst: &dyn AsRawDescriptor,
        count: usize,
    ) -> Result<()> {
        self.mapping
            .write_from_memory(mem_offset, &wrap_descriptor(dst), count)
    }
}

pub trait Unix {
    fn remove_range(&self, mem_offset: usize, count: usize) -> Result<()>;
}

impl Unix for MemoryMapping {
    fn remove_range(&self, mem_offset: usize, count: usize) -> Result<()> {
        self.mapping.remove_range(mem_offset, count)
    }
}

pub trait MemoryMappingBuilderUnix<'a> {
    #[allow(clippy::wrong_self_convention)]
    fn from_descriptor(self, descriptor: &'a dyn AsRawDescriptor) -> MemoryMappingBuilder;
}

pub struct MemoryMappingBuilder<'a> {
    descriptor: Option<&'a dyn AsRawDescriptor>,
    size: usize,
    offset: Option<u64>,
    protection: Option<Protection>,
    populate: bool,
}

impl<'a> MemoryMappingBuilderUnix<'a> for MemoryMappingBuilder<'a> {
    /// Build the memory mapping given the specified descriptor to mapped memory
    ///
    /// Default: Create a new memory mapping.
    #[allow(clippy::wrong_self_convention)]
    fn from_descriptor(mut self, descriptor: &'a dyn AsRawDescriptor) -> MemoryMappingBuilder {
        self.descriptor = Some(descriptor);
        self
    }
}

/// Builds a MemoryMapping object from the specified arguments.
impl<'a> MemoryMappingBuilder<'a> {
    /// Creates a new builder specifying size of the memory region in bytes.
    pub fn new(size: usize) -> MemoryMappingBuilder<'a> {
        MemoryMappingBuilder {
            descriptor: None,
            size,
            offset: None,
            protection: None,
            populate: false,
        }
    }

    /// Build the memory mapping given the specified File to mapped memory
    ///
    /// Default: Create a new memory mapping.
    ///
    /// Note: this is a forward looking interface to accomodate platforms that
    /// require special handling for file backed mappings.
    #[allow(clippy::wrong_self_convention, unused_mut)]
    pub fn from_file(mut self, file: &'a File) -> MemoryMappingBuilder {
        self.descriptor = Some(file as &dyn AsRawDescriptor);
        self
    }

    /// Build the memory mapping given the specified SharedMemory to mapped memory
    ///
    /// Default: Create a new memory mapping.
    pub fn from_shared_memory(mut self, shm: &'a SharedMemory) -> MemoryMappingBuilder {
        self.descriptor = Some(shm as &dyn AsRawDescriptor);
        self
    }

    /// Offset in bytes from the beginning of the mapping to start the mmap.
    ///
    /// Default: No offset
    pub fn offset(mut self, offset: u64) -> MemoryMappingBuilder<'a> {
        self.offset = Some(offset);
        self
    }

    /// Protection (e.g. readable/writable) of the memory region.
    ///
    /// Default: Read/write
    pub fn protection(mut self, protection: Protection) -> MemoryMappingBuilder<'a> {
        self.protection = Some(protection);
        self
    }

    /// Request that the mapped pages are pre-populated
    ///
    /// Default: Do not populate
    pub fn populate(mut self) -> MemoryMappingBuilder<'a> {
        self.populate = true;
        self
    }

    /// Build a MemoryMapping from the provided options.
    pub fn build(self) -> Result<MemoryMapping> {
        match self.descriptor {
            None => {
                if self.populate {
                    // Population not supported for new mmaps
                    return Err(MmapError::InvalidArgument);
                }
                MemoryMappingBuilder::wrap(SysUtilMmap::new_protection(
                    self.size,
                    self.protection.unwrap_or_else(Protection::read_write),
                ))
            }
            Some(descriptor) => {
                MemoryMappingBuilder::wrap(SysUtilMmap::from_fd_offset_protection_populate(
                    &wrap_descriptor(descriptor),
                    self.size,
                    self.offset.unwrap_or(0),
                    self.protection.unwrap_or_else(Protection::read_write),
                    self.populate,
                ))
            }
        }
    }

    /// Build a MemoryMapping from the provided options at a fixed address. Note this
    /// is a separate function from build in order to isolate unsafe behavior.
    ///
    /// # Safety
    ///
    /// Function should not be called before the caller unmaps any mmap'd regions already
    /// present at `(addr..addr+size)`. If another MemoryMapping object holds the same
    /// address space, the destructors of those objects will conflict and the space could
    /// be unmapped while still in use.
    pub unsafe fn build_fixed(self, addr: *mut u8) -> Result<MemoryMapping> {
        if self.populate {
            // Population not supported for fixed mapping.
            return Err(MmapError::InvalidArgument);
        }
        match self.descriptor {
            None => MemoryMappingBuilder::wrap(SysUtilMmap::new_protection_fixed(
                addr,
                self.size,
                self.protection.unwrap_or_else(Protection::read_write),
            )),
            Some(descriptor) => {
                MemoryMappingBuilder::wrap(SysUtilMmap::from_fd_offset_protection_fixed(
                    addr,
                    &wrap_descriptor(descriptor),
                    self.size,
                    self.offset.unwrap_or(0),
                    self.protection.unwrap_or_else(Protection::read_write),
                ))
            }
        }
    }

    fn wrap(result: Result<SysUtilMmap>) -> Result<MemoryMapping> {
        result.map(|mapping| MemoryMapping { mapping })
    }
}

impl VolatileMemory for MemoryMapping {
    fn get_slice(&self, offset: usize, count: usize) -> VolatileMemoryResult<VolatileSlice> {
        self.mapping.get_slice(offset, count)
    }
}

// Safe because it exclusively forwards calls to a safe implementation.
unsafe impl MappedRegion for MemoryMapping {
    fn as_ptr(&self) -> *mut u8 {
        self.mapping.as_ptr()
    }

    fn size(&self) -> usize {
        self.mapping.size()
    }
}

impl From<MemoryMapping> for MemoryMappingArena {
    fn from(mmap: MemoryMapping) -> Self {
        MemoryMappingArena::from(mmap.mapping)
    }
}
<|endoftext|>


<commit_before>use std::io::TcpStream;

trait Data
{
    fn process_request_data(&self, mut request: TcpStream);
}
<commit_msg>Updated trait<commit_after>use std::io::TcpStream;

pub trait Data
{
    fn process_request_data(&self, mut request: TcpStream);
}
<|endoftext|>


<commit_before>use super::super::messages::{RequestMessage, Message, RequestPropose, RequestTransactions,
                             RequestPrevotes, RequestPrecommits, RequestBlock, Block};
use super::super::blockchain::{Blockchain, View};
use super::super::storage::{Map, List};
use super::super::events::Channel;
use super::{NodeHandler, ExternalMessage, NodeTimeout};

// TODO validate_heights нужно обновлять по любым сообщениям, а не только по status (если они корректно подписаны)
// TODO propose имеет смысл запрашивать только тогда, когда мы знаем, что узел находится на нашей высоте

const REQUEST_ALIVE: i64 = 3_000_000_000; // 3 seconds

impl<B, S> NodeHandler<B, S>
    where B: Blockchain,
          S: Channel<ApplicationEvent = ExternalMessage<B>, Timeout = NodeTimeout> + Clone
{
    pub fn handle_request(&mut self, msg: RequestMessage) {
        // Request are sended to us
        if msg.to() != &self.public_key {
            return;
        }

        // FIXME: we should use some epsilon for checking lifetime < 0
        let lifetime = match (self.channel.get_time() - msg.time()).num_nanoseconds() {
            Some(nanos) => nanos,
            None => {
                // Incorrect time into message
                return;
            }
        };

        // Incorrect time of the request
        if lifetime < 0 || lifetime > REQUEST_ALIVE {
            return;
        }

        if !msg.verify(msg.from()) {
            return;
        }

        match msg {
            RequestMessage::Propose(msg) => self.handle_request_propose(msg),
            RequestMessage::Transactions(msg) => self.handle_request_txs(msg),
            RequestMessage::Prevotes(msg) => self.handle_request_prevotes(msg),
            RequestMessage::Precommits(msg) => self.handle_request_precommits(msg),
            RequestMessage::Peers(msg) => self.handle_request_peers(msg),
            RequestMessage::Block(msg) => self.handle_request_block(msg),
        }
    }

    pub fn handle_request_propose(&mut self, msg: RequestPropose) {
        if msg.height() != self.state.height() {
            return;
        }

        let propose = if msg.height() == self.state.height() {
            self.state.propose(msg.propose_hash()).map(|p| p.message().raw().clone())
        } else {
            return;
        };

        if let Some(propose) = propose {
            self.send_to_peer(*msg.from(), &propose);
        }
    }

    pub fn handle_request_txs(&mut self, msg: RequestTransactions) {
        trace!("HANDLE TRANSACTIONS REQUEST!!!");
        let view = self.blockchain.view();
        for hash in msg.txs() {
            let tx = self.state
                .transactions()
                .get(hash)
                .cloned()
                .or_else(|| view.transactions().get(hash).unwrap());

            if let Some(tx) = tx {
                self.send_to_peer(*msg.from(), tx.raw());
            }
        }
    }

    pub fn handle_request_prevotes(&mut self, msg: RequestPrevotes) {
        if msg.height() != self.state.height() {
            return;
        }

        let has_prevotes = msg.validators();
        let prevotes = self.state
            .prevotes(msg.round(), *msg.propose_hash())
            .iter()
            .filter(|p| !has_prevotes[p.validator() as usize])
            .map(|p| p.raw().clone())
            .collect::<Vec<_>>();

        for prevote in &prevotes {
            self.send_to_peer(*msg.from(), prevote);
        }
    }

    pub fn handle_request_precommits(&mut self, msg: RequestPrecommits) {
        if msg.height() > self.state.height() {
            return;
        }

        let has_precommits = msg.validators();
        let precommits = self.state
            .precommits(msg.round(), *msg.propose_hash())
            .iter()
            .filter(|p| !has_precommits[p.validator() as usize])
            .map(|p| p.raw().clone())
            .collect::<Vec<_>>();

        // FIXME what about msg.height < state.height ?
        // self.blockchain
        //     .view()
        //     .precommits(msg.block_hash())
        //     .values()
        //     .unwrap()
        //     .iter()
        //     .map(|p| p.raw().clone())
        //     .collect()

        for precommit in precommits {
            self.send_to_peer(*msg.from(), &precommit);
        }
    }

    pub fn handle_request_block(&mut self, msg: RequestBlock) {
        trace!("Handle block request with height:{}, our height: {}",
               msg.height(),
               self.state.height());
        if msg.height() >= self.state.height() {
            return;
        }

        let view = self.blockchain.view();
        let height = msg.height();
        let block_hash = view.heights().get(height).unwrap().unwrap();

        let block = view.blocks().get(&block_hash).unwrap().unwrap();
        let precommits = view.precommits(&block_hash)
            .values()
            .unwrap()
            .iter()
            .cloned()
            .collect::<Vec<_>>();
        let transactions = view.block_txs(height)
            .values()
            .unwrap()
            .iter()
            .map(|tx_hash| view.transactions().get(tx_hash).unwrap().unwrap())
            .map(|p| p.raw().clone())
            .collect::<Vec<_>>();

        let block_msg = Block::new(&self.public_key,
                                   msg.from(),
                                   self.channel.get_time(),
                                   block,
                                   precommits,
                                   transactions,
                                   &self.secret_key);
        self.send_to_peer(*msg.from(), block_msg.raw());
    }
}
<commit_msg>fix issue-119<commit_after>use super::super::messages::{RequestMessage, Message, RequestPropose, RequestTransactions,
                             RequestPrevotes, RequestPrecommits, RequestBlock, Block};
use super::super::blockchain::{Blockchain, View};
use super::super::storage::{Map, List};
use super::super::events::Channel;
use super::{NodeHandler, ExternalMessage, NodeTimeout};

// TODO validate_heights нужно обновлять по любым сообщениям, а не только по status (если они корректно подписаны)
// TODO propose имеет смысл запрашивать только тогда, когда мы знаем, что узел находится на нашей высоте

const REQUEST_ALIVE: i64 = 3_000_000_000; // 3 seconds

impl<B, S> NodeHandler<B, S>
    where B: Blockchain,
          S: Channel<ApplicationEvent = ExternalMessage<B>, Timeout = NodeTimeout> + Clone
{
    pub fn handle_request(&mut self, msg: RequestMessage) {
        // Request are sended to us
        if msg.to() != &self.public_key {
            return;
        }

        // FIXME: we should use some epsilon for checking lifetime < 0
        let lifetime = match (self.channel.get_time() - msg.time()).num_nanoseconds() {
            Some(nanos) => nanos,
            None => {
                // Incorrect time into message
                return;
            }
        };

        // Incorrect time of the request
        if lifetime < 0 || lifetime > REQUEST_ALIVE {
            return;
        }

        if !msg.verify(msg.from()) {
            return;
        }

        match msg {
            RequestMessage::Propose(msg) => self.handle_request_propose(msg),
            RequestMessage::Transactions(msg) => self.handle_request_txs(msg),
            RequestMessage::Prevotes(msg) => self.handle_request_prevotes(msg),
            RequestMessage::Precommits(msg) => self.handle_request_precommits(msg),
            RequestMessage::Peers(msg) => self.handle_request_peers(msg),
            RequestMessage::Block(msg) => self.handle_request_block(msg),
        }
    }

    pub fn handle_request_propose(&mut self, msg: RequestPropose) {
        if msg.height() != self.state.height() {
            return;
        }

        let propose = if msg.height() == self.state.height() {
            self.state.propose(msg.propose_hash()).map(|p| p.message().raw().clone())
        } else {
            return;
        };

        if let Some(propose) = propose {
            self.send_to_peer(*msg.from(), &propose);
        }
    }

    pub fn handle_request_txs(&mut self, msg: RequestTransactions) {
        trace!("HANDLE TRANSACTIONS REQUEST!!!");
        let view = self.blockchain.view();
        for hash in msg.txs() {
            let tx = self.state
                .transactions()
                .get(hash)
                .cloned()
                .or_else(|| view.transactions().get(hash).unwrap());

            if let Some(tx) = tx {
                self.send_to_peer(*msg.from(), tx.raw());
            }
        }
    }

    pub fn handle_request_prevotes(&mut self, msg: RequestPrevotes) {
        if msg.height() != self.state.height() {
            return;
        }

        let has_prevotes = msg.validators();
        let prevotes = self.state
            .prevotes(msg.round(), *msg.propose_hash())
            .iter()
            .filter(|p| !has_prevotes[p.validator() as usize])
            .map(|p| p.raw().clone())
            .collect::<Vec<_>>();

        for prevote in &prevotes {
            self.send_to_peer(*msg.from(), prevote);
        }
    }

    pub fn handle_request_precommits(&mut self, msg: RequestPrecommits) {
        if msg.height() > self.state.height() {
            return;
        }

        let has_precommits = msg.validators();
        let precommits = self.state
            .precommits(msg.round(), *msg.block_hash())
            .iter()
            .filter(|p| !has_precommits[p.validator() as usize])
            .map(|p| p.raw().clone())
            .collect::<Vec<_>>();

        // FIXME what about msg.height < state.height ?
        // self.blockchain
        //     .view()
        //     .precommits(msg.block_hash())
        //     .values()
        //     .unwrap()
        //     .iter()
        //     .map(|p| p.raw().clone())
        //     .collect()

        for precommit in precommits {
            self.send_to_peer(*msg.from(), &precommit);
        }
    }

    pub fn handle_request_block(&mut self, msg: RequestBlock) {
        trace!("Handle block request with height:{}, our height: {}",
               msg.height(),
               self.state.height());
        if msg.height() >= self.state.height() {
            return;
        }

        let view = self.blockchain.view();
        let height = msg.height();
        let block_hash = view.heights().get(height).unwrap().unwrap();

        let block = view.blocks().get(&block_hash).unwrap().unwrap();
        let precommits = view.precommits(&block_hash)
            .values()
            .unwrap()
            .iter()
            .cloned()
            .collect::<Vec<_>>();
        let transactions = view.block_txs(height)
            .values()
            .unwrap()
            .iter()
            .map(|tx_hash| view.transactions().get(tx_hash).unwrap().unwrap())
            .map(|p| p.raw().clone())
            .collect::<Vec<_>>();

        let block_msg = Block::new(&self.public_key,
                                   msg.from(),
                                   self.channel.get_time(),
                                   block,
                                   precommits,
                                   transactions,
                                   &self.secret_key);
        self.send_to_peer(*msg.from(), block_msg.raw());
    }
}
<|endoftext|>


<commit_before>const FIXSTR_SIZE   : u8 = 0x1f;
const FIXARRAY_SIZE : u8 = 0x0f;
const FIXMAP_SIZE   : u8 = 0x0f;

/// Format markers.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Marker {
    FixPos(u8),
    FixNeg(i8),
    Null,
    True,
    False,
    U8,
    U16,
    U32,
    U64,
    I8,
    I16,
    I32,
    I64,
    F32,
    F64,
    FixStr(u8),
    Str8,
    Str16,
    Str32,
    Bin8,
    Bin16,
    Bin32,
    FixArray(u8),
    Array16,
    Array32,
    FixMap(u8),
    Map16,
    Map32,
    FixExt1,
    FixExt2,
    FixExt4,
    FixExt8,
    FixExt16,
    Ext8,
    Ext16,
    Ext32,
    Reserved,
}

impl Marker {
    /// Construct a msgpack marker from a single byte.
    pub fn from_u8(n: u8) -> Marker {
        match n {
            0x00 ... 0x7f => Marker::FixPos(n),
            0xe0 ... 0xff => Marker::FixNeg(n as i8),
            0x80 ... 0x8f => Marker::FixMap(n & FIXMAP_SIZE),
            0x90 ... 0x9f => Marker::FixArray(n & FIXARRAY_SIZE),
            0xa0 ... 0xbf => Marker::FixStr(n & FIXSTR_SIZE),
            0xc0 => Marker::Null,
            /// Marked in MessagePack spec as never used.
            0xc1 => Marker::Reserved,
            0xc2 => Marker::False,
            0xc3 => Marker::True,
            0xc4 => Marker::Bin8,
            0xc5 => Marker::Bin16,
            0xc6 => Marker::Bin32,
            0xc7 => Marker::Ext8,
            0xc8 => Marker::Ext16,
            0xc9 => Marker::Ext32,
            0xca => Marker::F32,
            0xcb => Marker::F64,
            0xcc => Marker::U8,
            0xcd => Marker::U16,
            0xce => Marker::U32,
            0xcf => Marker::U64,
            0xd0 => Marker::I8,
            0xd1 => Marker::I16,
            0xd2 => Marker::I32,
            0xd3 => Marker::I64,
            0xd4 => Marker::FixExt1,
            0xd5 => Marker::FixExt2,
            0xd6 => Marker::FixExt4,
            0xd7 => Marker::FixExt8,
            0xd8 => Marker::FixExt16,
            0xd9 => Marker::Str8,
            0xda => Marker::Str16,
            0xdb => Marker::Str32,
            0xdc => Marker::Array16,
            0xdd => Marker::Array32,
            0xde => Marker::Map16,
            0xdf => Marker::Map32,
            _ => unreachable!(),
        }
    }

    /// Converts a marker object into a single-byte representation.
    pub fn to_u8(&self) -> u8 {
        match *self {
            Marker::FixPos(val)   => val,
            Marker::FixNeg(val)   => val as u8,

            Marker::Null          => 0xc0,

            Marker::True          => 0xc3,
            Marker::False         => 0xc2,

            Marker::U8            => 0xcc,
            Marker::U16           => 0xcd,
            Marker::U32           => 0xce,
            Marker::U64           => 0xcf,

            Marker::I8            => 0xd0,
            Marker::I16           => 0xd1,
            Marker::I32           => 0xd2,
            Marker::I64           => 0xd3,

            Marker::F32           => 0xca,
            Marker::F64           => 0xcb,

            Marker::FixStr(len)   => 0xa0 | (len & FIXSTR_SIZE),
            Marker::Str8          => 0xd9,
            Marker::Str16         => 0xda,
            Marker::Str32         => 0xdb,

            Marker::Bin8          => 0xc4,
            Marker::Bin16         => 0xc5,
            Marker::Bin32         => 0xc6,

            Marker::FixArray(len) => 0x90 | (len & FIXARRAY_SIZE),
            Marker::Array16       => 0xdc,
            Marker::Array32       => 0xdd,

            Marker::FixMap(len)   => 0x80 | (len & FIXMAP_SIZE),
            Marker::Map16         => 0xde,
            Marker::Map32         => 0xdf,

            Marker::FixExt1       => 0xd4,
            Marker::FixExt2       => 0xd5,
            Marker::FixExt4       => 0xd6,
            Marker::FixExt8       => 0xd7,
            Marker::FixExt16      => 0xd8,
            Marker::Ext8          => 0xc7,
            Marker::Ext16         => 0xc8,
            Marker::Ext32         => 0xc9,

            Marker::Reserved      => 0xc1,
        }
    }
}

impl From<u8> for Marker {
    fn from(val: u8) -> Marker {
        Marker::from_u8(val)
    }
}

impl Into<u8> for Marker {
    fn into(self) -> u8 {
        self.to_u8()
    }
}
<commit_msg>chore: code style<commit_after>const FIXSTR_SIZE   : u8 = 0x1f;
const FIXARRAY_SIZE : u8 = 0x0f;
const FIXMAP_SIZE   : u8 = 0x0f;

/// Format markers.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Marker {
    FixPos(u8),
    FixNeg(i8),
    Null,
    True,
    False,
    U8,
    U16,
    U32,
    U64,
    I8,
    I16,
    I32,
    I64,
    F32,
    F64,
    FixStr(u8),
    Str8,
    Str16,
    Str32,
    Bin8,
    Bin16,
    Bin32,
    FixArray(u8),
    Array16,
    Array32,
    FixMap(u8),
    Map16,
    Map32,
    FixExt1,
    FixExt2,
    FixExt4,
    FixExt8,
    FixExt16,
    Ext8,
    Ext16,
    Ext32,
    Reserved,
}

impl Marker {
    /// Construct a msgpack marker from a single byte.
    pub fn from_u8(n: u8) -> Marker {
        match n {
            0x00 ... 0x7f => Marker::FixPos(n),
            0xe0 ... 0xff => Marker::FixNeg(n as i8),
            0x80 ... 0x8f => Marker::FixMap(n & FIXMAP_SIZE),
            0x90 ... 0x9f => Marker::FixArray(n & FIXARRAY_SIZE),
            0xa0 ... 0xbf => Marker::FixStr(n & FIXSTR_SIZE),
            0xc0 => Marker::Null,
            // Marked in MessagePack spec as never used.
            0xc1 => Marker::Reserved,
            0xc2 => Marker::False,
            0xc3 => Marker::True,
            0xc4 => Marker::Bin8,
            0xc5 => Marker::Bin16,
            0xc6 => Marker::Bin32,
            0xc7 => Marker::Ext8,
            0xc8 => Marker::Ext16,
            0xc9 => Marker::Ext32,
            0xca => Marker::F32,
            0xcb => Marker::F64,
            0xcc => Marker::U8,
            0xcd => Marker::U16,
            0xce => Marker::U32,
            0xcf => Marker::U64,
            0xd0 => Marker::I8,
            0xd1 => Marker::I16,
            0xd2 => Marker::I32,
            0xd3 => Marker::I64,
            0xd4 => Marker::FixExt1,
            0xd5 => Marker::FixExt2,
            0xd6 => Marker::FixExt4,
            0xd7 => Marker::FixExt8,
            0xd8 => Marker::FixExt16,
            0xd9 => Marker::Str8,
            0xda => Marker::Str16,
            0xdb => Marker::Str32,
            0xdc => Marker::Array16,
            0xdd => Marker::Array32,
            0xde => Marker::Map16,
            0xdf => Marker::Map32,
            _ => unreachable!(),
        }
    }

    /// Converts a marker object into a single-byte representation.
    pub fn to_u8(&self) -> u8 {
        match *self {
            Marker::FixPos(val)   => val,
            Marker::FixNeg(val)   => val as u8,

            Marker::Null          => 0xc0,

            Marker::True          => 0xc3,
            Marker::False         => 0xc2,

            Marker::U8            => 0xcc,
            Marker::U16           => 0xcd,
            Marker::U32           => 0xce,
            Marker::U64           => 0xcf,

            Marker::I8            => 0xd0,
            Marker::I16           => 0xd1,
            Marker::I32           => 0xd2,
            Marker::I64           => 0xd3,

            Marker::F32           => 0xca,
            Marker::F64           => 0xcb,

            Marker::FixStr(len)   => 0xa0 | (len & FIXSTR_SIZE),
            Marker::Str8          => 0xd9,
            Marker::Str16         => 0xda,
            Marker::Str32         => 0xdb,

            Marker::Bin8          => 0xc4,
            Marker::Bin16         => 0xc5,
            Marker::Bin32         => 0xc6,

            Marker::FixArray(len) => 0x90 | (len & FIXARRAY_SIZE),
            Marker::Array16       => 0xdc,
            Marker::Array32       => 0xdd,

            Marker::FixMap(len)   => 0x80 | (len & FIXMAP_SIZE),
            Marker::Map16         => 0xde,
            Marker::Map32         => 0xdf,

            Marker::FixExt1       => 0xd4,
            Marker::FixExt2       => 0xd5,
            Marker::FixExt4       => 0xd6,
            Marker::FixExt8       => 0xd7,
            Marker::FixExt16      => 0xd8,
            Marker::Ext8          => 0xc7,
            Marker::Ext16         => 0xc8,
            Marker::Ext32         => 0xc9,

            Marker::Reserved      => 0xc1,
        }
    }
}

impl From<u8> for Marker {
    fn from(val: u8) -> Marker {
        Marker::from_u8(val)
    }
}

impl Into<u8> for Marker {
    fn into(self) -> u8 {
        self.to_u8()
    }
}
<|endoftext|>


<commit_before>//! Utilities for interacting with tasks implemented in the rust-rosetta repository.

use std::collections::HashSet;
use std::fs;
use std::path::{Path, PathBuf};

use anyhow::{anyhow, Context, Error};
use cargo_metadata;
use reqwest::Url;
use toml::Value;
use walkdir::WalkDir;

use crate::remote;
use crate::TASK_URL_RE;

/// A local (in repository) implementation of a Rosetta Code task.
#[derive(Debug, Clone)]
pub struct LocalTask {
    /// The name of the package implementing this task.
    pub package_name: String,

    /// The path to the crate manifest for the task.
    pub manifest_path: PathBuf,

    /// A set of filenames containing the Rust source code of the tasks.
    pub source: HashSet<PathBuf>,

    /// The URL of the task on the Rosetta Code wiki.
    ///
    /// This is parsed from the crate metadata, so it may not point to an actual Rosetta Code URL.
    pub url: Url,

    /// The title of the task on Rosetta Code.
    ///
    /// The title is normalized, so it can be used to uniquely identify the task on the wiki.
    pub title: String,
}

/// Given a path to the root `Cargo.toml`, returns a list of tasks implemented in the rust-rosetta
/// repository.
pub fn parse_tasks<P>(manifest_path: P) -> Result<Vec<LocalTask>, Error>
where
    P: AsRef<Path>,
{
    let metadata = cargo_metadata::metadata(Some(&manifest_path.as_ref())).unwrap();
    let packages = &metadata.packages;

    let mut tasks = vec![];

    for member in &metadata.workspace_members {
        // Skip if we encounter known non-task crates.
        if member.name() == "rust-rosetta" || member.name() == "meta" {
            continue;
        }

        let package = packages.iter().find(|p| p.name == member.name()).unwrap();

        // If the package has a proc-macro or dylib target, it's probably just a dependency of
        // another task. Skip it.
        if package.targets.iter().any(|t| {
            t.kind.contains(&String::from("dylib")) || t.kind.contains(&String::from("proc-macro"))
        }) {
            continue;
        }

        let manifest_path = Path::new(&package.manifest_path);

        let rosetta_url = parse_rosetta_url(manifest_path).context(format!(
            "could not parse rosetta code URL from {}",
            manifest_path.display()
        ))?;

        let title = {
            let caps = TASK_URL_RE.captures(rosetta_url.as_str()).ok_or_else(|| {
                anyhow!(
                    "task URL does not match rosetta code regex: {}",
                    rosetta_url
                )
            })?;
            remote::decode_title(&caps[1])
        };

        tasks.push(LocalTask {
            package_name: member.name().to_owned(),
            manifest_path: manifest_path.to_owned(),
            source: find_sources(manifest_path.parent().unwrap())?,
            url: rosetta_url,
            title,
        });
    }

    Ok(tasks)
}

/// Parses the Rosetta Code URL from the package metadata in a task's crate manifest.
fn parse_rosetta_url<P>(manifest_path: P) -> Result<Url, Error>
where
    P: AsRef<Path>,
{
    let manifest: Value = fs::read_to_string(manifest_path)?.parse()?;

    let url = manifest
        .get("package")
        .and_then(|p| p.get("metadata"))
        .and_then(|m| m.get("rosettacode"))
        .and_then(|m| m.get("url"))
        .and_then(|u| u.as_str())
        .ok_or_else(|| anyhow!("unexpected metadata format"))?;

    Ok(Url::parse(url)?)
}

/// Collect the paths to the source files of a given package.
fn find_sources<P>(directory: P) -> Result<HashSet<PathBuf>, Error>
where
    P: AsRef<Path>,
{
    let mut sources = HashSet::new();

    for entry in WalkDir::new(directory) {
        let entry = entry?;

        if let Some("rs") = entry.path().extension().and_then(|s| s.to_str()) {
            sources.insert(entry.path().to_owned());
        }
    }

    Ok(sources)
}
<commit_msg>fix single component path import<commit_after>//! Utilities for interacting with tasks implemented in the rust-rosetta repository.

use std::collections::HashSet;
use std::fs;
use std::path::{Path, PathBuf};

use anyhow::{anyhow, Context, Error};
use reqwest::Url;
use toml::Value;
use walkdir::WalkDir;

use crate::remote;
use crate::TASK_URL_RE;

/// A local (in repository) implementation of a Rosetta Code task.
#[derive(Debug, Clone)]
pub struct LocalTask {
    /// The name of the package implementing this task.
    pub package_name: String,

    /// The path to the crate manifest for the task.
    pub manifest_path: PathBuf,

    /// A set of filenames containing the Rust source code of the tasks.
    pub source: HashSet<PathBuf>,

    /// The URL of the task on the Rosetta Code wiki.
    ///
    /// This is parsed from the crate metadata, so it may not point to an actual Rosetta Code URL.
    pub url: Url,

    /// The title of the task on Rosetta Code.
    ///
    /// The title is normalized, so it can be used to uniquely identify the task on the wiki.
    pub title: String,
}

/// Given a path to the root `Cargo.toml`, returns a list of tasks implemented in the rust-rosetta
/// repository.
pub fn parse_tasks<P>(manifest_path: P) -> Result<Vec<LocalTask>, Error>
where
    P: AsRef<Path>,
{
    let metadata = cargo_metadata::metadata(Some(&manifest_path.as_ref())).unwrap();
    let packages = &metadata.packages;

    let mut tasks = vec![];

    for member in &metadata.workspace_members {
        // Skip if we encounter known non-task crates.
        if member.name() == "rust-rosetta" || member.name() == "meta" {
            continue;
        }

        let package = packages.iter().find(|p| p.name == member.name()).unwrap();

        // If the package has a proc-macro or dylib target, it's probably just a dependency of
        // another task. Skip it.
        if package.targets.iter().any(|t| {
            t.kind.contains(&String::from("dylib")) || t.kind.contains(&String::from("proc-macro"))
        }) {
            continue;
        }

        let manifest_path = Path::new(&package.manifest_path);

        let rosetta_url = parse_rosetta_url(manifest_path).context(format!(
            "could not parse rosetta code URL from {}",
            manifest_path.display()
        ))?;

        let title = {
            let caps = TASK_URL_RE.captures(rosetta_url.as_str()).ok_or_else(|| {
                anyhow!(
                    "task URL does not match rosetta code regex: {}",
                    rosetta_url
                )
            })?;
            remote::decode_title(&caps[1])
        };

        tasks.push(LocalTask {
            package_name: member.name().to_owned(),
            manifest_path: manifest_path.to_owned(),
            source: find_sources(manifest_path.parent().unwrap())?,
            url: rosetta_url,
            title,
        });
    }

    Ok(tasks)
}

/// Parses the Rosetta Code URL from the package metadata in a task's crate manifest.
fn parse_rosetta_url<P>(manifest_path: P) -> Result<Url, Error>
where
    P: AsRef<Path>,
{
    let manifest: Value = fs::read_to_string(manifest_path)?.parse()?;

    let url = manifest
        .get("package")
        .and_then(|p| p.get("metadata"))
        .and_then(|m| m.get("rosettacode"))
        .and_then(|m| m.get("url"))
        .and_then(|u| u.as_str())
        .ok_or_else(|| anyhow!("unexpected metadata format"))?;

    Ok(Url::parse(url)?)
}

/// Collect the paths to the source files of a given package.
fn find_sources<P>(directory: P) -> Result<HashSet<PathBuf>, Error>
where
    P: AsRef<Path>,
{
    let mut sources = HashSet::new();

    for entry in WalkDir::new(directory) {
        let entry = entry?;

        if let Some("rs") = entry.path().extension().and_then(|s| s.to_str()) {
            sources.insert(entry.path().to_owned());
        }
    }

    Ok(sources)
}
<|endoftext|>


<commit_before>#[derive(Show, PartialEq)]
pub struct PerElem {
    pub name: String,
    pub coef: u32,
    pub pos: usize,
    pub len: usize,
}

pub type Molecule = Vec<PerElem>;

pub fn group_elems(molecule: Molecule) -> Molecule {
    let mut out = Vec::<PerElem>::new();
    for elem in molecule.into_iter() {
        if let Some(pos) = out.iter().position(|e| e.name == elem.name) {
            out[pos].coef += elem.coef;
        } else {
            out.push(elem);
        }
    }
    out
}

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

    macro_rules! dummy_elem(
        ($name:expr) => (
            PerElem { name: $name.to_string(), coef: 1, pos: 0, len: 1 }
        );
        ($name:expr, $coef:expr) => (
            PerElem { name: $name.to_string(), coef: $coef, pos: 0, len: 1 }
        );
    );

    #[test]
    fn group() {
        let result = group_elems(vec!(dummy_elem!("C"), dummy_elem!("H"), dummy_elem!("C")));
        let expected = vec!(dummy_elem!("C", 2), dummy_elem!("H", 1));
        assert_eq!(result, expected);
    }
}<commit_msg>Change group_elems to run faster<commit_after>use std::cmp::Ordering::*;

#[derive(Show, PartialEq)]
pub struct PerElem {
    pub name: String,
    pub coef: u32,
    pub pos: usize,
    pub len: usize,
}

pub type Molecule = Vec<PerElem>;

pub fn group_elems(mut molecule: Molecule) -> Molecule {
    let mut out = Vec::<PerElem>::new();
    {
        // we open a scope, so slice borrow stops before the for-loop
        let mut slice = molecule.as_mut_slice();
        slice.sort_by(|a, b| a.name.cmp(&b.name));
    }
    // since the elements are now sorted, if the current elem does not match the
    // last element in out (i.e. what we previously pushed), then it won't match
    // anything in out
    for elem in molecule.into_iter() {
        if out.last().and_then(|e| Some(e.name == elem.name)).unwrap_or(false) {
            out.last_mut().unwrap().coef += elem.coef;
        } else {
            out.push(elem);
        }
    }
    out
}

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

    macro_rules! dummy_elem(
        ($name:expr) => (
            PerElem { name: $name.to_string(), coef: 1, pos: 0, len: 1 }
        );
        ($name:expr, $coef:expr) => (
            PerElem { name: $name.to_string(), coef: $coef, pos: 0, len: 1 }
        );
    );

    #[test]
    fn group() {
        let result = group_elems(vec!(dummy_elem!("C"), dummy_elem!("H"), dummy_elem!("C")));
        let expected = vec!(dummy_elem!("C", 2), dummy_elem!("H", 1));
        assert_eq!(result, expected);
    }
}<|endoftext|>


<commit_before>use std::rc::Rc;
use std::ops::Deref;

use ::expr::{Expr, Type, Proc, Error as E, Result};
use ::env::Env;
use ::util::*;

fn bind_names(mut env: &mut Env, params: &Expr, args: &Expr) -> Result<()>{
    let mut phead = params;
    let mut ahead = args;
    let nil = &knil();
    while phead != nil && ahead != nil {
        match (phead, ahead) {
            (&Expr::Cons(ref pcar, ref pcdr), &Expr::Cons(ref acar, ref acdr)) => {
                match pcar.deref() {
                    &Expr::Sym(ref name) => env.register(name.clone(), acar.deref().clone()),
                    pcar => return Err(E::Form(pcar.clone()))
                };
                phead = pcdr.deref();
                ahead = acdr.deref();
            },
            _ => return Err(E::Form(args.clone()))
        }
    };
    Ok(())
}

pub fn funcall(mut env: &mut Env, f: &Proc, args: &Expr) -> Result<Expr> {
    match f {
        &Proc::Prim(_, ref f) => {
            f(env, args)
        },
        &Proc::Lambda(ref params, ref body) => {
            env.new_local();
            try!(bind_names(env, params.deref(), args));
            let ret = eval(env, body.deref());
            env.end_local();
            ret
        }
    }
}

fn k_quote(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (sexp, Any));
    Ok(sexp.clone())
}

fn f_lambda(_: &mut Env, args: &Expr) -> Result<Proc> {
    match args {
        &Expr::Cons(ref params, ref body) =>
            Ok(klambda(params.deref().clone(),
                       kcons(ksym("progn"), body.deref().clone()))),
        _ => unreachable!()
    }
}

fn k_lambda(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    Ok(Expr::Proc(try!(f_lambda(env, args))))
}

fn k_feval(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    match args {
        &Expr::Cons(ref car, _) => Ok(Expr::Proc(try!(feval(env, car.deref())))),
        _ => unreachable!()
    }
}

fn k_progn(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    let mut head = args;
    let nil = &knil();
    let mut res = knil();
    while head != nil {
        match head {
            &Expr::Cons(ref car, ref cdr) => {
                res = try!(eval(env, car.deref()));
                head = cdr.deref();
            },
            _ => return Err(E::Form(args.clone()))
        }
    };
    Ok(res)
}

fn k_fset(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (s, Any) (f, Any));
    let s = try!(eval(env, s));
    let f = try!(feval(env, f));
    let tmp = klist!(s);
    get_args!(&tmp, (s, Sym));
    env.fregister(s.clone(), f.clone());
    return Ok(knil());
}

fn k_set(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (s, Any) (e, Any));
    let s = try!(eval(env, s));
    let e = try!(eval(env, e));
    let tmp = klist!(s);
    get_args!(&tmp, (s, Sym));
    env.register(s.clone(), e.clone());
    return Ok(knil());
}

fn k_if(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    // TODO: optional else clasue. Need optional argments.
    get_args!(args, (cnd, Any) (thn, Any) (els, Any));
    let res = try!(eval(env, cnd));
    if res != knil() {
        eval(env, thn)
    } else {
        eval(env, els)
    }
}

fn feval(mut env: &mut Env, expr: &Expr) -> Result<Proc> {
    match expr {
        &Expr::Sym(ref sym) => {
            match env.ffind(sym) {
                Ok(f) => Ok(f.clone()),
                Err(e) => Err(e)
            }
        },
        &Expr::Cons(ref op, ref rest) => {
            let op = op.deref();
            match op {
                &Expr::Sym(ref sym) => match &sym[..] {
                    "lambda" => f_lambda(env, rest.deref()),
                    _ => Err(E::NotFunction(expr.clone()))
                },
                _ => Err(E::NotFunction(expr.clone()))
            }
        }
        &Expr::Proc(ref f) => Ok(f.clone()),
        _ => Err(E::NotFunction(expr.clone()))
    }
}

pub fn eval(mut env: &mut Env, expr: &Expr) -> Result<Expr> {
    match expr {
        &Expr::Nil |
        &Expr::EOF |
        &Expr::Str(_) |
        &Expr::Int(_) |
        &Expr::Float(_) |
        &Expr::Proc(_) => Ok(expr.clone()),
        &Expr::Sym(ref name) => match env.find(&name.to_owned()) {
            Ok(v) =>Ok(v.clone()),
            Err(m) => if name == "t" {
                Ok(ksym("t"))
            }else {
                Err(m)
            }
        },
        &Expr::Cons(ref car, ref cdr) => {
            let car = car.deref();
            let cdr = cdr.deref();
            match car {
                &Expr::Sym(ref sym) => match &sym[..] {
                    // Eval special forms first
                    "quote" => k_quote(env, cdr),
                    "function" => k_feval(env, cdr),
                    "lambda" => k_lambda(env, cdr),
                    "progn" => k_progn(env, cdr),
                    "fset" => k_fset(env, cdr),
                    "set"  => k_set(env, cdr),
                    "if" => k_if(env, cdr),
                    _ => {
                        let f = try!(feval(env, car));
                        let arg = try!(f_map(env, &|env, x| eval(env, x), cdr));
                        funcall(env, &f, &arg)
                    }
                },
                car => {
                    let f = try!(feval(env, car));
                    let arg = try!(f_map(env, &|env, x| eval(env, x), cdr));
                    funcall(env, &f, &arg)
                }
            }
        }
    }
}

<commit_msg>support optional if<commit_after>use std::rc::Rc;
use std::ops::Deref;

use ::expr::{Expr, Type, Proc, Error as E, Result};
use ::env::Env;
use ::util::*;

fn bind_names(mut env: &mut Env, params: &Expr, args: &Expr) -> Result<()>{
    let mut phead = params;
    let mut ahead = args;
    let nil = &knil();
    while phead != nil && ahead != nil {
        match (phead, ahead) {
            (&Expr::Cons(ref pcar, ref pcdr), &Expr::Cons(ref acar, ref acdr)) => {
                match pcar.deref() {
                    &Expr::Sym(ref name) => env.register(name.clone(), acar.deref().clone()),
                    pcar => return Err(E::Form(pcar.clone()))
                };
                phead = pcdr.deref();
                ahead = acdr.deref();
            },
            _ => return Err(E::Form(args.clone()))
        }
    };
    Ok(())
}

pub fn funcall(mut env: &mut Env, f: &Proc, args: &Expr) -> Result<Expr> {
    match f {
        &Proc::Prim(_, ref f) => {
            f(env, args)
        },
        &Proc::Lambda(ref params, ref body) => {
            env.new_local();
            try!(bind_names(env, params.deref(), args));
            let ret = eval(env, body.deref());
            env.end_local();
            ret
        }
    }
}

fn k_quote(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (sexp, Any));
    Ok(sexp.clone())
}

fn f_lambda(_: &mut Env, args: &Expr) -> Result<Proc> {
    match args {
        &Expr::Cons(ref params, ref body) =>
            Ok(klambda(params.deref().clone(),
                       kcons(ksym("progn"), body.deref().clone()))),
        _ => unreachable!()
    }
}

fn k_lambda(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    Ok(Expr::Proc(try!(f_lambda(env, args))))
}

fn k_feval(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    match args {
        &Expr::Cons(ref car, _) => Ok(Expr::Proc(try!(feval(env, car.deref())))),
        _ => unreachable!()
    }
}

fn k_progn(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    let mut head = args;
    let nil = &knil();
    let mut res = knil();
    while head != nil {
        match head {
            &Expr::Cons(ref car, ref cdr) => {
                res = try!(eval(env, car.deref()));
                head = cdr.deref();
            },
            _ => return Err(E::Form(args.clone()))
        }
    };
    Ok(res)
}

fn k_fset(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (s, Any) (f, Any));
    let s = try!(eval(env, s));
    let f = try!(feval(env, f));
    let tmp = klist!(s);
    get_args!(&tmp, (s, Sym));
    env.fregister(s.clone(), f.clone());
    return Ok(knil());
}

fn k_set(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (s, Any) (e, Any));
    let s = try!(eval(env, s));
    let e = try!(eval(env, e));
    let tmp = klist!(s);
    get_args!(&tmp, (s, Sym));
    env.register(s.clone(), e.clone());
    return Ok(knil());
}

fn k_if(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    // TODO: optional else clasue. Need optional argments.
    get_args!(args, (cnd, Any) (thn, Any) &optional (els, Any));
    let res = try!(eval(env, cnd));
    if res != knil() {
        eval(env, thn)
    } else {
        match els {
            Some(els) =>  eval(env, els),
            None => Ok(knil())
        }
    }
}

fn feval(mut env: &mut Env, expr: &Expr) -> Result<Proc> {
    match expr {
        &Expr::Sym(ref sym) => {
            match env.ffind(sym) {
                Ok(f) => Ok(f.clone()),
                Err(e) => Err(e)
            }
        },
        &Expr::Cons(ref op, ref rest) => {
            let op = op.deref();
            match op {
                &Expr::Sym(ref sym) => match &sym[..] {
                    "lambda" => f_lambda(env, rest.deref()),
                    _ => Err(E::NotFunction(expr.clone()))
                },
                _ => Err(E::NotFunction(expr.clone()))
            }
        }
        &Expr::Proc(ref f) => Ok(f.clone()),
        _ => Err(E::NotFunction(expr.clone()))
    }
}

pub fn eval(mut env: &mut Env, expr: &Expr) -> Result<Expr> {
    match expr {
        &Expr::Nil |
        &Expr::EOF |
        &Expr::Str(_) |
        &Expr::Int(_) |
        &Expr::Float(_) |
        &Expr::Proc(_) => Ok(expr.clone()),
        &Expr::Sym(ref name) => match env.find(&name.to_owned()) {
            Ok(v) =>Ok(v.clone()),
            Err(m) => if name == "t" {
                Ok(ksym("t"))
            }else {
                Err(m)
            }
        },
        &Expr::Cons(ref car, ref cdr) => {
            let car = car.deref();
            let cdr = cdr.deref();
            match car {
                &Expr::Sym(ref sym) => match &sym[..] {
                    // Eval special forms first
                    "quote" => k_quote(env, cdr),
                    "function" => k_feval(env, cdr),
                    "lambda" => k_lambda(env, cdr),
                    "progn" => k_progn(env, cdr),
                    "fset" => k_fset(env, cdr),
                    "set"  => k_set(env, cdr),
                    "if" => k_if(env, cdr),
                    _ => {
                        let f = try!(feval(env, car));
                        let arg = try!(f_map(env, &|env, x| eval(env, x), cdr));
                        funcall(env, &f, &arg)
                    }
                },
                car => {
                    let f = try!(feval(env, car));
                    let arg = try!(f_map(env, &|env, x| eval(env, x), cdr));
                    funcall(env, &f, &arg)
                }
            }
        }
    }
}

<|endoftext|>