<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/. */

//! Per-node data used in style calculation.

use context::SharedStyleContext;
use dom::TElement;
use invalidation::element::restyle_hints::RestyleHint;
use properties::ComputedValues;
use properties::longhands::display::computed_value as display;
use rule_tree::StrongRuleNode;
use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage};
use servo_arc::Arc;
use shared_lock::StylesheetGuards;
use std::fmt;
use std::ops::{Deref, DerefMut};

bitflags! {
    flags RestyleFlags: u8 {
        /// Whether the styles changed for this restyle.
        const WAS_RESTYLED = 1 << 0,
        /// Whether we reframed/reconstructed any ancestor or self.
        const ANCESTOR_WAS_RECONSTRUCTED = 1 << 1,
    }
}

/// Transient data used by the restyle algorithm. This structure is instantiated
/// either before or during restyle traversal, and is cleared at the end of node
/// processing.
#[derive(Debug)]
pub struct RestyleData {
    /// The restyle hint, which indicates whether selectors need to be rematched
    /// for this element, its children, and its descendants.
    pub hint: RestyleHint,

    /// A few flags to have in mind.
    flags: RestyleFlags,

    /// The restyle damage, indicating what kind of layout changes are required
    /// afte restyling.
    pub damage: RestyleDamage,
}

impl Default for RestyleData {
    fn default() -> Self {
        Self::new()
    }
}

impl RestyleData {
    fn new() -> Self {
        Self {
            hint: RestyleHint::empty(),
            flags: RestyleFlags::empty(),
            damage: RestyleDamage::empty(),
        }
    }

    /// Clear all the restyle state associated with this element.
    fn clear(&mut self) {
        *self = Self::new();
    }

    /// Clear restyle flags and damage.
    fn clear_flags_and_damage(&mut self) {
        self.damage = RestyleDamage::empty();
        self.flags = RestyleFlags::empty();
    }

    /// Returns whether this element or any ancestor is going to be
    /// reconstructed.
    pub fn reconstructed_self_or_ancestor(&self) -> bool {
        self.reconstructed_ancestor() || self.reconstructed_self()
    }

    /// Returns whether this element is going to be reconstructed.
    pub fn reconstructed_self(&self) -> bool {
        self.damage.contains(RestyleDamage::reconstruct())
    }

    /// Returns whether any ancestor of this element is going to be
    /// reconstructed.
    fn reconstructed_ancestor(&self) -> bool {
        self.flags.contains(ANCESTOR_WAS_RECONSTRUCTED)
    }

    /// Sets the flag that tells us whether we've reconstructed an ancestor.
    pub fn set_reconstructed_ancestor(&mut self) {
        // If it weren't for animation-only traversals, we could assert
        // `!self.reconstructed_ancestor()` here.
        self.flags.insert(ANCESTOR_WAS_RECONSTRUCTED);
    }

    /// Mark this element as restyled, which is useful to know whether we need
    /// to do a post-traversal.
    pub fn set_restyled(&mut self) {
        self.flags.insert(WAS_RESTYLED);
    }

    /// Mark this element as restyled, which is useful to know whether we need
    /// to do a post-traversal.
    pub fn is_restyle(&self) -> bool {
        self.flags.contains(WAS_RESTYLED)
    }

    /// Returns whether this element has been part of a restyle.
    pub fn contains_restyle_data(&self) -> bool {
        self.is_restyle() || !self.hint.is_empty() || !self.damage.is_empty()
    }
}

/// A lazily-allocated list of styles for eagerly-cascaded pseudo-elements.
///
/// We use an Arc so that sharing these styles via the style sharing cache does
/// not require duplicate allocations. We leverage the copy-on-write semantics of
/// Arc::make_mut(), which is free (i.e. does not require atomic RMU operations)
/// in servo_arc.
#[derive(Clone, Debug, Default)]
pub struct EagerPseudoStyles(Option<Arc<EagerPseudoArray>>);

#[derive(Default)]
struct EagerPseudoArray(EagerPseudoArrayInner);
type EagerPseudoArrayInner = [Option<Arc<ComputedValues>>; EAGER_PSEUDO_COUNT];

impl Deref for EagerPseudoArray {
    type Target = EagerPseudoArrayInner;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for EagerPseudoArray {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

// Manually implement `Clone` here because the derived impl of `Clone` for
// array types assumes the value inside is `Copy`.
impl Clone for EagerPseudoArray {
    fn clone(&self) -> Self {
        let mut clone = Self::default();
        for i in 0..EAGER_PSEUDO_COUNT {
            clone[i] = self.0[i].clone();
        }
        clone
    }
}

// Override Debug to print which pseudos we have, and substitute the rule node
// for the much-more-verbose ComputedValues stringification.
impl fmt::Debug for EagerPseudoArray {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "EagerPseudoArray {{ ")?;
        for i in 0..EAGER_PSEUDO_COUNT {
            if let Some(ref values) = self[i] {
                write!(f, "{:?}: {:?}, ", PseudoElement::from_eager_index(i), &values.rules)?;
            }
        }
        write!(f, "}}")
    }
}

impl EagerPseudoStyles {
    /// Returns whether there are any pseudo styles.
    pub fn is_empty(&self) -> bool {
        self.0.is_none()
    }

    /// Grabs a reference to the list of styles, if they exist.
    pub fn as_array(&self) -> Option<&EagerPseudoArrayInner> {
        match self.0 {
            None => None,
            Some(ref x) => Some(&x.0),
        }
    }

    /// Returns a reference to the style for a given eager pseudo, if it exists.
    pub fn get(&self, pseudo: &PseudoElement) -> Option<&Arc<ComputedValues>> {
        debug_assert!(pseudo.is_eager());
        self.0.as_ref().and_then(|p| p[pseudo.eager_index()].as_ref())
    }

    /// Sets the style for the eager pseudo.
    pub fn set(&mut self, pseudo: &PseudoElement, value: Arc<ComputedValues>) {
        if self.0.is_none() {
            self.0 = Some(Arc::new(Default::default()));
        }
        let arr = Arc::make_mut(self.0.as_mut().unwrap());
        arr[pseudo.eager_index()] = Some(value);
    }
}

/// The styles associated with a node, including the styles for any
/// pseudo-elements.
#[derive(Clone, Default)]
pub struct ElementStyles {
    /// The element's style.
    pub primary: Option<Arc<ComputedValues>>,
    /// A list of the styles for the element's eagerly-cascaded pseudo-elements.
    pub pseudos: EagerPseudoStyles,
}

impl ElementStyles {
    /// Returns the primary style.
    pub fn get_primary(&self) -> Option<&Arc<ComputedValues>> {
        self.primary.as_ref()
    }

    /// Returns the primary style.  Panic if no style available.
    pub fn primary(&self) -> &Arc<ComputedValues> {
        self.primary.as_ref().unwrap()
    }

    /// Whether this element `display` value is `none`.
    pub fn is_display_none(&self) -> bool {
        self.primary().get_box().clone_display() == display::T::none
    }
}

// We manually implement Debug for ElementStyles so that we can avoid the
// verbose stringification of every property in the ComputedValues. We
// substitute the rule node instead.
impl fmt::Debug for ElementStyles {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ElementStyles {{ primary: {:?}, pseudos: {:?} }}",
               self.primary.as_ref().map(|x| &x.rules), self.pseudos)
    }
}

/// Style system data associated with an Element.
///
/// In Gecko, this hangs directly off the Element. Servo, this is embedded
/// inside of layout data, which itself hangs directly off the Element. In
/// both cases, it is wrapped inside an AtomicRefCell to ensure thread safety.
#[derive(Debug, Default)]
pub struct ElementData {
    /// The styles for the element and its pseudo-elements.
    pub styles: ElementStyles,

    /// Restyle state.
    pub restyle: RestyleData,
}

/// The kind of restyle that a single element should do.
#[derive(Debug)]
pub enum RestyleKind {
    /// We need to run selector matching plus re-cascade, that is, a full
    /// restyle.
    MatchAndCascade,
    /// We need to recascade with some replacement rule, such as the style
    /// attribute, or animation rules.
    CascadeWithReplacements(RestyleHint),
    /// We only need to recascade, for example, because only inherited
    /// properties in the parent changed.
    CascadeOnly,
}

impl ElementData {
    /// Invalidates style for this element, its descendants, and later siblings,
    /// based on the snapshot of the element that we took when attributes or
    /// state changed.
    pub fn invalidate_style_if_needed<'a, E: TElement>(
        &mut self,
        element: E,
        shared_context: &SharedStyleContext)
    {
        // In animation-only restyle we shouldn't touch snapshot at all.
        if shared_context.traversal_flags.for_animation_only() {
            return;
        }

        use invalidation::element::invalidator::TreeStyleInvalidator;

        debug!("invalidate_style_if_needed: {:?}, flags: {:?}, has_snapshot: {}, \
                handled_snapshot: {}, pseudo: {:?}",
                element,
                shared_context.traversal_flags,
                element.has_snapshot(),
                element.handled_snapshot(),
                element.implemented_pseudo_element());

        if element.has_snapshot() && !element.handled_snapshot() {
            let invalidator = TreeStyleInvalidator::new(
                element,
                Some(self),
                shared_context,
            );
            invalidator.invalidate();
            unsafe { element.set_handled_snapshot() }
            debug_assert!(element.handled_snapshot());
        }
    }

    /// Returns true if this element has styles.
    pub fn has_styles(&self) -> bool {
        self.styles.primary.is_some()
    }

    /// Returns the kind of restyling that we're going to need to do on this
    /// element, based of the stored restyle hint.
    pub fn restyle_kind(
        &self,
        shared_context: &SharedStyleContext
    ) -> RestyleKind {
        if shared_context.traversal_flags.for_animation_only() {
            return self.restyle_kind_for_animation(shared_context);
        }

        if !self.has_styles() {
            return RestyleKind::MatchAndCascade;
        }

        let hint = self.restyle.hint;
        if hint.match_self() {
            return RestyleKind::MatchAndCascade;
        }

        if hint.has_replacements() {
            debug_assert!(!hint.has_animation_hint(),
                          "Animation only restyle hint should have already processed");
            return RestyleKind::CascadeWithReplacements(hint & RestyleHint::replacements());
        }

        debug_assert!(hint.has_recascade_self(),
                      "We definitely need to do something!");
        return RestyleKind::CascadeOnly;
    }

    /// Returns the kind of restyling for animation-only restyle.
    fn restyle_kind_for_animation(
        &self,
        shared_context: &SharedStyleContext,
    ) -> RestyleKind {
        debug_assert!(shared_context.traversal_flags.for_animation_only());
        debug_assert!(self.has_styles(),
                      "Unstyled element shouldn't be traversed during \
                       animation-only traversal");

        // return either CascadeWithReplacements or CascadeOnly in case of
        // animation-only restyle. I.e. animation-only restyle never does
        // selector matching.
        let hint = self.restyle.hint;
        if hint.has_animation_hint() {
            return RestyleKind::CascadeWithReplacements(hint & RestyleHint::for_animations());
        }

        return RestyleKind::CascadeOnly;
    }

    /// Return true if important rules are different.
    /// We use this to make sure the cascade of off-main thread animations is correct.
    /// Note: Ignore custom properties for now because we only support opacity and transform
    ///       properties for animations running on compositor. Actually, we only care about opacity
    ///       and transform for now, but it's fine to compare all properties and let the user
    ///       the check which properties do they want.
    ///       If it costs too much, get_properties_overriding_animations() should return a set
    ///       containing only opacity and transform properties.
    pub fn important_rules_are_different(
        &self,
        rules: &StrongRuleNode,
        guards: &StylesheetGuards
    ) -> bool {
        debug_assert!(self.has_styles());
        let (important_rules, _custom) =
            self.styles.primary().rules().get_properties_overriding_animations(&guards);
        let (other_important_rules, _custom) = rules.get_properties_overriding_animations(&guards);
        important_rules != other_important_rules
    }

    /// Drops any restyle state from the element.
    pub fn clear_restyle_state(&mut self) {
        self.restyle.clear();
    }

    /// Drops restyle flags and damage from the element.
    pub fn clear_restyle_flags_and_damage(&mut self) {
        self.restyle.clear_flags_and_damage();
    }
}
<commit_msg>style: Improve the assertion message in restyle_kind().<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/. */

//! Per-node data used in style calculation.

use context::SharedStyleContext;
use dom::TElement;
use invalidation::element::restyle_hints::RestyleHint;
use properties::ComputedValues;
use properties::longhands::display::computed_value as display;
use rule_tree::StrongRuleNode;
use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage};
use servo_arc::Arc;
use shared_lock::StylesheetGuards;
use std::fmt;
use std::ops::{Deref, DerefMut};

bitflags! {
    flags RestyleFlags: u8 {
        /// Whether the styles changed for this restyle.
        const WAS_RESTYLED = 1 << 0,
        /// Whether we reframed/reconstructed any ancestor or self.
        const ANCESTOR_WAS_RECONSTRUCTED = 1 << 1,
    }
}

/// Transient data used by the restyle algorithm. This structure is instantiated
/// either before or during restyle traversal, and is cleared at the end of node
/// processing.
#[derive(Debug)]
pub struct RestyleData {
    /// The restyle hint, which indicates whether selectors need to be rematched
    /// for this element, its children, and its descendants.
    pub hint: RestyleHint,

    /// A few flags to have in mind.
    flags: RestyleFlags,

    /// The restyle damage, indicating what kind of layout changes are required
    /// afte restyling.
    pub damage: RestyleDamage,
}

impl Default for RestyleData {
    fn default() -> Self {
        Self::new()
    }
}

impl RestyleData {
    fn new() -> Self {
        Self {
            hint: RestyleHint::empty(),
            flags: RestyleFlags::empty(),
            damage: RestyleDamage::empty(),
        }
    }

    /// Clear all the restyle state associated with this element.
    fn clear(&mut self) {
        *self = Self::new();
    }

    /// Clear restyle flags and damage.
    fn clear_flags_and_damage(&mut self) {
        self.damage = RestyleDamage::empty();
        self.flags = RestyleFlags::empty();
    }

    /// Returns whether this element or any ancestor is going to be
    /// reconstructed.
    pub fn reconstructed_self_or_ancestor(&self) -> bool {
        self.reconstructed_ancestor() || self.reconstructed_self()
    }

    /// Returns whether this element is going to be reconstructed.
    pub fn reconstructed_self(&self) -> bool {
        self.damage.contains(RestyleDamage::reconstruct())
    }

    /// Returns whether any ancestor of this element is going to be
    /// reconstructed.
    fn reconstructed_ancestor(&self) -> bool {
        self.flags.contains(ANCESTOR_WAS_RECONSTRUCTED)
    }

    /// Sets the flag that tells us whether we've reconstructed an ancestor.
    pub fn set_reconstructed_ancestor(&mut self) {
        // If it weren't for animation-only traversals, we could assert
        // `!self.reconstructed_ancestor()` here.
        self.flags.insert(ANCESTOR_WAS_RECONSTRUCTED);
    }

    /// Mark this element as restyled, which is useful to know whether we need
    /// to do a post-traversal.
    pub fn set_restyled(&mut self) {
        self.flags.insert(WAS_RESTYLED);
    }

    /// Mark this element as restyled, which is useful to know whether we need
    /// to do a post-traversal.
    pub fn is_restyle(&self) -> bool {
        self.flags.contains(WAS_RESTYLED)
    }

    /// Returns whether this element has been part of a restyle.
    pub fn contains_restyle_data(&self) -> bool {
        self.is_restyle() || !self.hint.is_empty() || !self.damage.is_empty()
    }
}

/// A lazily-allocated list of styles for eagerly-cascaded pseudo-elements.
///
/// We use an Arc so that sharing these styles via the style sharing cache does
/// not require duplicate allocations. We leverage the copy-on-write semantics of
/// Arc::make_mut(), which is free (i.e. does not require atomic RMU operations)
/// in servo_arc.
#[derive(Clone, Debug, Default)]
pub struct EagerPseudoStyles(Option<Arc<EagerPseudoArray>>);

#[derive(Default)]
struct EagerPseudoArray(EagerPseudoArrayInner);
type EagerPseudoArrayInner = [Option<Arc<ComputedValues>>; EAGER_PSEUDO_COUNT];

impl Deref for EagerPseudoArray {
    type Target = EagerPseudoArrayInner;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for EagerPseudoArray {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

// Manually implement `Clone` here because the derived impl of `Clone` for
// array types assumes the value inside is `Copy`.
impl Clone for EagerPseudoArray {
    fn clone(&self) -> Self {
        let mut clone = Self::default();
        for i in 0..EAGER_PSEUDO_COUNT {
            clone[i] = self.0[i].clone();
        }
        clone
    }
}

// Override Debug to print which pseudos we have, and substitute the rule node
// for the much-more-verbose ComputedValues stringification.
impl fmt::Debug for EagerPseudoArray {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "EagerPseudoArray {{ ")?;
        for i in 0..EAGER_PSEUDO_COUNT {
            if let Some(ref values) = self[i] {
                write!(f, "{:?}: {:?}, ", PseudoElement::from_eager_index(i), &values.rules)?;
            }
        }
        write!(f, "}}")
    }
}

impl EagerPseudoStyles {
    /// Returns whether there are any pseudo styles.
    pub fn is_empty(&self) -> bool {
        self.0.is_none()
    }

    /// Grabs a reference to the list of styles, if they exist.
    pub fn as_array(&self) -> Option<&EagerPseudoArrayInner> {
        match self.0 {
            None => None,
            Some(ref x) => Some(&x.0),
        }
    }

    /// Returns a reference to the style for a given eager pseudo, if it exists.
    pub fn get(&self, pseudo: &PseudoElement) -> Option<&Arc<ComputedValues>> {
        debug_assert!(pseudo.is_eager());
        self.0.as_ref().and_then(|p| p[pseudo.eager_index()].as_ref())
    }

    /// Sets the style for the eager pseudo.
    pub fn set(&mut self, pseudo: &PseudoElement, value: Arc<ComputedValues>) {
        if self.0.is_none() {
            self.0 = Some(Arc::new(Default::default()));
        }
        let arr = Arc::make_mut(self.0.as_mut().unwrap());
        arr[pseudo.eager_index()] = Some(value);
    }
}

/// The styles associated with a node, including the styles for any
/// pseudo-elements.
#[derive(Clone, Default)]
pub struct ElementStyles {
    /// The element's style.
    pub primary: Option<Arc<ComputedValues>>,
    /// A list of the styles for the element's eagerly-cascaded pseudo-elements.
    pub pseudos: EagerPseudoStyles,
}

impl ElementStyles {
    /// Returns the primary style.
    pub fn get_primary(&self) -> Option<&Arc<ComputedValues>> {
        self.primary.as_ref()
    }

    /// Returns the primary style.  Panic if no style available.
    pub fn primary(&self) -> &Arc<ComputedValues> {
        self.primary.as_ref().unwrap()
    }

    /// Whether this element `display` value is `none`.
    pub fn is_display_none(&self) -> bool {
        self.primary().get_box().clone_display() == display::T::none
    }
}

// We manually implement Debug for ElementStyles so that we can avoid the
// verbose stringification of every property in the ComputedValues. We
// substitute the rule node instead.
impl fmt::Debug for ElementStyles {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ElementStyles {{ primary: {:?}, pseudos: {:?} }}",
               self.primary.as_ref().map(|x| &x.rules), self.pseudos)
    }
}

/// Style system data associated with an Element.
///
/// In Gecko, this hangs directly off the Element. Servo, this is embedded
/// inside of layout data, which itself hangs directly off the Element. In
/// both cases, it is wrapped inside an AtomicRefCell to ensure thread safety.
#[derive(Debug, Default)]
pub struct ElementData {
    /// The styles for the element and its pseudo-elements.
    pub styles: ElementStyles,

    /// Restyle state.
    pub restyle: RestyleData,
}

/// The kind of restyle that a single element should do.
#[derive(Debug)]
pub enum RestyleKind {
    /// We need to run selector matching plus re-cascade, that is, a full
    /// restyle.
    MatchAndCascade,
    /// We need to recascade with some replacement rule, such as the style
    /// attribute, or animation rules.
    CascadeWithReplacements(RestyleHint),
    /// We only need to recascade, for example, because only inherited
    /// properties in the parent changed.
    CascadeOnly,
}

impl ElementData {
    /// Invalidates style for this element, its descendants, and later siblings,
    /// based on the snapshot of the element that we took when attributes or
    /// state changed.
    pub fn invalidate_style_if_needed<'a, E: TElement>(
        &mut self,
        element: E,
        shared_context: &SharedStyleContext)
    {
        // In animation-only restyle we shouldn't touch snapshot at all.
        if shared_context.traversal_flags.for_animation_only() {
            return;
        }

        use invalidation::element::invalidator::TreeStyleInvalidator;

        debug!("invalidate_style_if_needed: {:?}, flags: {:?}, has_snapshot: {}, \
                handled_snapshot: {}, pseudo: {:?}",
                element,
                shared_context.traversal_flags,
                element.has_snapshot(),
                element.handled_snapshot(),
                element.implemented_pseudo_element());

        if element.has_snapshot() && !element.handled_snapshot() {
            let invalidator = TreeStyleInvalidator::new(
                element,
                Some(self),
                shared_context,
            );
            invalidator.invalidate();
            unsafe { element.set_handled_snapshot() }
            debug_assert!(element.handled_snapshot());
        }
    }

    /// Returns true if this element has styles.
    pub fn has_styles(&self) -> bool {
        self.styles.primary.is_some()
    }

    /// Returns the kind of restyling that we're going to need to do on this
    /// element, based of the stored restyle hint.
    pub fn restyle_kind(
        &self,
        shared_context: &SharedStyleContext
    ) -> RestyleKind {
        if shared_context.traversal_flags.for_animation_only() {
            return self.restyle_kind_for_animation(shared_context);
        }

        if !self.has_styles() {
            return RestyleKind::MatchAndCascade;
        }

        let hint = self.restyle.hint;
        if hint.match_self() {
            return RestyleKind::MatchAndCascade;
        }

        if hint.has_replacements() {
            debug_assert!(!hint.has_animation_hint(),
                          "Animation only restyle hint should have already processed");
            return RestyleKind::CascadeWithReplacements(hint & RestyleHint::replacements());
        }

        debug_assert!(hint.has_recascade_self(),
                      "We definitely need to do something: {:?}!", hint);
        return RestyleKind::CascadeOnly;
    }

    /// Returns the kind of restyling for animation-only restyle.
    fn restyle_kind_for_animation(
        &self,
        shared_context: &SharedStyleContext,
    ) -> RestyleKind {
        debug_assert!(shared_context.traversal_flags.for_animation_only());
        debug_assert!(self.has_styles(),
                      "Unstyled element shouldn't be traversed during \
                       animation-only traversal");

        // return either CascadeWithReplacements or CascadeOnly in case of
        // animation-only restyle. I.e. animation-only restyle never does
        // selector matching.
        let hint = self.restyle.hint;
        if hint.has_animation_hint() {
            return RestyleKind::CascadeWithReplacements(hint & RestyleHint::for_animations());
        }

        return RestyleKind::CascadeOnly;
    }

    /// Return true if important rules are different.
    /// We use this to make sure the cascade of off-main thread animations is correct.
    /// Note: Ignore custom properties for now because we only support opacity and transform
    ///       properties for animations running on compositor. Actually, we only care about opacity
    ///       and transform for now, but it's fine to compare all properties and let the user
    ///       the check which properties do they want.
    ///       If it costs too much, get_properties_overriding_animations() should return a set
    ///       containing only opacity and transform properties.
    pub fn important_rules_are_different(
        &self,
        rules: &StrongRuleNode,
        guards: &StylesheetGuards
    ) -> bool {
        debug_assert!(self.has_styles());
        let (important_rules, _custom) =
            self.styles.primary().rules().get_properties_overriding_animations(&guards);
        let (other_important_rules, _custom) = rules.get_properties_overriding_animations(&guards);
        important_rules != other_important_rules
    }

    /// Drops any restyle state from the element.
    pub fn clear_restyle_state(&mut self) {
        self.restyle.clear();
    }

    /// Drops restyle flags and damage from the element.
    pub fn clear_restyle_flags_and_damage(&mut self) {
        self.restyle.clear_flags_and_damage();
    }
}
<|endoftext|>


<commit_before>extern crate c_ares;
extern crate mio;

use std::collections::HashSet;
use std::mem;
use std::os::unix::io;
use std::sync::mpsc;
use std::thread;

enum ResolverMessage {
    RegisterInterest(io::RawFd, bool, bool),
    ShutDown,
}

struct DNSResolver {
    ares_channel: c_ares::Channel,
    tracked_fds: HashSet<io::RawFd>,
}

impl mio::Handler for DNSResolver {
    type Timeout = usize;
    type Message = ResolverMessage;

    fn readable(
        &mut self,
        _event_loop: &mut mio::EventLoop<DNSResolver>,
        token: mio::Token,
        _read_hint: mio::ReadHint) {
        let fd = token.as_usize() as io::RawFd;
        self.ares_channel.process_fd(fd, c_ares::SOCKET_BAD);
    }

    fn writable(
        &mut self,
        _event_loop: &mut mio::EventLoop<DNSResolver>,
        token: mio::Token) {
        let fd = token.as_usize() as io::RawFd;
        self.ares_channel.process_fd(c_ares::SOCKET_BAD, fd);
    }

    fn notify(
        &mut self,
        event_loop:&mut mio::EventLoop<DNSResolver>,
        msg: Self::Message) {
        match msg {
            ResolverMessage::RegisterInterest(fd, readable, writable) => {
                let io = mio::Io::new(fd);
                if !readable && !writable {
                    self.tracked_fds.remove(&fd);
                    event_loop
                        .deregister(&io)
                        .ok()
                        .expect("failed to deregister interest");
                } else {
                    let mut interest = mio::Interest::none();
                    if readable {
                        interest = interest | mio::Interest::readable();
                    }
                    if writable {
                        interest = interest | mio::Interest::writable();
                    }
                    let token = mio::Token(fd as usize);
                    let insert_result = if !self.tracked_fds.insert(fd) {
                        event_loop
                            .reregister(
                                &io,
                                token,
                                interest,
                                mio::PollOpt::level())
                    } else {
                        event_loop
                            .register_opt(
                                &io,
                                token,
                                interest,
                                mio::PollOpt::level())
                    };
                    insert_result.ok().expect("failed to register interest");
                }

                // Don't close the file descriptor by dropping io.
                mem::forget(io);
            },

            ResolverMessage::ShutDown => event_loop.shutdown(),
        }
    }
}

impl DNSResolver {
    fn new<F>(callback: F) -> DNSResolver
        where F: FnOnce(io::RawFd, bool, bool) + 'static {
        let ares_channel = c_ares::Channel::new(callback)
            .ok()
            .expect("Failed to create channel");
        DNSResolver {
            ares_channel: ares_channel,
            tracked_fds: HashSet::new(),
        }
    }

    fn query_a<F>(&mut self, name: &str, callback: F)
        where F: FnOnce(Result<c_ares::AResult, c_ares::AresError>) + 'static {
        self.ares_channel.query_a(name, callback);
    }

    fn query_aaaa<F>(&mut self, name: &str, callback: F)
        where F: FnOnce(Result<c_ares::AAAAResult, c_ares::AresError>) + 'static {
        self.ares_channel.query_aaaa(name, callback);
    }
}

fn print_a_result(result: Result<c_ares::AResult, c_ares::AresError>) {
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("Lookup failed with error '{:}'", err_string);
        }
        Ok(result) => {
            println!("Successful lookup...");
            for addr in &result.ip_addrs {
                println!("{:}", addr);
            }
        }
    }
}

fn print_aaaa_result(result: Result<c_ares::AAAAResult, c_ares::AresError>) {
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("Lookup failed with error '{:}'", err_string);
        }
        Ok(result) => {
            println!("Successful lookup...");
            for addr in &result.ip_addrs {
                println!("{:}", addr);
            }
        }
    }
}

fn main() {
    // Create an event loop and a DNSResolver.
    let mut event_loop = mio::EventLoop::new()
        .ok()
        .expect("failed to create event loop");
    let event_loop_channel = event_loop.channel();
    let ev_channel_clone = event_loop_channel.clone();
    let sock_callback = move |fd: io::RawFd, readable: bool, writable: bool| {
        ev_channel_clone
            .send(ResolverMessage::RegisterInterest(fd, readable, writable))
            .ok()
            .expect("Failed to send RegisterInterest");
    };
    let mut resolver = DNSResolver::new(sock_callback);

    // Set up a couple of queries.
    let (results_tx, results_rx) = mpsc::channel();
    let tx = results_tx.clone();
    resolver.query_a("apple.com", move |result| {
        print_a_result(result);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    resolver.query_aaaa("google.com", move |result| {
        print_aaaa_result(result);
        tx.send(()).unwrap()
    });

    // Kick off the event loop.
    thread::spawn(move || {
        event_loop
            .run(&mut resolver)
            .ok()
            .expect("failed to run event loop")
    });

    // Wait for results to roll in.
    for _ in 0..2 {
        results_rx.recv().unwrap();
    }

    // Shut down event loop.
    event_loop_channel
        .send(ResolverMessage::ShutDown)
        .ok()
        .expect("failed to shut down event loop");
}
<commit_msg>Clarify example<commit_after>extern crate c_ares;
extern crate mio;

use std::collections::HashSet;
use std::mem;
use std::os::unix::io;
use std::sync::mpsc;
use std::thread;

enum CAresHandlerMessage {
    RegisterInterest(io::RawFd, bool, bool),
    ShutDown,
}

struct CAresEventHandler {
    ares_channel: c_ares::Channel,
    tracked_fds: HashSet<io::RawFd>,
}

impl mio::Handler for CAresEventHandler {
    type Timeout = usize;
    type Message = CAresHandlerMessage;

    fn readable(
        &mut self,
        _event_loop: &mut mio::EventLoop<CAresEventHandler>,
        token: mio::Token,
        _read_hint: mio::ReadHint) {
        let fd = token.as_usize() as io::RawFd;
        self.ares_channel.process_fd(fd, c_ares::SOCKET_BAD);
    }

    fn writable(
        &mut self,
        _event_loop: &mut mio::EventLoop<CAresEventHandler>,
        token: mio::Token) {
        let fd = token.as_usize() as io::RawFd;
        self.ares_channel.process_fd(c_ares::SOCKET_BAD, fd);
    }

    fn notify(
        &mut self,
        event_loop:&mut mio::EventLoop<CAresEventHandler>,
        msg: Self::Message) {
        match msg {
            CAresHandlerMessage::RegisterInterest(fd, readable, writable) => {
                let io = mio::Io::new(fd);
                if !readable && !writable {
                    self.tracked_fds.remove(&fd);
                    event_loop
                        .deregister(&io)
                        .ok()
                        .expect("failed to deregister interest");
                } else {
                    let mut interest = mio::Interest::none();
                    if readable {
                        interest = interest | mio::Interest::readable();
                    }
                    if writable {
                        interest = interest | mio::Interest::writable();
                    }
                    let token = mio::Token(fd as usize);
                    let insert_result = if !self.tracked_fds.insert(fd) {
                        event_loop
                            .reregister(
                                &io,
                                token,
                                interest,
                                mio::PollOpt::level())
                    } else {
                        event_loop
                            .register_opt(
                                &io,
                                token,
                                interest,
                                mio::PollOpt::level())
                    };
                    insert_result.ok().expect("failed to register interest");
                }

                // Don't close the file descriptor by dropping io.
                mem::forget(io);
            },

            CAresHandlerMessage::ShutDown => event_loop.shutdown(),
        }
    }
}

impl CAresEventHandler {
    fn new(ares_channel: c_ares::Channel) -> CAresEventHandler {
        CAresEventHandler {
            ares_channel: ares_channel,
            tracked_fds: HashSet::new(),
        }
    }
}

fn print_a_result(result: Result<c_ares::AResult, c_ares::AresError>) {
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("Lookup failed with error '{:}'", err_string);
        }
        Ok(result) => {
            println!("Successful lookup...");
            for addr in &result.ip_addrs {
                println!("{:}", addr);
            }
        }
    }
}

fn print_aaaa_result(result: Result<c_ares::AAAAResult, c_ares::AresError>) {
    match result {
        Err(e) => {
            let err_string = c_ares::str_error(e);
            println!("Lookup failed with error '{:}'", err_string);
        }
        Ok(result) => {
            println!("Successful lookup...");
            for addr in &result.ip_addrs {
                println!("{:}", addr);
            }
        }
    }
}

fn main() {
    // Create an event loop, and a c_ares::Channel.
    let mut event_loop = mio::EventLoop::new()
        .ok()
        .expect("failed to create event loop");
    let event_loop_channel = event_loop.channel();
    let ev_channel_clone = event_loop_channel.clone();
    let sock_callback = move |fd: io::RawFd, readable: bool, writable: bool| {
        ev_channel_clone
            .send(CAresHandlerMessage::RegisterInterest(fd, readable, writable))
            .ok()
            .expect("Failed to send RegisterInterest");
    };
    let mut ares_channel = c_ares::Channel::new(sock_callback)
        .ok()
        .expect("Failed to create channel");

    // Set up a couple of queries.
    let (results_tx, results_rx) = mpsc::channel();
    let tx = results_tx.clone();
    ares_channel.query_a("apple.com", move |result| {
        print_a_result(result);
        tx.send(()).unwrap()
    });

    let tx = results_tx.clone();
    ares_channel.query_aaaa("google.com", move |result| {
        print_aaaa_result(result);
        tx.send(()).unwrap()
    });

    // Kick off the event loop.
    let mut event_handler = CAresEventHandler::new(ares_channel);
    thread::spawn(move || {
        event_loop
            .run(&mut event_handler)
            .ok()
            .expect("failed to run event loop")
    });

    // Wait for results to roll in.
    for _ in 0..2 {
        results_rx.recv().unwrap();
    }

    // Shut down event loop.
    event_loop_channel
        .send(CAresHandlerMessage::ShutDown)
        .ok()
        .expect("failed to shut down event loop");
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use std::fmt;

use counter::Counter;

/// Given a list of poker hands, return a list of those hands which win.
///
/// Note the type signature: this function should return _the same_ reference to
/// the winning hand(s) as were passed in, not reconstructed strings which happen to be equal.
pub fn winning_hands<'a>(hands: &[&'a str]) -> Option<Vec<&'a str>> {
    let mut hands = hands
        .iter()
        .map(|source| Hand::try_from(source))
        .collect::<Option<Vec<Hand>>>()?;
    hands.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Less));
    hands.last().map(|last| {
        hands
            .iter()
            .rev()
            .take_while(|&item| item.partial_cmp(last) == Some(Ordering::Equal))
            .map(|hand| hand.source)
            .collect()
    })
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Copy, Hash)]
enum Suit {
    Spades,
    Clubs,
    Diamonds,
    Hearts,
}

impl Suit {
    fn try_from(source: &str) -> Option<Suit> {
        use crate::Suit::*;
        match source {
            "S" => Some(Spades),
            "C" => Some(Clubs),
            "D" => Some(Diamonds),
            "H" => Some(Hearts),
            _ => None,
        }
    }
}

impl fmt::Display for Suit {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use crate::Suit::*;
        write!(
            f,
            "{}",
            match *self {
                Spades => "S",
                Clubs => "C",
                Diamonds => "D",
                Hearts => "H",
            }
        )
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
enum Rank {
    Number(u8),
    Jack,
    Queen,
    King,
    Ace,
}

impl Rank {
    fn try_from(source: &str) -> Option<Rank> {
        use crate::Rank::*;
        match source {
            "A" => Some(Ace),
            "K" => Some(King),
            "Q" => Some(Queen),
            "J" => Some(Jack),
            "10" => Some(Number(10)),
            "9" => Some(Number(9)),
            "8" => Some(Number(8)),
            "7" => Some(Number(7)),
            "6" => Some(Number(6)),
            "5" => Some(Number(5)),
            "4" => Some(Number(4)),
            "3" => Some(Number(3)),
            "2" => Some(Number(2)),
            _ => None,
        }
    }

    fn value(&self) -> usize {
        use crate::Rank::*;
        match *self {
            Ace => 14,
            King => 13,
            Queen => 12,
            Jack => 11,
            Number(n) => n as usize,
        }
    }
}

impl fmt::Display for Rank {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use crate::Rank::*;
        let num_str; // early declaration to placate NLL of Number case
        write!(
            f,
            "{}",
            match *self {
                Ace => "A",
                King => "K",
                Queen => "Q",
                Jack => "J",
                Number(n) => {
                    num_str = n.to_string();
                    &num_str
                }
            }
        )
    }
}

impl PartialOrd for Rank {
    fn partial_cmp(&self, other: &Rank) -> Option<Ordering> {
        Some(self.value().cmp(&other.value()))
    }
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Copy)]
struct Card {
    rank: Rank,
    suit: Suit,
}

impl Card {
    fn try_from_split(source: &str, split: usize) -> Option<Card> {
        Some(Card {
            rank: Rank::try_from(&source[..split])?,
            suit: Suit::try_from(&source[split..])?,
        })
    }

    fn try_from(source: &str) -> Option<Card> {
        match source.len() {
            3 => Card::try_from_split(source, 2),
            2 => Card::try_from_split(source, 1),
            _ => None,
        }
    }
}

impl fmt::Display for Card {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}{}", self.rank, self.suit)
    }
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
enum PokerHand {
    HighCard,
    OnePair,
    TwoPair,
    ThreeOfAKind,
    Straight,
    Flush,
    FullHouse,
    FourOfAKind,
    StraightFlush,
}

impl PokerHand {
    fn is_ace_low_straight(cards: &[Card]) -> bool {
        // special case: ace-low straight
        // still depends on the sorted precondition
        cards[0].rank.value() == 2
            && cards[4].rank == Rank::Ace
            && cards
                .windows(2)
                .take(3) // (0, 1), (1, 2), (2, 3) --> skips 4, ace
                .map(|pair| pair[1].rank.value() - pair[0].rank.value())
                .all(|diff| diff == 1)
    }

    fn analyze(cards: &[Card]) -> Option<PokerHand> {
        if cards.len() == 5 {
            let suit_counter = cards.iter().map(|c| c.suit).collect::<Counter<_>>();
            let is_flush = suit_counter
                .most_common()
                .into_iter()
                .map(|(_suit, count)| count)
                .next()
                == Some(5);
            // Note that `is_straight` depends on a precondition: it only works
            // if the input `cards` are sorted by rank value ascending.
            let is_straight = cards
                .windows(2)
                .map(|pair| pair[1].rank.value() - pair[0].rank.value())
                .all(|diff| diff == 1)
                || PokerHand::is_ace_low_straight(cards);

            if is_flush && is_straight {
                return Some(PokerHand::StraightFlush);
            }

            let rank_counter = cards.iter().map(|c| c.rank).collect::<Counter<_>>();
            let mut rc_iter = rank_counter.most_common().into_iter().map(|(_rank, count)| count);
            let rc_most = rc_iter.next();
            let rc_second = rc_iter.next();

            if rc_most == Some(4) {
                return Some(PokerHand::FourOfAKind);
            }
            if rc_most == Some(3) && rc_second == Some(2) {
                return Some(PokerHand::FullHouse);
            }
            if is_flush {
                return Some(PokerHand::Flush);
            }
            if is_straight {
                return Some(PokerHand::Straight);
            }
            if rc_most == Some(3) {
                return Some(PokerHand::ThreeOfAKind);
            }
            if rc_most == Some(2) && rc_second == Some(2) {
                return Some(PokerHand::TwoPair);
            }
            if rc_most == Some(2) {
                return Some(PokerHand::OnePair);
            }
            Some(PokerHand::HighCard)
        } else {
            None
        }
    }
}

#[derive(Debug, PartialEq, Eq)]
struct Hand<'a> {
    source: &'a str,
    cards: [Card; 5],
    hand_type: PokerHand,
}

impl<'a> Hand<'a> {
    fn try_from(source: &'a str) -> Option<Hand> {
        let mut cards = source
            .split_whitespace()
            .map(|s| Card::try_from(s))
            .collect::<Option<Vec<Card>>>()?;
        cards.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Less));
        if cards.len() == 5 {
            Some(Hand {
                source,
                cards: [cards[0], cards[1], cards[2], cards[3], cards[4]],
                hand_type: PokerHand::analyze(&cards)?,
            })
        } else {
            None
        }
    }

    fn cmp_high_card(&self, other: &Hand, card: usize) -> Ordering {
        let mut ordering = self.cards[card]
            .rank
            .value()
            .cmp(&other.cards[card].rank.value());
        if card != 0 {
            ordering = ordering.then_with(|| self.cmp_high_card(other, card - 1));
        }
        ordering
    }

    fn value_by_frequency(&self) -> (Option<Rank>, Option<Rank>, Option<Rank>) {
        let rank_counter = self.cards.iter().map(|c| c.rank).collect::<Counter<_>>();
        let mut rc_iter = rank_counter
            .most_common_tiebreaker(|a, b| b.partial_cmp(a).unwrap_or(Ordering::Less))
            .into_iter()
            .map(|(rank, _count)| rank);
        (rc_iter.next(), rc_iter.next(), rc_iter.next())
    }

    fn cmp_cascade_by_freq(&self, other: &Hand) -> Ordering {
        let (s1, s2, s3) = self.value_by_frequency();
        let (o1, o2, o3) = other.value_by_frequency();
        s1.partial_cmp(&o1)
            .map(|c| {
                c.then(
                    s2.partial_cmp(&o2)
                        .map(|c2| c2.then(s3.partial_cmp(&o3).unwrap_or(Ordering::Equal)))
                        .unwrap_or(Ordering::Equal),
                )
            })
            .unwrap_or(Ordering::Equal)
    }

    fn cmp_straight(&self, other: &Hand) -> Ordering {
        let s = if PokerHand::is_ace_low_straight(&self.cards) {
            5
        } else {
            self.cards[4].rank.value()
        };
        let o = if PokerHand::is_ace_low_straight(&other.cards) {
            5
        } else {
            other.cards[4].rank.value()
        };
        s.cmp(&o)
    }
}

impl<'a> fmt::Display for Hand<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.source)
    }
}

impl<'a> PartialOrd for Hand<'a> {
    fn partial_cmp(&self, other: &Hand) -> Option<Ordering> {
        Some(self.hand_type.cmp(&other.hand_type).then_with(|| {
            use crate::PokerHand::*;
            match self.hand_type {
                HighCard => self.cmp_high_card(other, 4),
                OnePair => self.cmp_cascade_by_freq(other),
                TwoPair => self.cmp_cascade_by_freq(other),
                ThreeOfAKind => self.cmp_cascade_by_freq(other),
                Straight => self.cmp_straight(other),
                Flush => self.cmp_high_card(other, 4),
                FullHouse => self.cmp_cascade_by_freq(other),
                FourOfAKind => self.cmp_cascade_by_freq(other),
                StraightFlush => self.cmp_straight(other),
            }
        }))
    }
}
<commit_msg>using 'TryFrom' and 'Result' (#969)<commit_after>use std::{cmp::Ordering, convert::TryFrom};
use std::fmt;

use counter::Counter;

/// Given a list of poker hands, return a list of those hands which win.
///
/// Note the type signature: this function should return _the same_ reference to
/// the winning hand(s) as were passed in, not reconstructed strings which happen to be equal.
pub fn winning_hands<'a>(hands: &[&'a str]) -> Option<Vec<&'a str>> {
    let mut hands = hands
        .into_iter()
        .map(|source| Hand::try_from(*source))
        .collect::<Result<Vec<_>, _>>().ok()?;
    hands.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Less));
    hands.last().map(|last| {
        hands
            .iter()
            .rev()
            .take_while(|&item| item.partial_cmp(last) == Some(Ordering::Equal))
            .map(|hand| hand.source)
            .collect()
    })
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Copy, Hash)]
enum Suit {
    Spades,
    Clubs,
    Diamonds,
    Hearts,
}

impl fmt::Display for Suit {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use crate::Suit::*;
        write!(
            f,
            "{}",
            match *self {
                Spades => "S",
                Clubs => "C",
                Diamonds => "D",
                Hearts => "H",
            }
        )
    }
}

impl<'a> TryFrom<&'a str> for Suit {
    type Error = &'static str;

    fn try_from(source: &str) -> Result<Self, Self::Error> {
        use crate::Suit::*;
        match source {
            "S" => Ok(Spades),
            "C" => Ok(Clubs),
            "D" => Ok(Diamonds),
            "H" => Ok(Hearts),
            _ => Err("Invalid suit"),
        }
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
enum Rank {
    Number(u8),
    Jack,
    Queen,
    King,
    Ace,
}

impl Rank {
    fn value(&self) -> usize {
        use crate::Rank::*;
        match *self {
            Ace => 14,
            King => 13,
            Queen => 12,
            Jack => 11,
            Number(n) => n as usize,
        }
    }
}

impl fmt::Display for Rank {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use crate::Rank::*;
        let num_str; // early declaration to placate NLL of Number case
        write!(
            f,
            "{}",
            match *self {
                Ace => "A",
                King => "K",
                Queen => "Q",
                Jack => "J",
                Number(n) => {
                    num_str = n.to_string();
                    &num_str
                }
            }
        )
    }
}

impl PartialOrd for Rank {
    fn partial_cmp(&self, other: &Rank) -> Option<Ordering> {
        Some(self.value().cmp(&other.value()))
    }
}

impl<'a> TryFrom<&'a str> for Rank {
    type Error = &'static str;

    fn try_from(source: &str) -> Result<Self, Self::Error> {
        use crate::Rank::*;
        match source {
            "A" => Ok(Ace),
            "K" => Ok(King),
            "Q" => Ok(Queen),
            "J" => Ok(Jack),
            "10" => Ok(Number(10)),
            "9" => Ok(Number(9)),
            "8" => Ok(Number(8)),
            "7" => Ok(Number(7)),
            "6" => Ok(Number(6)),
            "5" => Ok(Number(5)),
            "4" => Ok(Number(4)),
            "3" => Ok(Number(3)),
            "2" => Ok(Number(2)),
            _ => Err("Invalid rank"),
        }
    }
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Copy)]
struct Card {
    rank: Rank,
    suit: Suit,
}

impl Card {
    fn try_from_split(source: &str, split: usize) -> Result<Self, &'static str> {
        Ok(Card {
            rank: Rank::try_from(&source[..split])?,
            suit: Suit::try_from(&source[split..])?,
        })
    }
}

impl fmt::Display for Card {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}{}", self.rank, self.suit)
    }
}

impl<'a> TryFrom<&'a str> for Card {
    type Error = &'static str;

    fn try_from(source: &str) -> Result<Self, Self::Error> {
        match source.len() {
            3 => Card::try_from_split(source, 2),
            2 => Card::try_from_split(source, 1),
            _ => Err("Invalid card"),
        }
    }
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
enum PokerHand {
    HighCard,
    OnePair,
    TwoPair,
    ThreeOfAKind,
    Straight,
    Flush,
    FullHouse,
    FourOfAKind,
    StraightFlush,
}

impl PokerHand {
    fn is_ace_low_straight(cards: &[Card]) -> bool {
        // special case: ace-low straight
        // still depends on the sorted precondition
        cards[0].rank.value() == 2
            && cards[4].rank == Rank::Ace
            && cards
                .windows(2)
                .take(3) // (0, 1), (1, 2), (2, 3) --> skips 4, ace
                .map(|pair| pair[1].rank.value() - pair[0].rank.value())
                .all(|diff| diff == 1)
    }

    fn analyze(cards: &[Card]) -> Result<Self, &'static str> {
        if cards.len() == 5 {
            let suit_counter = cards.iter().map(|c| c.suit).collect::<Counter<_>>();
            let is_flush = suit_counter
                .most_common()
                .into_iter()
                .map(|(_suit, count)| count)
                .next()
                == Some(5);
            // Note that `is_straight` depends on a precondition: it only works
            // if the input `cards` are sorted by rank value ascending.
            let is_straight = cards
                .windows(2)
                .map(|pair| pair[1].rank.value() - pair[0].rank.value())
                .all(|diff| diff == 1)
                || PokerHand::is_ace_low_straight(cards);

            if is_flush && is_straight {
                return Ok(PokerHand::StraightFlush);
            }

            let rank_counter = cards.iter().map(|c| c.rank).collect::<Counter<_>>();
            let mut rc_iter = rank_counter.most_common().into_iter().map(|(_rank, count)| count);
            let rc_most = rc_iter.next();
            let rc_second = rc_iter.next();

            if rc_most == Some(4) {
                return Ok(PokerHand::FourOfAKind);
            }
            if rc_most == Some(3) && rc_second == Some(2) {
                return Ok(PokerHand::FullHouse);
            }
            if is_flush {
                return Ok(PokerHand::Flush);
            }
            if is_straight {
                return Ok(PokerHand::Straight);
            }
            if rc_most == Some(3) {
                return Ok(PokerHand::ThreeOfAKind);
            }
            if rc_most == Some(2) && rc_second == Some(2) {
                return Ok(PokerHand::TwoPair);
            }
            if rc_most == Some(2) {
                return Ok(PokerHand::OnePair);
            }
            Ok(PokerHand::HighCard)
        } else {
            Err("Not a hand of five")
        }
    }
}

#[derive(Debug, PartialEq, Eq)]
struct Hand<'a> {
    source: &'a str,
    cards: [Card; 5],
    hand_type: PokerHand,
}

impl<'a> Hand<'a> {

    fn cmp_high_card(&self, other: &Hand, card: usize) -> Ordering {
        let mut ordering = self.cards[card]
            .rank
            .value()
            .cmp(&other.cards[card].rank.value());
        if card != 0 {
            ordering = ordering.then_with(|| self.cmp_high_card(other, card - 1));
        }
        ordering
    }

    fn value_by_frequency(&self) -> (Option<Rank>, Option<Rank>, Option<Rank>) {
        let rank_counter = self.cards.iter().map(|c| c.rank).collect::<Counter<_>>();
        let mut rc_iter = rank_counter
            .most_common_tiebreaker(|a, b| b.partial_cmp(a).unwrap_or(Ordering::Less))
            .into_iter()
            .map(|(rank, _count)| rank);
        (rc_iter.next(), rc_iter.next(), rc_iter.next())
    }

    fn cmp_cascade_by_freq(&self, other: &Hand) -> Ordering {
        let (s1, s2, s3) = self.value_by_frequency();
        let (o1, o2, o3) = other.value_by_frequency();
        s1.partial_cmp(&o1)
            .map(|c| {
                c.then(
                    s2.partial_cmp(&o2)
                        .map(|c2| c2.then(s3.partial_cmp(&o3).unwrap_or(Ordering::Equal)))
                        .unwrap_or(Ordering::Equal),
                )
            })
            .unwrap_or(Ordering::Equal)
    }

    fn cmp_straight(&self, other: &Hand) -> Ordering {
        let s = if PokerHand::is_ace_low_straight(&self.cards) {
            5
        } else {
            self.cards[4].rank.value()
        };
        let o = if PokerHand::is_ace_low_straight(&other.cards) {
            5
        } else {
            other.cards[4].rank.value()
        };
        s.cmp(&o)
    }
}

impl<'a> fmt::Display for Hand<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.source)
    }
}

impl<'a> PartialOrd for Hand<'a> {
    fn partial_cmp(&self, other: &Hand) -> Option<Ordering> {
        Some(self.hand_type.cmp(&other.hand_type).then_with(|| {
            use crate::PokerHand::*;
            match self.hand_type {
                HighCard => self.cmp_high_card(other, 4),
                OnePair => self.cmp_cascade_by_freq(other),
                TwoPair => self.cmp_cascade_by_freq(other),
                ThreeOfAKind => self.cmp_cascade_by_freq(other),
                Straight => self.cmp_straight(other),
                Flush => self.cmp_high_card(other, 4),
                FullHouse => self.cmp_cascade_by_freq(other),
                FourOfAKind => self.cmp_cascade_by_freq(other),
                StraightFlush => self.cmp_straight(other),
            }
        }))
    }
}

impl<'a> TryFrom<&'a str> for Hand<'a> {
    type Error = &'static str;

    fn try_from(source: &'a str) -> Result<Self, Self::Error> {
        let mut cards = source
            .split_whitespace()
            .map(Card::try_from)
            .collect::<Result<Vec<_>, _>>()?;
        cards.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Less));
        if cards.len() == 5 {
            Ok(Hand {
                source,
                cards: [cards[0], cards[1], cards[2], cards[3], cards[4]],
                hand_type: PokerHand::analyze(&cards)?,
            })
        } else {
            Err("Invalid hand")
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 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.

//! The proof of work needs to strike a balance between fast header
//! verification to avoid DoS attacks and difficulty for block verifiers to
//! build new blocks. In addition, mining new blocks should also be as
//! difficult on high end custom-made hardware (ASICs) as on commodity hardware
//! or smartphones. For this reason we use Cuckoo Cycle (see the cuckoo
//! module for more information).
//!
//! Note that this miner implementation is here mostly for tests and
//! reference. It's not optimized for speed.

mod siphash;
pub mod cuckoo;

use time;

use consensus::EASINESS;
use core::{Block, Proof};
use core::hash::{Hash, Hashed};
use core::target::Target;
use pow::cuckoo::{Cuckoo, Miner, Error};

use ser;
use ser::{Writeable, Writer};

/// Subset of a block header that goes into hashing for proof of work.
/// Basically the whole thing minus the PoW solution itself and the total
/// difficulty (yet unknown). We also add the count of every variable length
/// elements in a header to make lying on those much harder.
#[derive(Debug)]
pub struct PowHeader {
	pub nonce: u64,
	pub height: u64,
	pub previous: Hash,
	pub timestamp: time::Tm,
	pub utxo_merkle: Hash,
	pub tx_merkle: Hash,
	pub n_in: u64,
	pub n_out: u64,
	pub n_proofs: u64,
}

/// The binary definition of a PoW header is material for consensus as that's
/// the data that gets hashed for PoW calculation. The nonce is written first
/// to make incrementing from the serialized form trivial.
impl Writeable for PowHeader {
	fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
		try!(writer.write_u64(self.nonce));
		try!(writer.write_u64(self.height));
		try!(writer.write_fixed_bytes(&self.previous));
		try!(writer.write_i64(self.timestamp.to_timespec().sec));
		try!(writer.write_fixed_bytes(&self.utxo_merkle));
		try!(writer.write_fixed_bytes(&self.tx_merkle));
		try!(writer.write_u64(self.n_in));
		try!(writer.write_u64(self.n_out));
		writer.write_u64(self.n_proofs)
	}
}

impl PowHeader {
	pub fn from_block(b: &Block) -> PowHeader {
		let ref h = b.header;
		PowHeader {
			nonce: h.nonce,
			height: h.height,
			previous: h.previous,
			timestamp: h.timestamp,
			utxo_merkle: h.utxo_merkle,
			tx_merkle: h.tx_merkle,
			n_in: b.inputs.len() as u64,
			n_out: b.outputs.len() as u64,
			n_proofs: b.proofs.len() as u64,
		}
	}
}

/// Validates the proof of work of a given header.
pub fn verify(b: &Block) -> bool {
	verify_size(b, b.header.cuckoo_len as u32)
}

/// Same as default verify function but uses the much easier Cuckoo20 (mostly
/// for tests).
pub fn verify20(b: &Block) -> bool {
	verify_size(b, 20)
}

pub fn verify_size(b: &Block, sizeshift: u32) -> bool {
	let hash = PowHeader::from_block(b).hash();
	// make sure the hash is smaller than our target before going into more
	// expensive validation
	if b.header.target < b.header.pow.to_target() {
		return false;
	}
	Cuckoo::new(hash.to_slice(), sizeshift).verify(b.header.pow, EASINESS as u64)
}

/// Runs a naive single-threaded proof of work computation over the provided
/// block, until the required difficulty target is reached. May take a
/// while for a low target...
pub fn pow(b: &Block, target: Target) -> Result<(Proof, u64), Error> {
	pow_size(b, target, b.header.cuckoo_len as u32)
}

/// Same as default pow function but uses the much easier Cuckoo20 (mostly for
/// tests).
pub fn pow20(b: &Block, target: Target) -> Result<(Proof, u64), Error> {
	pow_size(b, target, 20)
}

fn pow_size(b: &Block, target: Target, sizeshift: u32) -> Result<(Proof, u64), Error> {
	let mut pow_header = PowHeader::from_block(b);
	let start_nonce = pow_header.nonce;

	// try to find a cuckoo cycle on that header hash
	loop {
		// can be trivially optimized by avoiding re-serialization every time but this
		// is not meant as a fast miner implementation
		let pow_hash = pow_header.hash();

		// if we found a cycle (not guaranteed) and the proof is lower that the target,
		// we're all good
		if let Ok(proof) = Miner::new(pow_hash.to_slice(), EASINESS, sizeshift).mine() {
			if proof.to_target() <= target {
				return Ok((proof, pow_header.nonce));
			}
		}

		// otherwise increment the nonce
		pow_header.nonce += 1;

		// and if we're back where we started, update the time (changes the hash as
		// well)
		if pow_header.nonce == start_nonce {
			pow_header.timestamp = time::at_utc(time::Timespec { sec: 0, nsec: 0 });
		}
	}
}

#[cfg(test)]
mod test {
	use super::*;
	use consensus::MAX_TARGET;
	use core::Proof;
	use genesis;

	#[test]
	fn genesis_pow() {
		let mut b = genesis::genesis();
		let (proof, nonce) = pow20(&b, MAX_TARGET).unwrap();
		assert!(nonce > 0);
		assert!(proof.to_target() < MAX_TARGET);
		b.header.pow = proof;
		b.header.nonce = nonce;
		assert!(verify20(&b));
	}
}
<commit_msg>Any size pow accesible to tests.<commit_after>// Copyright 2016 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.

//! The proof of work needs to strike a balance between fast header
//! verification to avoid DoS attacks and difficulty for block verifiers to
//! build new blocks. In addition, mining new blocks should also be as
//! difficult on high end custom-made hardware (ASICs) as on commodity hardware
//! or smartphones. For this reason we use Cuckoo Cycle (see the cuckoo
//! module for more information).
//!
//! Note that this miner implementation is here mostly for tests and
//! reference. It's not optimized for speed.

mod siphash;
pub mod cuckoo;

use time;

use consensus::EASINESS;
use core::{Block, Proof};
use core::hash::{Hash, Hashed};
use core::target::Target;
use pow::cuckoo::{Cuckoo, Miner, Error};

use ser;
use ser::{Writeable, Writer};

/// Subset of a block header that goes into hashing for proof of work.
/// Basically the whole thing minus the PoW solution itself and the total
/// difficulty (yet unknown). We also add the count of every variable length
/// elements in a header to make lying on those much harder.
#[derive(Debug)]
pub struct PowHeader {
	pub nonce: u64,
	pub height: u64,
	pub previous: Hash,
	pub timestamp: time::Tm,
	pub utxo_merkle: Hash,
	pub tx_merkle: Hash,
	pub n_in: u64,
	pub n_out: u64,
	pub n_proofs: u64,
}

/// The binary definition of a PoW header is material for consensus as that's
/// the data that gets hashed for PoW calculation. The nonce is written first
/// to make incrementing from the serialized form trivial.
impl Writeable for PowHeader {
	fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
		try!(writer.write_u64(self.nonce));
		try!(writer.write_u64(self.height));
		try!(writer.write_fixed_bytes(&self.previous));
		try!(writer.write_i64(self.timestamp.to_timespec().sec));
		try!(writer.write_fixed_bytes(&self.utxo_merkle));
		try!(writer.write_fixed_bytes(&self.tx_merkle));
		try!(writer.write_u64(self.n_in));
		try!(writer.write_u64(self.n_out));
		writer.write_u64(self.n_proofs)
	}
}

impl PowHeader {
	pub fn from_block(b: &Block) -> PowHeader {
		let ref h = b.header;
		PowHeader {
			nonce: h.nonce,
			height: h.height,
			previous: h.previous,
			timestamp: h.timestamp,
			utxo_merkle: h.utxo_merkle,
			tx_merkle: h.tx_merkle,
			n_in: b.inputs.len() as u64,
			n_out: b.outputs.len() as u64,
			n_proofs: b.proofs.len() as u64,
		}
	}
}

/// Validates the proof of work of a given header.
pub fn verify(b: &Block) -> bool {
	verify_size(b, b.header.cuckoo_len as u32)
}

/// Same as default verify function but uses the much easier Cuckoo20 (mostly
/// for tests).
pub fn verify20(b: &Block) -> bool {
	verify_size(b, 20)
}

pub fn verify_size(b: &Block, sizeshift: u32) -> bool {
	let hash = PowHeader::from_block(b).hash();
	// make sure the hash is smaller than our target before going into more
	// expensive validation
	if b.header.target < b.header.pow.to_target() {
		return false;
	}
	Cuckoo::new(hash.to_slice(), sizeshift).verify(b.header.pow, EASINESS as u64)
}

/// Runs a naive single-threaded proof of work computation over the provided
/// block, until the required difficulty target is reached. May take a
/// while for a low target...
pub fn pow(b: &Block, target: Target) -> Result<(Proof, u64), Error> {
	pow_size(b, target, b.header.cuckoo_len as u32)
}

/// Same as default pow function but uses the much easier Cuckoo20 (mostly for
/// tests).
pub fn pow20(b: &Block, target: Target) -> Result<(Proof, u64), Error> {
	pow_size(b, target, 20)
}

pub fn pow_size(b: &Block, target: Target, sizeshift: u32) -> Result<(Proof, u64), Error> {
	let mut pow_header = PowHeader::from_block(b);
	let start_nonce = pow_header.nonce;

	// try to find a cuckoo cycle on that header hash
	loop {
		// can be trivially optimized by avoiding re-serialization every time but this
		// is not meant as a fast miner implementation
		let pow_hash = pow_header.hash();

		// if we found a cycle (not guaranteed) and the proof is lower that the target,
		// we're all good
		if let Ok(proof) = Miner::new(pow_hash.to_slice(), EASINESS, sizeshift).mine() {
			if proof.to_target() <= target {
				return Ok((proof, pow_header.nonce));
			}
		}

		// otherwise increment the nonce
		pow_header.nonce += 1;

		// and if we're back where we started, update the time (changes the hash as
		// well)
		if pow_header.nonce == start_nonce {
			pow_header.timestamp = time::at_utc(time::Timespec { sec: 0, nsec: 0 });
		}
	}
}

#[cfg(test)]
mod test {
	use super::*;
	use consensus::MAX_TARGET;
	use core::Proof;
	use genesis;

	#[test]
	fn genesis_pow() {
		let mut b = genesis::genesis();
		let (proof, nonce) = pow20(&b, MAX_TARGET).unwrap();
		assert!(nonce > 0);
		assert!(proof.to_target() < MAX_TARGET);
		b.header.pow = proof;
		b.header.nonce = nonce;
		assert!(verify20(&b));
	}
}
<|endoftext|>


<commit_before>use ast;
use lexer;
use parser;

use interp::env;
use interp::types;

use core::hashmap::linear;
use core::to_bytes;

/*
 * aster - AST EvaulatoR
 *
 * aster evaluates a Prismo program via reduction of the AST.
 *
 * "It's pretty terrible."
 * -- Tony, 2013
 */

impl to_bytes::IterBytes for ast::RecordName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::RecordName(n, s) => (n, s).iter_bytes(lsb0, f)
        }
    }
}

impl to_bytes::IterBytes for ast::DottedName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::DottedName(s) => s.iter_bytes(lsb0, f)
        }
    }
}

pub struct Interp {
    record_types: @mut linear::LinearMap<@ast::RecordName, @ast::RecordDeclaration>,
    import_paths: @[Path],
    root: @mut env::Env<Interp>,
    argv: @[@str],
    filename: @str,
    current_frame: @mut option::Option<@mut Frame>
}

pub impl Interp {
    pub fn new(import_paths: @[Path], argv: @[@str], filename: @str) -> Interp {
        Interp {
            record_types: @mut linear::LinearMap::new(),
            import_paths: import_paths,
            root: @mut env::Env::new(),
            argv: argv,
            filename: filename,
            current_frame: @mut option::None
        }
    }
}

fn wind(interp: @mut Interp, env: @mut env::Env<Interp>, lineno: uint) -> @mut Frame {
    // allocate a new frame
    let frame = @mut Frame::new(interp, env, interp.filename, lineno);
    interp.current_frame = @mut option::Some(frame);
    frame
}

fn unwind(interp: @mut Interp) -> () {
    interp.current_frame = match *interp.current_frame {
        option::None => @mut option::None,
        option::Some(frame) => frame.parent
    };
}

pub struct Frame {
    parent: @mut option::Option<@mut Frame>,
    env: @mut env::Env<Interp>,
    file: @str,
    lineno: uint,
    exception: @mut option::Option<@mut types::Val<Interp>>
}

pub impl Frame {
    pub fn new(interp: @mut Interp, env: @mut env::Env<Interp>, file: @str, lineno: uint) -> Frame {
        Frame {
            parent: interp.current_frame,
            env: env,
            file: file,
            lineno: lineno,
            exception: @mut option::None
        }
    }
}

pub fn import_module(interp: @mut Interp, name: &ast::DottedName, qualified: bool) -> () {
    let module_parts = (**name).to_owned().map(|x| (*x).to_owned());
    let mut parts = copy module_parts;

    vec::reverse(parts);
    let module_name = copy parts[0];
    let filename = fmt!("%s.pr", module_name);
    parts = vec::tail(parts).to_owned();
    vec::reverse(parts);

    let mut found = false;
    let mut paths = interp.import_paths.to_owned();

    for paths.each_mut |import_path| {
        // make a path inside the import path and check if that exists
        let base_path = (copy *import_path).push_many(parts);
        let path = base_path.push(filename);

        if os::path_exists(&path) {
            // make a copy of the import paths then give them to a new sub-interpreter
            let mut import_paths1 = interp.import_paths.to_owned();
            import_paths1.unshift(base_path);

            let interp1 = @mut Interp::new(at_vec::from_owned(import_paths1), interp.argv, path.to_str().to_managed());

            // run the file in the sub-interpreter
            run_file(interp1, &path);

            if qualified {
                let module_name = ast::Sym(module_name.to_managed());

                // qualified imports symbols from child interpreter into a module
                env::declare(interp.root, &module_name,
                             @mut types::Module(interp1.root.vars));

                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(match *k {
                        @ast::RecordName(modu, name) => @ast::RecordName(@ast::DottedName(**modu + [module_name]), name)
                    }, *interp1.record_types.find(k).unwrap());
                }
            } else {
                // otherwise we just plop all the symbols in
                for interp1.root.vars.each_key |k| {
                    env::declare(interp.root, k, *interp1.root.vars.find(k).unwrap());
                }

                // import record types
                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(*k, *interp1.record_types.find(k).unwrap());
                }
            }

            found = true;
            break;
        }
    };

    if !found {
        fail!(fmt!("couldn't import module %s", str::connect(module_parts, ".")))
    };
}

fn unify_pattern_basic(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::Pat, val: @mut types::Val<Interp>) -> bool {
    // perform pattern matching of basic patterns -- if a match fails, we leave all the symbols in
    // scope and not care. this is pretty bad.
    match *pat {
        ast::AnyPattern => true,
        ast::ManyPattern => false,
        ast::UnitPattern => match *val {
            types::Unit => true,
            _ => false
        },
        ast::LiteralPattern(lit) => *val == types:: gen_lit(lit),
        ast::SymbolPattern(sym) => {
            env::declare(env, &sym, val);
            true
        },
        ast::BoundPattern(sym, pat) => {
            let r = unify_pattern_basic(interp, env, pat, val);
            env::declare(env, &sym, val);
            r
        },
        ast::DisjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) || unify_pattern_basic(interp, env, pat2, val)
        },
        ast::ConjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) && unify_pattern_basic(interp, env, pat2, val)
        },
        ast::RecordPattern(pat_decl, pats) => fail!(~":V"),
        ast::ListPattern(pats) => match *val {
            types::List(vals) => {
                if vals.len() < pats.len() {
                    false
                } else {
                    match pats[pats.len() - 1] {
                        ast::ManyPattern => {
                            // pattern match with a spread argument
                            let mut ok = true;
                            let mut i = 0;
                            while i < pats.len() - 1 {
                                ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                if !ok { break; };
                                i += 1;
                            }
                            ok
                        },
                        _ => {
                            if vals.len() > pats.len() {
                                // no spread argument, :(
                                false
                            } else {
                                // pattern match with a full pattern list
                                let mut ok = true;
                                let mut i = 0;
                                while i < pats.len() {
                                    ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                    if !ok { break; };
                                    i += 1;
                                }
                                ok
                            }
                        }
                    }
                }
            },
            _ => false
        }
    }
}

fn unify_pattern_let(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::LetPat, val: @mut types::Val<Interp>) -> bool {
    match *pat {
        ast::BasicPattern(pat) => unify_pattern_basic(interp, env, &pat, val),
        _ => fail!(~":V")
    }
}

fn eval_exp(interp: @mut Interp, env: @mut env::Env<Interp>, exp: &ast::Exp) -> types::Val<Interp> {
    let frame = interp.current_frame.unwrap();

    let r = match exp.exp {
        ast::UnitExpression => types::Unit,
        ast::LiteralExpression(l) => types::gen_lit(l),
        ast::LambdaExpression(pat, exp) => types::Function(@[types::Fun {
            pattern: pat,
            body: exp,
            env: env
        }]),
        ast::ListExpression(exps) => {
            let mut vals = @[];

            for exps.each |exp| {
                vals += [@mut eval_exp(interp, env, exp)];
                if !frame.exception.is_none() {
                    return types::Unit;
                }
            }

            types::List(vals)
        },
        ast::SymbolExpression(sym) => {
            match env::find(env, &sym) {
                option::Some(x) => types::Unit,
                option::None => {
                    frame.exception = @mut option::Some(@mut types::String(fmt!("symbol `%s` not found in scope", *sym).to_managed()));
                    types::Unit
                }
            }
        },
        _ => fail!(~":V")
    };

    r
}

fn exec_stmt(interp: @mut Interp, env: @mut env::Env<Interp>, stmt: &ast::Stmt) -> () {
    let frame = interp.current_frame.unwrap();

    match stmt.stmt {
        ast::LetBindingStatement(pat, exp) => {
            if !unify_pattern_let(interp, env, &pat, @mut eval_exp(interp, env, &exp)) {
                // uh oh, we need to throw an exception and unwind
                frame.exception = @mut option::Some(@mut types::String(@"pattern match refuted"));
            }
        },
        ast::ExpressionStatement(exp) => { eval_exp(interp, env, &exp); }
    };
}

pub fn run_file(interp: @mut Interp, path: &Path) -> () {
    match io::file_reader(path) {
        result::Ok(r) => {
            let tokens = lexer::lex(r);
            let program = parser::parse(tokens);
            run(interp, program);
        },
        result::Err(f) => fail!(f)
    }
}

pub fn run(interp: @mut Interp, prog: ast::Program) -> () {
    for prog.imports.each |imp| {
        import_module(interp, &imp.module, imp.qualified);
    }

    for prog.records.each |rec| {
        interp.record_types.insert(@rec.name, @*rec);
    }

    for prog.body.each |stmt| {
        let mut frame = wind(interp, interp.root, stmt.lineno);

        exec_stmt(interp, interp.root, stmt);

        match *frame.exception {
            option::None => unwind(interp),
            option::Some(f) => {
                let mut current_frame = frame;
                let mut buf = ~[fmt!("%?", f)];
                loop {
                    buf += [fmt!("        from %s:%u", frame.file, frame.lineno)];
                    if current_frame.parent.is_none() { break; }
                    current_frame = current_frame.parent.unwrap();
                }
                io::println(str::connect(buf, "\n"));
                fail!(~"uncaught aster exception");
            }
        }
    }
}
<commit_msg>add TODO note<commit_after>use ast;
use lexer;
use parser;

use interp::env;
use interp::types;

use core::hashmap::linear;
use core::to_bytes;

/*
 * aster - AST EvaulatoR
 *
 * aster evaluates a Prismo program via reduction of the AST.
 *
 * "It's pretty terrible."
 * -- Tony, 2013
 */

impl to_bytes::IterBytes for ast::RecordName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::RecordName(n, s) => (n, s).iter_bytes(lsb0, f)
        }
    }
}

impl to_bytes::IterBytes for ast::DottedName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::DottedName(s) => s.iter_bytes(lsb0, f)
        }
    }
}

pub struct Interp {
    record_types: @mut linear::LinearMap<@ast::RecordName, @ast::RecordDeclaration>,
    import_paths: @[Path],
    root: @mut env::Env<Interp>,
    argv: @[@str],
    filename: @str,
    current_frame: @mut option::Option<@mut Frame>
}

pub impl Interp {
    pub fn new(import_paths: @[Path], argv: @[@str], filename: @str) -> Interp {
        Interp {
            record_types: @mut linear::LinearMap::new(),
            import_paths: import_paths,
            root: @mut env::Env::new(),
            argv: argv,
            filename: filename,
            current_frame: @mut option::None
        }
    }
}

fn wind(interp: @mut Interp, env: @mut env::Env<Interp>, lineno: uint) -> @mut Frame {
    // allocate a new frame
    let frame = @mut Frame::new(interp, env, interp.filename, lineno);
    interp.current_frame = @mut option::Some(frame);
    frame
}

fn unwind(interp: @mut Interp) -> () {
    interp.current_frame = match *interp.current_frame {
        option::None => @mut option::None,
        option::Some(frame) => frame.parent
    };
}

pub struct Frame {
    parent: @mut option::Option<@mut Frame>,
    env: @mut env::Env<Interp>,
    file: @str,
    lineno: uint,
    exception: @mut option::Option<@mut types::Val<Interp>>
}

pub impl Frame {
    pub fn new(interp: @mut Interp, env: @mut env::Env<Interp>, file: @str, lineno: uint) -> Frame {
        Frame {
            parent: interp.current_frame,
            env: env,
            file: file,
            lineno: lineno,
            exception: @mut option::None
        }
    }
}

pub fn import_module(interp: @mut Interp, name: &ast::DottedName, qualified: bool) -> () {
    let module_parts = (**name).to_owned().map(|x| (*x).to_owned());
    let mut parts = copy module_parts;

    vec::reverse(parts);
    let module_name = copy parts[0];
    let filename = fmt!("%s.pr", module_name);
    parts = vec::tail(parts).to_owned();
    vec::reverse(parts);

    let mut found = false;
    let mut paths = interp.import_paths.to_owned();

    for paths.each_mut |import_path| {
        // make a path inside the import path and check if that exists
        let base_path = (copy *import_path).push_many(parts);
        let path = base_path.push(filename);

        if os::path_exists(&path) {
            // make a copy of the import paths then give them to a new sub-interpreter
            let mut import_paths1 = interp.import_paths.to_owned();
            import_paths1.unshift(base_path);

            let interp1 = @mut Interp::new(at_vec::from_owned(import_paths1), interp.argv, path.to_str().to_managed());

            // run the file in the sub-interpreter
            run_file(interp1, &path);

            if qualified {
                let module_name = ast::Sym(module_name.to_managed());

                // qualified imports symbols from child interpreter into a module
                env::declare(interp.root, &module_name,
                             @mut types::Module(interp1.root.vars));

                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(match *k {
                        @ast::RecordName(modu, name) => @ast::RecordName(@ast::DottedName(**modu + [module_name]), name)
                    }, *interp1.record_types.find(k).unwrap());
                }
            } else {
                // otherwise we just plop all the symbols in
                for interp1.root.vars.each_key |k| {
                    env::declare(interp.root, k, *interp1.root.vars.find(k).unwrap());
                }

                // import record types
                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(*k, *interp1.record_types.find(k).unwrap());
                }
            }

            found = true;
            break;
        }
    };

    if !found {
        fail!(fmt!("couldn't import module %s", str::connect(module_parts, ".")))
    };
}

fn unify_pattern_basic(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::Pat, val: @mut types::Val<Interp>) -> bool {
    // perform pattern matching of basic patterns -- if a match fails, we leave all the symbols in
    // scope and not care. this is pretty bad.
    match *pat {
        ast::AnyPattern => true,
        ast::ManyPattern => false,
        ast::UnitPattern => match *val {
            types::Unit => true,
            _ => false
        },
        ast::LiteralPattern(lit) => *val == types:: gen_lit(lit),
        ast::SymbolPattern(sym) => {
            env::declare(env, &sym, val);
            true
        },
        ast::BoundPattern(sym, pat) => {
            let r = unify_pattern_basic(interp, env, pat, val);
            env::declare(env, &sym, val);
            r
        },
        ast::DisjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) || unify_pattern_basic(interp, env, pat2, val)
        },
        ast::ConjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) && unify_pattern_basic(interp, env, pat2, val)
        },
        ast::RecordPattern(pat_decl, pats) => fail!(~":V"),
        ast::ListPattern(pats) => match *val {
            types::List(vals) => {
                if vals.len() < pats.len() {
                    false
                } else {
                    match pats[pats.len() - 1] {
                        ast::ManyPattern => {
                            // pattern match with a spread argument
                            let mut ok = true;
                            let mut i = 0;
                            while i < pats.len() - 1 {
                                ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                if !ok { break; };
                                i += 1;
                            }
                            ok
                        },
                        _ => {
                            if vals.len() > pats.len() {
                                // no spread argument, :(
                                false
                            } else {
                                // pattern match with a full pattern list
                                let mut ok = true;
                                let mut i = 0;
                                while i < pats.len() {
                                    ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                    if !ok { break; };
                                    i += 1;
                                }
                                ok
                            }
                        }
                    }
                }
            },
            _ => false
        }
    }
}

fn unify_pattern_let(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::LetPat, val: @mut types::Val<Interp>) -> bool {
    match *pat {
        ast::BasicPattern(pat) => unify_pattern_basic(interp, env, &pat, val),
        _ => fail!(~":V")
    }
}

fn eval_exp(interp: @mut Interp, env: @mut env::Env<Interp>, exp: &ast::Exp) -> types::Val<Interp> {
    let frame = interp.current_frame.unwrap();

    let r = match exp.exp {
        ast::UnitExpression => types::Unit,
        ast::LiteralExpression(l) => types::gen_lit(l),
        ast::LambdaExpression(pat, exp) => types::Function(@[types::Fun {
            pattern: pat,
            body: exp,
            env: env
        }]),
        ast::ListExpression(exps) => {
            let mut vals = @[];

            for exps.each |exp| {
                vals += [@mut eval_exp(interp, env, exp)];
                if !frame.exception.is_none() {
                    return types::Unit;
                }
            }

            types::List(vals)
        },
        ast::SymbolExpression(sym) => {
            match env::find(env, &sym) {
                option::Some(x) => types::Unit,
                option::None => {
                    frame.exception = @mut option::Some(@mut types::String(fmt!("symbol `%s` not found in scope", *sym).to_managed()));
                    types::Unit
                }
            }
        },
        _ => fail!(~":V")
    };

    r
}

fn exec_stmt(interp: @mut Interp, env: @mut env::Env<Interp>, stmt: &ast::Stmt) -> () {
    let frame = interp.current_frame.unwrap();

    match stmt.stmt {
        ast::LetBindingStatement(pat, exp) => {
            if !unify_pattern_let(interp, env, &pat, @mut eval_exp(interp, env, &exp)) {
                // uh oh, we need to throw an exception and unwind
                frame.exception = @mut option::Some(@mut types::String(@"pattern match refuted"));
            }
        },
        ast::ExpressionStatement(exp) => { eval_exp(interp, env, &exp); }
    };
}

pub fn run_file(interp: @mut Interp, path: &Path) -> () {
    match io::file_reader(path) {
        result::Ok(r) => {
            let tokens = lexer::lex(r);
            let program = parser::parse(tokens);
            run(interp, program);
        },
        result::Err(f) => fail!(f)
    }
}

pub fn run(interp: @mut Interp, prog: ast::Program) -> () {
    for prog.imports.each |imp| {
        import_module(interp, &imp.module, imp.qualified);
    }

    for prog.records.each |rec| {
        interp.record_types.insert(@rec.name, @*rec);
        // TODO: generate record constructors
    }

    for prog.body.each |stmt| {
        let mut frame = wind(interp, interp.root, stmt.lineno);

        exec_stmt(interp, interp.root, stmt);

        match *frame.exception {
            option::None => unwind(interp),
            option::Some(f) => {
                let mut current_frame = frame;
                let mut buf = ~[fmt!("%?", f)];
                loop {
                    buf += [fmt!("        from %s:%u", frame.file, frame.lineno)];
                    if current_frame.parent.is_none() { break; }
                    current_frame = current_frame.parent.unwrap();
                }
                io::println(str::connect(buf, "\n"));
                fail!(~"uncaught aster exception");
            }
        }
    }
}
<|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 rustc_serialize::json;
use std::mem;
use std::net::TcpStream;
use time::precise_time_ns;

use actor::{Actor, ActorRegistry};

pub struct FramerateActor {
    name: String,
    start_time: Option<u64>,
    is_recording: bool,
    ticks: Vec<u64>,
}

impl Actor for FramerateActor {
    fn name(&self) -> String {
        self.name.clone()
    }

    fn handle_message(&self,
                      _registry: &ActorRegistry,
                      _msg_type: &str,
                      _msg: &json::Object,
                      _stream: &mut TcpStream) -> Result<bool, ()> {
        Ok(false)
    }
}

impl FramerateActor {
    /// return name of actor
    pub fn create(registry: &ActorRegistry) -> String {
        let actor_name = registry.new_name("framerate");
        let mut actor = FramerateActor {
            name: actor_name.clone(),
            start_time: None,
            is_recording: false,
            ticks: Vec::new(),
        };

        actor.start_recording();
        registry.register_later(box actor);
        actor_name
    }

    // callback on request animation frame
    pub fn on_refresh_driver_tick(&mut self) {
        if !self.is_recording {
            return;
        }
        // TODO: Need implement requesting animation frame
        // http://hg.mozilla.org/mozilla-central/file/0a46652bd992/dom/base/nsGlobalWindow.cpp#l5314

        let start_time = self.start_time.as_ref().unwrap();
        self.ticks.push(*start_time - precise_time_ns());
    }

    pub fn take_pending_ticks(&mut self) -> Vec<u64> {
        mem::replace(&mut self.ticks, Vec::new())
    }

    fn start_recording(&mut self) {
        self.is_recording = true;
        self.start_time = Some(precise_time_ns());

        // TODO: Need implement requesting animation frame
        // http://hg.mozilla.org/mozilla-central/file/0a46652bd992/dom/base/nsGlobalWindow.cpp#l5314
    }

    fn stop_recording(&mut self) {
        if !self.is_recording {
            return;
        }
        self.is_recording = false;
        self.start_time = None;
    }

}

impl Drop for FramerateActor {
    fn drop(&mut self) {
        self.stop_recording();
    }
}
<commit_msg>Auto merge of #5682 - Ms2ger:mention-5681, r=Manishearth<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 rustc_serialize::json;
use std::mem;
use std::net::TcpStream;
use time::precise_time_ns;

use actor::{Actor, ActorRegistry};

pub struct FramerateActor {
    name: String,
    start_time: Option<u64>,
    is_recording: bool,
    ticks: Vec<u64>,
}

impl Actor for FramerateActor {
    fn name(&self) -> String {
        self.name.clone()
    }

    fn handle_message(&self,
                      _registry: &ActorRegistry,
                      _msg_type: &str,
                      _msg: &json::Object,
                      _stream: &mut TcpStream) -> Result<bool, ()> {
        Ok(false)
    }
}

impl FramerateActor {
    /// return name of actor
    pub fn create(registry: &ActorRegistry) -> String {
        let actor_name = registry.new_name("framerate");
        let mut actor = FramerateActor {
            name: actor_name.clone(),
            start_time: None,
            is_recording: false,
            ticks: Vec::new(),
        };

        actor.start_recording();
        registry.register_later(box actor);
        actor_name
    }

    // callback on request animation frame
    #[allow(dead_code)]
    pub fn on_refresh_driver_tick(&mut self) {
        if !self.is_recording {
            return;
        }
        // TODO: Need implement requesting animation frame
        // http://hg.mozilla.org/mozilla-central/file/0a46652bd992/dom/base/nsGlobalWindow.cpp#l5314

        let start_time = self.start_time.as_ref().unwrap();
        self.ticks.push(*start_time - precise_time_ns());
    }

    pub fn take_pending_ticks(&mut self) -> Vec<u64> {
        mem::replace(&mut self.ticks, Vec::new())
    }

    fn start_recording(&mut self) {
        self.is_recording = true;
        self.start_time = Some(precise_time_ns());

        // TODO(#5681): Need implement requesting animation frame
        // http://hg.mozilla.org/mozilla-central/file/0a46652bd992/dom/base/nsGlobalWindow.cpp#l5314
    }

    fn stop_recording(&mut self) {
        if !self.is_recording {
            return;
        }
        self.is_recording = false;
        self.start_time = None;
    }

}

impl Drop for FramerateActor {
    fn drop(&mut self) {
        self.stop_recording();
    }
}
<|endoftext|>