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

//! The [`@counter-style`][counter-style] at-rule.
//!
//! [counter-style]: https://drafts.csswg.org/css-counter-styles/

use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser, Token};
use cssparser::{serialize_string, serialize_identifier};
#[cfg(feature = "gecko")] use gecko::rules::CounterStyleDescriptors;
#[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSCounterDesc;
use parser::{ParserContext, log_css_error, Parse};
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use std::fmt;
use style_traits::ToCss;
use values::CustomIdent;

/// Parse the prelude of an @counter-style rule
pub fn parse_counter_style_name(input: &mut Parser) -> Result<CustomIdent, ()> {
    CustomIdent::from_ident(input.expect_ident()?, &["decimal", "none"])
}

/// Parse the body (inside `{}`) of an @counter-style rule
pub fn parse_counter_style_body(name: CustomIdent, context: &ParserContext, input: &mut Parser)
                            -> Result<CounterStyleRule, ()> {
    let mut rule = CounterStyleRule::initial(name);
    {
        let parser = CounterStyleRuleParser {
            context: context,
            rule: &mut rule,
        };
        let mut iter = DeclarationListParser::new(input, parser);
        while let Some(declaration) = iter.next() {
            if let Err(range) = declaration {
                let pos = range.start;
                let message = format!("Unsupported @counter-style descriptor declaration: '{}'",
                                      iter.input.slice(range));
                log_css_error(iter.input, pos, &*message, context);
            }
        }
    }
    Ok(rule)
}

struct CounterStyleRuleParser<'a, 'b: 'a> {
    context: &'a ParserContext<'b>,
    rule: &'a mut CounterStyleRule,
}

/// Default methods reject all at rules.
impl<'a, 'b> AtRuleParser for CounterStyleRuleParser<'a, 'b> {
    type Prelude = ();
    type AtRule = ();
}

macro_rules! counter_style_descriptors {
    (
        $( #[$doc: meta] $name: tt $ident: ident / $gecko_ident: ident: $ty: ty = $initial: expr; )+
    ) => {
        /// An @counter-style rule
        #[derive(Debug)]
        pub struct CounterStyleRule {
            name: CustomIdent,
            $(
                #[$doc]
                $ident: $ty,
            )+
        }

        impl CounterStyleRule {
            fn initial(name: CustomIdent) -> Self {
                CounterStyleRule {
                    name: name,
                    $(
                        $ident: $initial,
                    )+
                }
            }

            /// Convert to Gecko types
            #[cfg(feature = "gecko")]
            pub fn set_descriptors(&self, descriptors: &mut CounterStyleDescriptors) {
                $(
                    descriptors[nsCSSCounterDesc::$gecko_ident as usize].set_from(&self.$ident);
                )*
            }
        }

       impl<'a, 'b> DeclarationParser for CounterStyleRuleParser<'a, 'b> {
            type Declaration = ();

            fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> {
                match_ignore_ascii_case! { name,
                    $(
                        $name => {
                            // DeclarationParser also calls parse_entirely
                            // so we’d normally not need to,
                            // but in this case we do because we set the value as a side effect
                            // rather than returning it.
                            let value = input.parse_entirely(|i| Parse::parse(self.context, i))?;
                            self.rule.$ident = value
                        }
                    )*
                    _ => return Err(())
                }
                Ok(())
            }
        }

        impl ToCssWithGuard for CounterStyleRule {
            fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
            where W: fmt::Write {
                dest.write_str("@counter-style ")?;
                self.name.to_css(dest)?;
                dest.write_str(" {\n")?;
                $(
                    dest.write_str(concat!("  ", $name, ": "))?;
                    ToCss::to_css(&self.$ident, dest)?;
                    dest.write_str(";\n")?;
                )+
                dest.write_str("}")
            }
        }
    }
}

counter_style_descriptors! {
    /// https://drafts.csswg.org/css-counter-styles/#counter-style-system
    "system" system / eCSSCounterDesc_System: System = System::Symbolic;

    /// https://drafts.csswg.org/css-counter-styles/#counter-style-negative
    "negative" negative / eCSSCounterDesc_Negative: Negative =
        Negative(Symbol::String("-".to_owned()), None);
}

/// https://drafts.csswg.org/css-counter-styles/#counter-style-system
#[derive(Debug)]
pub enum System {
    /// 'cyclic'
    Cyclic,
    /// 'numeric'
    Numeric,
    /// 'alphabetic'
    Alphabetic,
    /// 'symbolic'
    Symbolic,
    /// 'additive'
    Additive,
    /// 'fixed <integer>?'
    Fixed {
        /// '<integer>?'
        first_symbol_value: Option<i32>
    },
    /// 'extends <counter-style-name>'
    Extends(CustomIdent),
}

impl Parse for System {
    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        match_ignore_ascii_case! { &input.expect_ident()?,
            "cyclic" => Ok(System::Cyclic),
            "numeric" => Ok(System::Numeric),
            "alphabetic" => Ok(System::Alphabetic),
            "symbolic" => Ok(System::Symbolic),
            "additive" => Ok(System::Additive),
            "fixed" => {
                let first_symbol_value = input.try(|i| i.expect_integer()).ok();
                Ok(System::Fixed { first_symbol_value: first_symbol_value })
            }
            "extends" => {
                let other = parse_counter_style_name(input)?;
                Ok(System::Extends(other))
            }
            _ => Err(())
        }
    }
}

impl ToCss for System {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            System::Cyclic => dest.write_str("cyclic"),
            System::Numeric => dest.write_str("numeric"),
            System::Alphabetic => dest.write_str("alphabetic"),
            System::Symbolic => dest.write_str("symbolic"),
            System::Additive => dest.write_str("additive"),
            System::Fixed { first_symbol_value } => {
                if let Some(value) = first_symbol_value {
                    write!(dest, "fixed {}", value)
                } else {
                    dest.write_str("fixed")
                }
            }
            System::Extends(ref other) => {
                dest.write_str("extends ")?;
                other.to_css(dest)
            }
        }
    }
}

/// https://drafts.csswg.org/css-counter-styles/#typedef-symbol
#[derive(Debug)]
pub enum Symbol {
    /// <string>
    String(String),
    /// <ident>
    Ident(String),
    // Not implemented:
    // /// <image>
    // Image(Image),
}

impl Parse for Symbol {
    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        match input.next() {
            Ok(Token::QuotedString(s)) => Ok(Symbol::String(s.into_owned())),
            Ok(Token::Ident(s)) => Ok(Symbol::Ident(s.into_owned())),
            _ => Err(())
        }
    }
}

impl ToCss for Symbol {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            Symbol::String(ref s) => serialize_string(s, dest),
            Symbol::Ident(ref s) => serialize_identifier(s, dest),
        }
    }
}

/// https://drafts.csswg.org/css-counter-styles/#counter-style-negative
#[derive(Debug)]
pub struct Negative(pub Symbol, pub Option<Symbol>);

impl Parse for Negative {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        Ok(Negative(
            Symbol::parse(context, input)?,
            input.try(|input| Symbol::parse(context, input)).ok(),
        ))
    }
}

impl ToCss for Negative {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        self.0.to_css(dest)?;
        if let Some(ref symbol) = self.1 {
            dest.write_char(' ')?;
            symbol.to_css(dest)?
        }
        Ok(())
    }
}
<commit_msg>Add 'prefix' and 'suffix' descriptors for @counter-style<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/. */

//! The [`@counter-style`][counter-style] at-rule.
//!
//! [counter-style]: https://drafts.csswg.org/css-counter-styles/

use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser, Token};
use cssparser::{serialize_string, serialize_identifier};
#[cfg(feature = "gecko")] use gecko::rules::CounterStyleDescriptors;
#[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSCounterDesc;
use parser::{ParserContext, log_css_error, Parse};
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use std::fmt;
use style_traits::ToCss;
use values::CustomIdent;

/// Parse the prelude of an @counter-style rule
pub fn parse_counter_style_name(input: &mut Parser) -> Result<CustomIdent, ()> {
    CustomIdent::from_ident(input.expect_ident()?, &["decimal", "none"])
}

/// Parse the body (inside `{}`) of an @counter-style rule
pub fn parse_counter_style_body(name: CustomIdent, context: &ParserContext, input: &mut Parser)
                            -> Result<CounterStyleRule, ()> {
    let mut rule = CounterStyleRule::initial(name);
    {
        let parser = CounterStyleRuleParser {
            context: context,
            rule: &mut rule,
        };
        let mut iter = DeclarationListParser::new(input, parser);
        while let Some(declaration) = iter.next() {
            if let Err(range) = declaration {
                let pos = range.start;
                let message = format!("Unsupported @counter-style descriptor declaration: '{}'",
                                      iter.input.slice(range));
                log_css_error(iter.input, pos, &*message, context);
            }
        }
    }
    Ok(rule)
}

struct CounterStyleRuleParser<'a, 'b: 'a> {
    context: &'a ParserContext<'b>,
    rule: &'a mut CounterStyleRule,
}

/// Default methods reject all at rules.
impl<'a, 'b> AtRuleParser for CounterStyleRuleParser<'a, 'b> {
    type Prelude = ();
    type AtRule = ();
}

macro_rules! counter_style_descriptors {
    (
        $( #[$doc: meta] $name: tt $ident: ident / $gecko_ident: ident: $ty: ty = $initial: expr; )+
    ) => {
        /// An @counter-style rule
        #[derive(Debug)]
        pub struct CounterStyleRule {
            name: CustomIdent,
            $(
                #[$doc]
                $ident: $ty,
            )+
        }

        impl CounterStyleRule {
            fn initial(name: CustomIdent) -> Self {
                CounterStyleRule {
                    name: name,
                    $(
                        $ident: $initial,
                    )+
                }
            }

            /// Convert to Gecko types
            #[cfg(feature = "gecko")]
            pub fn set_descriptors(&self, descriptors: &mut CounterStyleDescriptors) {
                $(
                    descriptors[nsCSSCounterDesc::$gecko_ident as usize].set_from(&self.$ident);
                )*
            }
        }

       impl<'a, 'b> DeclarationParser for CounterStyleRuleParser<'a, 'b> {
            type Declaration = ();

            fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> {
                match_ignore_ascii_case! { name,
                    $(
                        $name => {
                            // DeclarationParser also calls parse_entirely
                            // so we’d normally not need to,
                            // but in this case we do because we set the value as a side effect
                            // rather than returning it.
                            let value = input.parse_entirely(|i| Parse::parse(self.context, i))?;
                            self.rule.$ident = value
                        }
                    )*
                    _ => return Err(())
                }
                Ok(())
            }
        }

        impl ToCssWithGuard for CounterStyleRule {
            fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
            where W: fmt::Write {
                dest.write_str("@counter-style ")?;
                self.name.to_css(dest)?;
                dest.write_str(" {\n")?;
                $(
                    dest.write_str(concat!("  ", $name, ": "))?;
                    ToCss::to_css(&self.$ident, dest)?;
                    dest.write_str(";\n")?;
                )+
                dest.write_str("}")
            }
        }
    }
}

counter_style_descriptors! {
    /// https://drafts.csswg.org/css-counter-styles/#counter-style-system
    "system" system / eCSSCounterDesc_System: System = System::Symbolic;

    /// https://drafts.csswg.org/css-counter-styles/#counter-style-negative
    "negative" negative / eCSSCounterDesc_Negative: Negative =
        Negative(Symbol::String("-".to_owned()), None);

    /// https://drafts.csswg.org/css-counter-styles/#counter-style-prefix
    "prefix" prefix / eCSSCounterDesc_Prefix: Symbol = Symbol::String("".to_owned());

    /// https://drafts.csswg.org/css-counter-styles/#counter-style-suffix
    "suffix" suffix / eCSSCounterDesc_Suffix: Symbol = Symbol::String(". ".to_owned());
}

/// https://drafts.csswg.org/css-counter-styles/#counter-style-system
#[derive(Debug)]
pub enum System {
    /// 'cyclic'
    Cyclic,
    /// 'numeric'
    Numeric,
    /// 'alphabetic'
    Alphabetic,
    /// 'symbolic'
    Symbolic,
    /// 'additive'
    Additive,
    /// 'fixed <integer>?'
    Fixed {
        /// '<integer>?'
        first_symbol_value: Option<i32>
    },
    /// 'extends <counter-style-name>'
    Extends(CustomIdent),
}

impl Parse for System {
    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        match_ignore_ascii_case! { &input.expect_ident()?,
            "cyclic" => Ok(System::Cyclic),
            "numeric" => Ok(System::Numeric),
            "alphabetic" => Ok(System::Alphabetic),
            "symbolic" => Ok(System::Symbolic),
            "additive" => Ok(System::Additive),
            "fixed" => {
                let first_symbol_value = input.try(|i| i.expect_integer()).ok();
                Ok(System::Fixed { first_symbol_value: first_symbol_value })
            }
            "extends" => {
                let other = parse_counter_style_name(input)?;
                Ok(System::Extends(other))
            }
            _ => Err(())
        }
    }
}

impl ToCss for System {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            System::Cyclic => dest.write_str("cyclic"),
            System::Numeric => dest.write_str("numeric"),
            System::Alphabetic => dest.write_str("alphabetic"),
            System::Symbolic => dest.write_str("symbolic"),
            System::Additive => dest.write_str("additive"),
            System::Fixed { first_symbol_value } => {
                if let Some(value) = first_symbol_value {
                    write!(dest, "fixed {}", value)
                } else {
                    dest.write_str("fixed")
                }
            }
            System::Extends(ref other) => {
                dest.write_str("extends ")?;
                other.to_css(dest)
            }
        }
    }
}

/// https://drafts.csswg.org/css-counter-styles/#typedef-symbol
#[derive(Debug)]
pub enum Symbol {
    /// <string>
    String(String),
    /// <ident>
    Ident(String),
    // Not implemented:
    // /// <image>
    // Image(Image),
}

impl Parse for Symbol {
    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        match input.next() {
            Ok(Token::QuotedString(s)) => Ok(Symbol::String(s.into_owned())),
            Ok(Token::Ident(s)) => Ok(Symbol::Ident(s.into_owned())),
            _ => Err(())
        }
    }
}

impl ToCss for Symbol {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            Symbol::String(ref s) => serialize_string(s, dest),
            Symbol::Ident(ref s) => serialize_identifier(s, dest),
        }
    }
}

/// https://drafts.csswg.org/css-counter-styles/#counter-style-negative
#[derive(Debug)]
pub struct Negative(pub Symbol, pub Option<Symbol>);

impl Parse for Negative {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        Ok(Negative(
            Symbol::parse(context, input)?,
            input.try(|input| Symbol::parse(context, input)).ok(),
        ))
    }
}

impl ToCss for Negative {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        self.0.to_css(dest)?;
        if let Some(ref symbol) = self.1 {
            dest.write_char(' ')?;
            symbol.to_css(dest)?
        }
        Ok(())
    }
}
<|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 element_state::ElementState;
use properties::{self, ServoComputedValues};
use selector_matching::{USER_OR_USER_AGENT_STYLESHEETS, QUIRKS_MODE_STYLESHEET};
use selectors::Element;
use selectors::parser::{ParserContext, SelectorImpl};
use stylesheets::Stylesheet;

pub trait ElementExt: Element {
    fn is_link(&self) -> bool;
}

pub trait SelectorImplExt : SelectorImpl + Sized {
    type ComputedValues: properties::ComputedValues;

    fn each_pseudo_element<F>(mut fun: F)
        where F: FnMut(<Self as SelectorImpl>::PseudoElement);

    fn is_eagerly_cascaded_pseudo_element(pseudo: &<Self as SelectorImpl>::PseudoElement) -> bool;

    #[inline]
    fn each_eagerly_cascaded_pseudo_element<F>(mut fun: F)
        where F: FnMut(<Self as SelectorImpl>::PseudoElement) {
        Self::each_pseudo_element(|pseudo| {
            if Self::is_eagerly_cascaded_pseudo_element(&pseudo) {
                fun(pseudo)
            }
        })
    }

    #[inline]
    fn each_non_eagerly_cascaded_pseudo_element<F>(mut fun: F)
        where F: FnMut(<Self as SelectorImpl>::PseudoElement) {
        Self::each_pseudo_element(|pseudo| {
            if !Self::is_eagerly_cascaded_pseudo_element(&pseudo) {
                fun(pseudo)
            }
        })
    }

    fn pseudo_class_state_flag(pc: &Self::NonTSPseudoClass) -> ElementState;

    fn get_user_or_user_agent_stylesheets() -> &'static [Stylesheet<Self>];

    fn get_quirks_mode_stylesheet() -> Option<&'static Stylesheet<Self>>;
}

#[derive(Clone, Debug, PartialEq, Eq, HeapSizeOf, Hash)]
pub enum PseudoElement {
    Before,
    After,
    Selection,
    DetailsSummary,
    DetailsContent,
}

impl PseudoElement {
    #[inline]
    pub fn is_eagerly_cascaded(&self) -> bool {
        match *self {
            PseudoElement::Before |
            PseudoElement::After |
            PseudoElement::Selection |
            PseudoElement::DetailsSummary => true,
            PseudoElement::DetailsContent => false,
        }
    }
}

#[derive(Clone, Debug, PartialEq, Eq, HeapSizeOf, Hash)]
pub enum NonTSPseudoClass {
    AnyLink,
    Link,
    Visited,
    Active,
    Focus,
    Hover,
    Enabled,
    Disabled,
    Checked,
    Indeterminate,
    ServoNonZeroBorder,
    ReadWrite,
    ReadOnly
}

impl NonTSPseudoClass {
    pub fn state_flag(&self) -> ElementState {
        use element_state::*;
        use self::NonTSPseudoClass::*;
        match *self {
            Active => IN_ACTIVE_STATE,
            Focus => IN_FOCUS_STATE,
            Hover => IN_HOVER_STATE,
            Enabled => IN_ENABLED_STATE,
            Disabled => IN_DISABLED_STATE,
            Checked => IN_CHECKED_STATE,
            Indeterminate => IN_INDETERMINATE_STATE,
            ReadOnly | ReadWrite => IN_READ_WRITE_STATE,

            AnyLink |
            Link |
            Visited |
            ServoNonZeroBorder => ElementState::empty(),
        }
    }
}

#[derive(Clone, Debug, PartialEq, HeapSizeOf)]
pub struct ServoSelectorImpl;

impl SelectorImpl for ServoSelectorImpl {
    type PseudoElement = PseudoElement;
    type NonTSPseudoClass = NonTSPseudoClass;

    fn parse_non_ts_pseudo_class(context: &ParserContext,
                                 name: &str) -> Result<NonTSPseudoClass, ()> {
        use self::NonTSPseudoClass::*;
        let pseudo_class = match_ignore_ascii_case! { name,
            "any-link" => AnyLink,
            "link" => Link,
            "visited" => Visited,
            "active" => Active,
            "focus" => Focus,
            "hover" => Hover,
            "enabled" => Enabled,
            "disabled" => Disabled,
            "checked" => Checked,
            "indeterminate" => Indeterminate,
            "read-write" => ReadWrite,
            "read-only" => ReadOnly,
            "-servo-nonzero-border" => {
                if !context.in_user_agent_stylesheet {
                    return Err(());
                }
                ServoNonZeroBorder
            },
            _ => return Err(())
        };

        Ok(pseudo_class)
    }

    fn parse_pseudo_element(context: &ParserContext,
                            name: &str) -> Result<PseudoElement, ()> {
        use self::PseudoElement::*;
        let pseudo_element = match_ignore_ascii_case! { name,
            "before" => Before,
            "after" => After,
            "selection" => Selection,
            "-servo-details-summary" => {
                if !context.in_user_agent_stylesheet {
                    return Err(())
                }
                DetailsSummary
            },
            "-servo-details-content" => {
                if !context.in_user_agent_stylesheet {
                    return Err(())
                }
                DetailsContent
            },
            _ => return Err(())
        };

        Ok(pseudo_element)
    }
}

impl SelectorImplExt for ServoSelectorImpl {
    type ComputedValues = ServoComputedValues;

    #[inline]
    fn is_eagerly_cascaded_pseudo_element(pseudo: &PseudoElement) -> bool {
        pseudo.is_eagerly_cascaded()
    }

    #[inline]
    fn each_pseudo_element<F>(mut fun: F)
        where F: FnMut(PseudoElement) {
        fun(PseudoElement::Before);
        fun(PseudoElement::After);
        fun(PseudoElement::DetailsContent);
        fun(PseudoElement::DetailsSummary);
        fun(PseudoElement::Selection);
    }

    #[inline]
    fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState {
        pc.state_flag()
    }

    #[inline]
    fn get_user_or_user_agent_stylesheets() -> &'static [Stylesheet<Self>] {
        &*USER_OR_USER_AGENT_STYLESHEETS
    }

    #[inline]
    fn get_quirks_mode_stylesheet() -> Option<&'static Stylesheet<Self>> {
        Some(&*QUIRKS_MODE_STYLESHEET)
    }
}

impl<E: Element<Impl=ServoSelectorImpl>> ElementExt for E {
    fn is_link(&self) -> bool {
        self.match_non_ts_pseudo_class(NonTSPseudoClass::AnyLink)
    }
}
<commit_msg>style: Add doc-comment about is_eagerly_cascaded_pseudo_element<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 element_state::ElementState;
use properties::{self, ServoComputedValues};
use selector_matching::{USER_OR_USER_AGENT_STYLESHEETS, QUIRKS_MODE_STYLESHEET};
use selectors::Element;
use selectors::parser::{ParserContext, SelectorImpl};
use stylesheets::Stylesheet;

pub trait ElementExt: Element {
    fn is_link(&self) -> bool;
}

pub trait SelectorImplExt : SelectorImpl + Sized {
    type ComputedValues: properties::ComputedValues;

    fn each_pseudo_element<F>(mut fun: F)
        where F: FnMut(<Self as SelectorImpl>::PseudoElement);

    /// This function determines if a pseudo-element is eagerly cascaded or not.
    ///
    /// Eagerly cascaded pseudo-elements are "normal" pseudo-elements (i.e.
    /// `::before` and `::after`). They inherit styles normally as another
    /// selector would do.
    ///
    /// Non-eagerly cascaded ones skip the cascade process entirely, mostly as
    /// an optimisation since they are private pseudo-elements (like
    /// `::-servo-details-content`). This pseudo-elements are resolved on the
    /// fly using global rules (rules of the form `*|*`), and applying them to
    /// the parent style.
    ///
    /// If you're implementing a public selector that the end-user might
    /// customize, then you probably need doing the whole cascading process and
    /// return true in this function for that pseudo.
    ///
    /// But if you are implementing a private pseudo-element, please consider if
    /// it might be possible to skip the cascade for it.
    fn is_eagerly_cascaded_pseudo_element(pseudo: &<Self as SelectorImpl>::PseudoElement) -> bool;

    #[inline]
    fn each_eagerly_cascaded_pseudo_element<F>(mut fun: F)
        where F: FnMut(<Self as SelectorImpl>::PseudoElement) {
        Self::each_pseudo_element(|pseudo| {
            if Self::is_eagerly_cascaded_pseudo_element(&pseudo) {
                fun(pseudo)
            }
        })
    }

    #[inline]
    fn each_non_eagerly_cascaded_pseudo_element<F>(mut fun: F)
        where F: FnMut(<Self as SelectorImpl>::PseudoElement) {
        Self::each_pseudo_element(|pseudo| {
            if !Self::is_eagerly_cascaded_pseudo_element(&pseudo) {
                fun(pseudo)
            }
        })
    }

    fn pseudo_class_state_flag(pc: &Self::NonTSPseudoClass) -> ElementState;

    fn get_user_or_user_agent_stylesheets() -> &'static [Stylesheet<Self>];

    fn get_quirks_mode_stylesheet() -> Option<&'static Stylesheet<Self>>;
}

#[derive(Clone, Debug, PartialEq, Eq, HeapSizeOf, Hash)]
pub enum PseudoElement {
    Before,
    After,
    Selection,
    DetailsSummary,
    DetailsContent,
}

impl PseudoElement {
    #[inline]
    pub fn is_eagerly_cascaded(&self) -> bool {
        match *self {
            PseudoElement::Before |
            PseudoElement::After |
            PseudoElement::Selection |
            PseudoElement::DetailsSummary => true,
            PseudoElement::DetailsContent => false,
        }
    }
}

#[derive(Clone, Debug, PartialEq, Eq, HeapSizeOf, Hash)]
pub enum NonTSPseudoClass {
    AnyLink,
    Link,
    Visited,
    Active,
    Focus,
    Hover,
    Enabled,
    Disabled,
    Checked,
    Indeterminate,
    ServoNonZeroBorder,
    ReadWrite,
    ReadOnly
}

impl NonTSPseudoClass {
    pub fn state_flag(&self) -> ElementState {
        use element_state::*;
        use self::NonTSPseudoClass::*;
        match *self {
            Active => IN_ACTIVE_STATE,
            Focus => IN_FOCUS_STATE,
            Hover => IN_HOVER_STATE,
            Enabled => IN_ENABLED_STATE,
            Disabled => IN_DISABLED_STATE,
            Checked => IN_CHECKED_STATE,
            Indeterminate => IN_INDETERMINATE_STATE,
            ReadOnly | ReadWrite => IN_READ_WRITE_STATE,

            AnyLink |
            Link |
            Visited |
            ServoNonZeroBorder => ElementState::empty(),
        }
    }
}

#[derive(Clone, Debug, PartialEq, HeapSizeOf)]
pub struct ServoSelectorImpl;

impl SelectorImpl for ServoSelectorImpl {
    type PseudoElement = PseudoElement;
    type NonTSPseudoClass = NonTSPseudoClass;

    fn parse_non_ts_pseudo_class(context: &ParserContext,
                                 name: &str) -> Result<NonTSPseudoClass, ()> {
        use self::NonTSPseudoClass::*;
        let pseudo_class = match_ignore_ascii_case! { name,
            "any-link" => AnyLink,
            "link" => Link,
            "visited" => Visited,
            "active" => Active,
            "focus" => Focus,
            "hover" => Hover,
            "enabled" => Enabled,
            "disabled" => Disabled,
            "checked" => Checked,
            "indeterminate" => Indeterminate,
            "read-write" => ReadWrite,
            "read-only" => ReadOnly,
            "-servo-nonzero-border" => {
                if !context.in_user_agent_stylesheet {
                    return Err(());
                }
                ServoNonZeroBorder
            },
            _ => return Err(())
        };

        Ok(pseudo_class)
    }

    fn parse_pseudo_element(context: &ParserContext,
                            name: &str) -> Result<PseudoElement, ()> {
        use self::PseudoElement::*;
        let pseudo_element = match_ignore_ascii_case! { name,
            "before" => Before,
            "after" => After,
            "selection" => Selection,
            "-servo-details-summary" => {
                if !context.in_user_agent_stylesheet {
                    return Err(())
                }
                DetailsSummary
            },
            "-servo-details-content" => {
                if !context.in_user_agent_stylesheet {
                    return Err(())
                }
                DetailsContent
            },
            _ => return Err(())
        };

        Ok(pseudo_element)
    }
}

impl SelectorImplExt for ServoSelectorImpl {
    type ComputedValues = ServoComputedValues;

    #[inline]
    fn is_eagerly_cascaded_pseudo_element(pseudo: &PseudoElement) -> bool {
        pseudo.is_eagerly_cascaded()
    }

    #[inline]
    fn each_pseudo_element<F>(mut fun: F)
        where F: FnMut(PseudoElement) {
        fun(PseudoElement::Before);
        fun(PseudoElement::After);
        fun(PseudoElement::DetailsContent);
        fun(PseudoElement::DetailsSummary);
        fun(PseudoElement::Selection);
    }

    #[inline]
    fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState {
        pc.state_flag()
    }

    #[inline]
    fn get_user_or_user_agent_stylesheets() -> &'static [Stylesheet<Self>] {
        &*USER_OR_USER_AGENT_STYLESHEETS
    }

    #[inline]
    fn get_quirks_mode_stylesheet() -> Option<&'static Stylesheet<Self>> {
        Some(&*QUIRKS_MODE_STYLESHEET)
    }
}

impl<E: Element<Impl=ServoSelectorImpl>> ElementExt for E {
    fn is_link(&self) -> bool {
        self.match_non_ts_pseudo_class(NonTSPseudoClass::AnyLink)
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A mini version of ast::Ty, which is easier to use, and features an explicit `Self` type to use
//! when specifying impls to be derived.

pub use self::PtrTy::*;
pub use self::Ty::*;

use syntax::ast;
use syntax::ast::{Expr, GenericParamKind, Generics, Ident, SelfKind, GenericArg};
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::codemap::{respan, DUMMY_SP};
use syntax::ptr::P;
use syntax_pos::Span;
use syntax_pos::symbol::keywords;

/// The types of pointers
#[derive(Clone)]
pub enum PtrTy<'a> {
    /// &'lifetime mut
    Borrowed(Option<&'a str>, ast::Mutability),
    /// *mut
    Raw(ast::Mutability),
}

/// A path, e.g. `::std::option::Option::<i32>` (global). Has support
/// for type parameters and a lifetime.
#[derive(Clone)]
pub struct Path<'a> {
    path: Vec<&'a str>,
    lifetime: Option<&'a str>,
    params: Vec<Box<Ty<'a>>>,
    kind: PathKind,
}

#[derive(Clone)]
pub enum PathKind {
    Local,
    Global,
    Std,
}

impl<'a> Path<'a> {
    pub fn new<'r>(path: Vec<&'r str>) -> Path<'r> {
        Path::new_(path, None, Vec::new(), PathKind::Std)
    }
    pub fn new_local<'r>(path: &'r str) -> Path<'r> {
        Path::new_(vec![path], None, Vec::new(), PathKind::Local)
    }
    pub fn new_<'r>(path: Vec<&'r str>,
                    lifetime: Option<&'r str>,
                    params: Vec<Box<Ty<'r>>>,
                    kind: PathKind)
                    -> Path<'r> {
        Path {
            path,
            lifetime,
            params,
            kind,
        }
    }

    pub fn to_ty(&self,
                 cx: &ExtCtxt,
                 span: Span,
                 self_ty: Ident,
                 self_generics: &Generics)
                 -> P<ast::Ty> {
        cx.ty_path(self.to_path(cx, span, self_ty, self_generics))
    }
    pub fn to_path(&self,
                   cx: &ExtCtxt,
                   span: Span,
                   self_ty: Ident,
                   self_generics: &Generics)
                   -> ast::Path {
        let mut idents = self.path.iter().map(|s| cx.ident_of(*s)).collect();
        let lt = mk_lifetimes(cx, span, &self.lifetime);
        let tys: Vec<P<ast::Ty>> =
            self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect();
        let params = lt.into_iter()
                       .map(|lt| GenericArg::Lifetime(lt))
                       .chain(tys.into_iter().map(|ty| GenericArg::Type(ty)))
                       .collect();

        match self.kind {
            PathKind::Global => cx.path_all(span, true, idents, params, Vec::new()),
            PathKind::Local => cx.path_all(span, false, idents, params, Vec::new()),
            PathKind::Std => {
                let def_site = DUMMY_SP.apply_mark(cx.current_expansion.mark);
                idents.insert(0, Ident::new(keywords::DollarCrate.name(), def_site));
                cx.path_all(span, false, idents, params, Vec::new())
            }
        }

    }
}

/// A type. Supports pointers, Self, and literals
#[derive(Clone)]
pub enum Ty<'a> {
    Self_,
    /// &/Box/ Ty
    Ptr(Box<Ty<'a>>, PtrTy<'a>),
    /// mod::mod::Type<[lifetime], [Params...]>, including a plain type
    /// parameter, and things like `i32`
    Literal(Path<'a>),
    /// includes unit
    Tuple(Vec<Ty<'a>>),
}

pub fn borrowed_ptrty<'r>() -> PtrTy<'r> {
    Borrowed(None, ast::Mutability::Immutable)
}
pub fn borrowed<'r>(ty: Box<Ty<'r>>) -> Ty<'r> {
    Ptr(ty, borrowed_ptrty())
}

pub fn borrowed_explicit_self<'r>() -> Option<Option<PtrTy<'r>>> {
    Some(Some(borrowed_ptrty()))
}

pub fn borrowed_self<'r>() -> Ty<'r> {
    borrowed(Box::new(Self_))
}

pub fn nil_ty<'r>() -> Ty<'r> {
    Tuple(Vec::new())
}

fn mk_lifetime(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Option<ast::Lifetime> {
    match *lt {
        Some(s) => Some(cx.lifetime(span, Ident::from_str(s))),
        None => None,
    }
}

fn mk_lifetimes(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Vec<ast::Lifetime> {
    match *lt {
        Some(s) => vec![cx.lifetime(span, Ident::from_str(s))],
        None => vec![],
    }
}

impl<'a> Ty<'a> {
    pub fn to_ty(&self,
                 cx: &ExtCtxt,
                 span: Span,
                 self_ty: Ident,
                 self_generics: &Generics)
                 -> P<ast::Ty> {
        match *self {
            Ptr(ref ty, ref ptr) => {
                let raw_ty = ty.to_ty(cx, span, self_ty, self_generics);
                match *ptr {
                    Borrowed(ref lt, mutbl) => {
                        let lt = mk_lifetime(cx, span, lt);
                        cx.ty_rptr(span, raw_ty, lt, mutbl)
                    }
                    Raw(mutbl) => cx.ty_ptr(span, raw_ty, mutbl),
                }
            }
            Literal(ref p) => p.to_ty(cx, span, self_ty, self_generics),
            Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)),
            Tuple(ref fields) => {
                let ty = ast::TyKind::Tup(fields.iter()
                    .map(|f| f.to_ty(cx, span, self_ty, self_generics))
                    .collect());
                cx.ty(span, ty)
            }
        }
    }

    pub fn to_path(&self,
                   cx: &ExtCtxt,
                   span: Span,
                   self_ty: Ident,
                   generics: &Generics)
                   -> ast::Path {
        match *self {
            Self_ => {
                let params: Vec<_> = generics.params.iter().map(|param| match param.kind {
                    GenericParamKind::Lifetime { .. } => {
                        GenericArg::Lifetime(ast::Lifetime { id: param.id, ident: param.ident })
                    }
                    GenericParamKind::Type { .. } => {
                        GenericArg::Type(cx.ty_ident(span, param.ident))
                    }
                }).collect();

                cx.path_all(span, false, vec![self_ty], params, vec![])
            }
            Literal(ref p) => p.to_path(cx, span, self_ty, generics),
            Ptr(..) => cx.span_bug(span, "pointer in a path in generic `derive`"),
            Tuple(..) => cx.span_bug(span, "tuple in a path in generic `derive`"),
        }
    }
}

fn mk_ty_param(cx: &ExtCtxt,
               span: Span,
               name: &str,
               attrs: &[ast::Attribute],
               bounds: &[Path],
               self_ident: Ident,
               self_generics: &Generics)
               -> ast::GenericParam {
    let bounds = bounds.iter()
        .map(|b| {
            let path = b.to_path(cx, span, self_ident, self_generics);
            cx.trait_bound(path)
        })
        .collect();
    cx.typaram(span, cx.ident_of(name), attrs.to_owned(), bounds, None)
}

fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {
    Generics {
        params,
        where_clause: ast::WhereClause {
            id: ast::DUMMY_NODE_ID,
            predicates: Vec::new(),
            span,
        },
        span,
    }
}

/// Lifetimes and bounds on type parameters
#[derive(Clone)]
pub struct LifetimeBounds<'a> {
    pub lifetimes: Vec<(&'a str, Vec<&'a str>)>,
    pub bounds: Vec<(&'a str, Vec<Path<'a>>)>,
}

impl<'a> LifetimeBounds<'a> {
    pub fn empty() -> LifetimeBounds<'a> {
        LifetimeBounds {
            lifetimes: Vec::new(),
            bounds: Vec::new(),
        }
    }
    pub fn to_generics(&self,
                       cx: &ExtCtxt,
                       span: Span,
                       self_ty: Ident,
                       self_generics: &Generics)
                       -> Generics {
        let generic_params = self.lifetimes
            .iter()
            .map(|&(lt, ref bounds)| {
                let bounds = bounds.iter()
                    .map(|b| ast::GenericBound::Outlives(cx.lifetime(span, Ident::from_str(b))));
                cx.lifetime_def(span, Ident::from_str(lt), vec![], bounds.collect())
            })
            .chain(self.bounds
                .iter()
                .map(|t| {
                    let (name, ref bounds) = *t;
                    mk_ty_param(cx, span, name, &[], &bounds, self_ty, self_generics)
                })
            )
            .collect();

        mk_generics(generic_params, span)
    }
}

pub fn get_explicit_self(cx: &ExtCtxt,
                         span: Span,
                         self_ptr: &Option<PtrTy>)
                         -> (P<Expr>, ast::ExplicitSelf) {
    // this constructs a fresh `self` path
    let self_path = cx.expr_self(span);
    match *self_ptr {
        None => (self_path, respan(span, SelfKind::Value(ast::Mutability::Immutable))),
        Some(ref ptr) => {
            let self_ty =
                respan(span,
                       match *ptr {
                           Borrowed(ref lt, mutbl) => {
                               let lt = lt.map(|s| cx.lifetime(span, Ident::from_str(s)));
                               SelfKind::Region(lt, mutbl)
                           }
                           Raw(_) => {
                               cx.span_bug(span, "attempted to use *self in deriving definition")
                           }
                       });
            let self_expr = cx.expr_deref(span, self_path);
            (self_expr, self_ty)
        }
    }
}
<commit_msg>libsyntax_ext: Prefer `Option::map` over `match` where applicable<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A mini version of ast::Ty, which is easier to use, and features an explicit `Self` type to use
//! when specifying impls to be derived.

pub use self::PtrTy::*;
pub use self::Ty::*;

use syntax::ast;
use syntax::ast::{Expr, GenericParamKind, Generics, Ident, SelfKind, GenericArg};
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::codemap::{respan, DUMMY_SP};
use syntax::ptr::P;
use syntax_pos::Span;
use syntax_pos::symbol::keywords;

/// The types of pointers
#[derive(Clone)]
pub enum PtrTy<'a> {
    /// &'lifetime mut
    Borrowed(Option<&'a str>, ast::Mutability),
    /// *mut
    Raw(ast::Mutability),
}

/// A path, e.g. `::std::option::Option::<i32>` (global). Has support
/// for type parameters and a lifetime.
#[derive(Clone)]
pub struct Path<'a> {
    path: Vec<&'a str>,
    lifetime: Option<&'a str>,
    params: Vec<Box<Ty<'a>>>,
    kind: PathKind,
}

#[derive(Clone)]
pub enum PathKind {
    Local,
    Global,
    Std,
}

impl<'a> Path<'a> {
    pub fn new<'r>(path: Vec<&'r str>) -> Path<'r> {
        Path::new_(path, None, Vec::new(), PathKind::Std)
    }
    pub fn new_local<'r>(path: &'r str) -> Path<'r> {
        Path::new_(vec![path], None, Vec::new(), PathKind::Local)
    }
    pub fn new_<'r>(path: Vec<&'r str>,
                    lifetime: Option<&'r str>,
                    params: Vec<Box<Ty<'r>>>,
                    kind: PathKind)
                    -> Path<'r> {
        Path {
            path,
            lifetime,
            params,
            kind,
        }
    }

    pub fn to_ty(&self,
                 cx: &ExtCtxt,
                 span: Span,
                 self_ty: Ident,
                 self_generics: &Generics)
                 -> P<ast::Ty> {
        cx.ty_path(self.to_path(cx, span, self_ty, self_generics))
    }
    pub fn to_path(&self,
                   cx: &ExtCtxt,
                   span: Span,
                   self_ty: Ident,
                   self_generics: &Generics)
                   -> ast::Path {
        let mut idents = self.path.iter().map(|s| cx.ident_of(*s)).collect();
        let lt = mk_lifetimes(cx, span, &self.lifetime);
        let tys: Vec<P<ast::Ty>> =
            self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect();
        let params = lt.into_iter()
                       .map(|lt| GenericArg::Lifetime(lt))
                       .chain(tys.into_iter().map(|ty| GenericArg::Type(ty)))
                       .collect();

        match self.kind {
            PathKind::Global => cx.path_all(span, true, idents, params, Vec::new()),
            PathKind::Local => cx.path_all(span, false, idents, params, Vec::new()),
            PathKind::Std => {
                let def_site = DUMMY_SP.apply_mark(cx.current_expansion.mark);
                idents.insert(0, Ident::new(keywords::DollarCrate.name(), def_site));
                cx.path_all(span, false, idents, params, Vec::new())
            }
        }

    }
}

/// A type. Supports pointers, Self, and literals
#[derive(Clone)]
pub enum Ty<'a> {
    Self_,
    /// &/Box/ Ty
    Ptr(Box<Ty<'a>>, PtrTy<'a>),
    /// mod::mod::Type<[lifetime], [Params...]>, including a plain type
    /// parameter, and things like `i32`
    Literal(Path<'a>),
    /// includes unit
    Tuple(Vec<Ty<'a>>),
}

pub fn borrowed_ptrty<'r>() -> PtrTy<'r> {
    Borrowed(None, ast::Mutability::Immutable)
}
pub fn borrowed<'r>(ty: Box<Ty<'r>>) -> Ty<'r> {
    Ptr(ty, borrowed_ptrty())
}

pub fn borrowed_explicit_self<'r>() -> Option<Option<PtrTy<'r>>> {
    Some(Some(borrowed_ptrty()))
}

pub fn borrowed_self<'r>() -> Ty<'r> {
    borrowed(Box::new(Self_))
}

pub fn nil_ty<'r>() -> Ty<'r> {
    Tuple(Vec::new())
}

fn mk_lifetime(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Option<ast::Lifetime> {
    lt.map(|s|
        cx.lifetime(span, Ident::from_str(s))
    )
}

fn mk_lifetimes(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Vec<ast::Lifetime> {
    mk_lifetime(cx, span, lt).into_iter().collect()
}

impl<'a> Ty<'a> {
    pub fn to_ty(&self,
                 cx: &ExtCtxt,
                 span: Span,
                 self_ty: Ident,
                 self_generics: &Generics)
                 -> P<ast::Ty> {
        match *self {
            Ptr(ref ty, ref ptr) => {
                let raw_ty = ty.to_ty(cx, span, self_ty, self_generics);
                match *ptr {
                    Borrowed(ref lt, mutbl) => {
                        let lt = mk_lifetime(cx, span, lt);
                        cx.ty_rptr(span, raw_ty, lt, mutbl)
                    }
                    Raw(mutbl) => cx.ty_ptr(span, raw_ty, mutbl),
                }
            }
            Literal(ref p) => p.to_ty(cx, span, self_ty, self_generics),
            Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)),
            Tuple(ref fields) => {
                let ty = ast::TyKind::Tup(fields.iter()
                    .map(|f| f.to_ty(cx, span, self_ty, self_generics))
                    .collect());
                cx.ty(span, ty)
            }
        }
    }

    pub fn to_path(&self,
                   cx: &ExtCtxt,
                   span: Span,
                   self_ty: Ident,
                   generics: &Generics)
                   -> ast::Path {
        match *self {
            Self_ => {
                let params: Vec<_> = generics.params.iter().map(|param| match param.kind {
                    GenericParamKind::Lifetime { .. } => {
                        GenericArg::Lifetime(ast::Lifetime { id: param.id, ident: param.ident })
                    }
                    GenericParamKind::Type { .. } => {
                        GenericArg::Type(cx.ty_ident(span, param.ident))
                    }
                }).collect();

                cx.path_all(span, false, vec![self_ty], params, vec![])
            }
            Literal(ref p) => p.to_path(cx, span, self_ty, generics),
            Ptr(..) => cx.span_bug(span, "pointer in a path in generic `derive`"),
            Tuple(..) => cx.span_bug(span, "tuple in a path in generic `derive`"),
        }
    }
}

fn mk_ty_param(cx: &ExtCtxt,
               span: Span,
               name: &str,
               attrs: &[ast::Attribute],
               bounds: &[Path],
               self_ident: Ident,
               self_generics: &Generics)
               -> ast::GenericParam {
    let bounds = bounds.iter()
        .map(|b| {
            let path = b.to_path(cx, span, self_ident, self_generics);
            cx.trait_bound(path)
        })
        .collect();
    cx.typaram(span, cx.ident_of(name), attrs.to_owned(), bounds, None)
}

fn mk_generics(params: Vec<ast::GenericParam>, span: Span) -> Generics {
    Generics {
        params,
        where_clause: ast::WhereClause {
            id: ast::DUMMY_NODE_ID,
            predicates: Vec::new(),
            span,
        },
        span,
    }
}

/// Lifetimes and bounds on type parameters
#[derive(Clone)]
pub struct LifetimeBounds<'a> {
    pub lifetimes: Vec<(&'a str, Vec<&'a str>)>,
    pub bounds: Vec<(&'a str, Vec<Path<'a>>)>,
}

impl<'a> LifetimeBounds<'a> {
    pub fn empty() -> LifetimeBounds<'a> {
        LifetimeBounds {
            lifetimes: Vec::new(),
            bounds: Vec::new(),
        }
    }
    pub fn to_generics(&self,
                       cx: &ExtCtxt,
                       span: Span,
                       self_ty: Ident,
                       self_generics: &Generics)
                       -> Generics {
        let generic_params = self.lifetimes
            .iter()
            .map(|&(lt, ref bounds)| {
                let bounds = bounds.iter()
                    .map(|b| ast::GenericBound::Outlives(cx.lifetime(span, Ident::from_str(b))));
                cx.lifetime_def(span, Ident::from_str(lt), vec![], bounds.collect())
            })
            .chain(self.bounds
                .iter()
                .map(|t| {
                    let (name, ref bounds) = *t;
                    mk_ty_param(cx, span, name, &[], &bounds, self_ty, self_generics)
                })
            )
            .collect();

        mk_generics(generic_params, span)
    }
}

pub fn get_explicit_self(cx: &ExtCtxt,
                         span: Span,
                         self_ptr: &Option<PtrTy>)
                         -> (P<Expr>, ast::ExplicitSelf) {
    // this constructs a fresh `self` path
    let self_path = cx.expr_self(span);
    match *self_ptr {
        None => (self_path, respan(span, SelfKind::Value(ast::Mutability::Immutable))),
        Some(ref ptr) => {
            let self_ty =
                respan(span,
                       match *ptr {
                           Borrowed(ref lt, mutbl) => {
                               let lt = lt.map(|s| cx.lifetime(span, Ident::from_str(s)));
                               SelfKind::Region(lt, mutbl)
                           }
                           Raw(_) => {
                               cx.span_bug(span, "attempted to use *self in deriving definition")
                           }
                       });
            let self_expr = cx.expr_deref(span, self_path);
            (self_expr, self_ty)
        }
    }
}
<|endoftext|>


<commit_before>use anyhow::Result;
use bitflags::bitflags;
use thiserror::Error;

use crate::{
    aspace::{AbsoluteAddressSpace, AddressSpace},
    pagemap::PageMapError::NotMapped,
    RVA, VA,
};

#[derive(Error, Debug)]
pub enum ModuleError {
    #[error("invalid address: {0:#x}")]
    InvalidAddress(u64),
}

#[derive(Copy, Clone, Debug)]
pub enum Arch {
    X32,
    X64,
}

impl Arch {
    pub fn pointer_size(&self) -> usize {
        match self {
            Arch::X32 => 4,
            Arch::X64 => 8,
        }
    }
}

bitflags! {
    pub struct Permissions: u8 {
        const R = 0b0000_0001;
        const W = 0b0000_0010;
        const X = 0b0000_0100;
        const RW = Self::R.bits | Self::W.bits;
        const RX =  Self::R.bits | Self::X.bits;
        const WX =  Self::W.bits | Self::X.bits;
        const RWX =  Self::R.bits | Self::W.bits | Self::X.bits;
    }
}

#[derive(Debug, Clone)]
pub struct Section {
    // source data, from the PE file, relative to file start.
    pub physical_range: std::ops::Range<RVA>,
    // as mapped into memory with absolute addresses.
    pub virtual_range:  std::ops::Range<VA>,
    pub perms:          Permissions,
    pub name:           String,
}

/// An address space, as a file would be loaded into memory.
/// This has an associated architecture (e.g. x32 or x64),
/// base address, and collection of sections.
/// This is the information that we'd expect to be common across formats.
#[derive(Clone)]
pub struct Module {
    pub arch:          Arch,
    pub sections:      Vec<Section>,
    pub address_space: AbsoluteAddressSpace,
}

impl Module {
    pub fn read_va_at_rva(&self, offset: RVA) -> Result<VA> {
        match self.arch {
            Arch::X32 => Ok(self.address_space.relative.read_u32(offset)? as VA),
            Arch::X64 => Ok(self.address_space.relative.read_u64(offset)? as VA),
        }
    }

    pub fn read_rva_at_rva(&self, offset: RVA) -> Result<RVA> {
        match self.arch {
            Arch::X32 => Ok(self.address_space.relative.read_u32(offset)? as RVA),
            Arch::X64 => Ok(self.address_space.relative.read_u64(offset)? as RVA),
        }
    }

    pub fn read_va_at_va(&self, offset: VA) -> Result<VA> {
        match self.arch {
            Arch::X32 => Ok(self.address_space.read_u32(offset)? as VA),
            Arch::X64 => Ok(self.address_space.read_u64(offset)? as VA),
        }
    }

    pub fn read_rva_at_va(&self, offset: VA) -> Result<RVA> {
        match self.arch {
            Arch::X32 => Ok(self.address_space.read_u32(offset)? as RVA),
            Arch::X64 => Ok(self.address_space.read_u64(offset)? as RVA),
        }
    }

    pub fn probe_va(&self, offset: VA, perm: Permissions) -> bool {
        self.sections
            .iter()
            .any(|section| section.virtual_range.contains(&offset) && section.perms.intersects(perm))
    }

    pub fn probe_rva(&self, offset: RVA, perm: Permissions) -> bool {
        let va = self.address_space.base_address + offset;
        self.probe_va(va, perm)
    }

    pub fn file_offset(&self, va: VA) -> Result<usize> {
        if let Some(sec) = self.sections.iter().find(|&sec| sec.virtual_range.contains(&va)) {
            let offset = va - sec.virtual_range.start;
            Ok((offset + sec.physical_range.start) as usize)
        } else {
            Err(NotMapped.into())
        }
    }
}
<commit_msg>module: add virtual_address from file_offset<commit_after>use anyhow::Result;
use bitflags::bitflags;
use thiserror::Error;

use crate::{
    aspace::{AbsoluteAddressSpace, AddressSpace},
    pagemap::PageMapError::NotMapped,
    RVA, VA,
};

#[derive(Error, Debug)]
pub enum ModuleError {
    #[error("invalid address: {0:#x}")]
    InvalidAddress(u64),
}

#[derive(Copy, Clone, Debug)]
pub enum Arch {
    X32,
    X64,
}

impl Arch {
    pub fn pointer_size(&self) -> usize {
        match self {
            Arch::X32 => 4,
            Arch::X64 => 8,
        }
    }
}

bitflags! {
    pub struct Permissions: u8 {
        const R = 0b0000_0001;
        const W = 0b0000_0010;
        const X = 0b0000_0100;
        const RW = Self::R.bits | Self::W.bits;
        const RX =  Self::R.bits | Self::X.bits;
        const WX =  Self::W.bits | Self::X.bits;
        const RWX =  Self::R.bits | Self::W.bits | Self::X.bits;
    }
}

#[derive(Debug, Clone)]
pub struct Section {
    // source data, from the PE file, relative to file start.
    pub physical_range: std::ops::Range<RVA>,
    // as mapped into memory with absolute addresses.
    pub virtual_range:  std::ops::Range<VA>,
    pub perms:          Permissions,
    pub name:           String,
}

/// An address space, as a file would be loaded into memory.
/// This has an associated architecture (e.g. x32 or x64),
/// base address, and collection of sections.
/// This is the information that we'd expect to be common across formats.
#[derive(Clone)]
pub struct Module {
    pub arch:          Arch,
    pub sections:      Vec<Section>,
    pub address_space: AbsoluteAddressSpace,
}

impl Module {
    pub fn read_va_at_rva(&self, offset: RVA) -> Result<VA> {
        match self.arch {
            Arch::X32 => Ok(self.address_space.relative.read_u32(offset)? as VA),
            Arch::X64 => Ok(self.address_space.relative.read_u64(offset)? as VA),
        }
    }

    pub fn read_rva_at_rva(&self, offset: RVA) -> Result<RVA> {
        match self.arch {
            Arch::X32 => Ok(self.address_space.relative.read_u32(offset)? as RVA),
            Arch::X64 => Ok(self.address_space.relative.read_u64(offset)? as RVA),
        }
    }

    pub fn read_va_at_va(&self, offset: VA) -> Result<VA> {
        match self.arch {
            Arch::X32 => Ok(self.address_space.read_u32(offset)? as VA),
            Arch::X64 => Ok(self.address_space.read_u64(offset)? as VA),
        }
    }

    pub fn read_rva_at_va(&self, offset: VA) -> Result<RVA> {
        match self.arch {
            Arch::X32 => Ok(self.address_space.read_u32(offset)? as RVA),
            Arch::X64 => Ok(self.address_space.read_u64(offset)? as RVA),
        }
    }

    pub fn probe_va(&self, offset: VA, perm: Permissions) -> bool {
        self.sections
            .iter()
            .any(|section| section.virtual_range.contains(&offset) && section.perms.intersects(perm))
    }

    pub fn probe_rva(&self, offset: RVA, perm: Permissions) -> bool {
        let va = self.address_space.base_address + offset;
        self.probe_va(va, perm)
    }

    pub fn file_offset(&self, va: VA) -> Result<usize> {
        if let Some(sec) = self.sections.iter().find(|&sec| sec.virtual_range.contains(&va)) {
            let offset = va - sec.virtual_range.start;
            Ok((offset + sec.physical_range.start) as usize)
        } else {
            Err(NotMapped.into())
        }
    }

    pub fn virtual_address(&self, file_offset: u64) -> Result<VA> {
        self.sections
            .iter()
            .find(|&sec| sec.physical_range.contains(&(file_offset as u64)))
            .map(|sec| {
                let section_offset = file_offset as u64 - sec.physical_range.start;
                sec.virtual_range.start + section_offset
            })
            .ok_or(NotMapped.into())
    }
}
<|endoftext|>


<commit_before>use wtftw_core::core::*;

extern crate wtftw_core;

#[test]
fn stack_add() {
    let s1 = Stack::from_element(42);
    let s2 = s1.add(23);

    assert!(s2.focus == 23);
    assert!(s1.up == s2.up);
    assert!(s1.focus == s2.down[0]);
}

#[test]
fn stack_integrate() {
    let s1 = Stack::new(1, vec!(2, 3), vec!(4, 5, 6));
    assert!(s1.integrate() == vec!(3, 2, 1, 4, 5, 6));
}

#[test]
fn stack_filter() {
    let s1 = Stack::new(1, vec!(2, 3), vec!(4, 5, 6));
    let s2 = s1.filter(|&x| x != 3);

    assert!(s2.is_some());
    assert!(s2.unwrap() == Stack::new(1, vec!(2), vec!(4, 5, 6)));
}

#[test]
fn stack_focus_up() {
    let s1 = Stack::new(1, vec!(2, 3), vec!(4, 5, 6));
    let s2 = s1.focus_up();

    assert!(s2 == Stack::new(2, vec!(3), vec!(1, 4, 5, 6)));
}

#[test]
fn stack_focus_down() {
    let s1 = Stack::new(1, vec!(2, 3), vec!(4, 5, 6));
    let s2 = s1.focus_down();

    assert!(s2 == Stack::new(4, vec!(1, 2, 3), vec!(5, 6)));
}

#[test]
fn stack_reverse() {
    let v1 = vec!(2, 3);
    let v2 = vec!(4, 5, 6);

    let s1 = Stack::new(1, v1.clone(), v2.clone());
    let s2 = Stack::new(1, v2.clone(), v1.clone());

    assert!(s1.reverse() == s2);
    assert!(s2.reverse() == s1);
    assert!(s1.reverse().reverse() == s1);
}

#[test]
fn stack_len() {
    let s1 = Stack::new(1, vec!(2, 3), vec!(4, 5, 6));

    assert!(s1.len() == 6);
}

#[test]
fn stack_contains() {
    let s1 = Stack::new(42, vec!(2, 3), vec!(4, 5, 6));
    let s2 = Stack::new(23, Vec::new(), Vec::new());

    assert!(s1.contains(42));
    assert!(!s1.contains(23));
    assert!(!s2.contains(42));
    assert!(s2.contains(23));
}
<commit_msg>updated testcases<commit_after>use wtftw_core::core::*;
use wtftw_core::layout::FullLayout;

extern crate wtftw_core;

#[test]
fn stack_add() {
    let s1 = Stack::from_element(42);
    let s2 = s1.add(23);

    assert!(s2.focus == 23);
    assert!(s1.up == s2.up);
    assert!(s1.focus == s2.down[0]);
}

#[test]
fn stack_integrate() {
    let s1 = Stack::new(1, vec!(2, 3), vec!(4, 5, 6));
    assert!(s1.integrate() == vec!(3, 2, 1, 4, 5, 6));
}

#[test]
fn stack_filter() {
    let s1 = Stack::new(1, vec!(2, 3), vec!(4, 5, 6));
    let s2 = s1.filter(|&x| x != 3);

    assert!(s2.is_some());
    assert!(s2.unwrap() == Stack::new(1, vec!(2), vec!(4, 5, 6)));
}

#[test]
fn stack_focus_up() {
    let s1 = Stack::new(1, vec!(2, 3), vec!(4, 5, 6));
    let s2 = s1.focus_up();

    assert!(s2 == Stack::new(2, vec!(3), vec!(1, 4, 5, 6)));
}

#[test]
fn stack_focus_down() {
    let s1 = Stack::new(1, vec!(2, 3), vec!(4, 5, 6));
    let s2 = s1.focus_down();

    assert!(s2 == Stack::new(4, vec!(1, 2, 3), vec!(5, 6)));
}

#[test]
fn stack_reverse() {
    let v1 = vec!(2, 3);
    let v2 = vec!(4, 5, 6);

    let s1 = Stack::new(1, v1.clone(), v2.clone());
    let s2 = Stack::new(1, v2.clone(), v1.clone());

    assert!(s1.reverse() == s2);
    assert!(s2.reverse() == s1);
    assert!(s1.reverse().reverse() == s1);
}

#[test]
fn stack_len() {
    let s1 = Stack::new(1, vec!(2, 3), vec!(4, 5, 6));

    assert!(s1.len() == 6);
}

#[test]
fn stack_contains() {
    let s1 = Stack::new(42, vec!(2, 3), vec!(4, 5, 6));
    let s2 = Stack::new(23, Vec::new(), Vec::new());

    assert!(s1.contains(42));
    assert!(!s1.contains(23));
    assert!(!s2.contains(42));
    assert!(s2.contains(23));
}

#[test]
fn workspace_contains() {
    let s1 = Stack::new(42, vec!(2, 3), vec!(4, 5, 6));
    let w1 = Workspace::new(1, String::from_str("Foo"), Box::new(FullLayout), Some(s1));
    let w2 = Workspace::new(1, String::from_str("Foo"), Box::new(FullLayout), None);

    assert!(w1.contains(42));
    assert!(!w1.contains(23));
    assert!(!w2.contains(2));
}
<|endoftext|>


<commit_before>use Type;

#[derive(Clone,Debug,PartialEq,Eq)]
pub enum Value
{
    Local {
        number: u32,
        ty: Type,
    },
    Argument {
        number: u32,
        ty: Type,
    },
    ConstantInteger {
        bit_width: u32,
        value: i64,
    },
}

impl Value
{
    pub fn ty(&self) -> Type {
        match *self {
            Value::Local { ref ty, .. } => ty.clone(),
            Value::Argument { ref ty, .. } => ty.clone(),
            Value::ConstantInteger { bit_width, .. } => {
                Type::Integer { bit_width: bit_width }
            },
        }
    }

    pub fn i(width: u32, value: i64) -> Self {
        Value::ConstantInteger {
            bit_width: width,
            value: value,
        }
    }

    pub fn expect_constant_integer(&self) -> i64 {
        if let Value::ConstantInteger { value, .. } = *self {
            value
        } else {
            panic!("expected a constant integer");
        }
    }
}
<commit_msg>[mir] Replace 'Local' with 'Register'<commit_after>use Type;

/// A register.
/// Stores the zero-based index of the node in the
/// DAG that is referred to.
#[derive(Clone,Debug,PartialEq,Eq)]
pub struct Register {
    /// The number of the node that is referred to.
    /// Zero based.
    pub number: u32,
    /// The number of the result from the node.
    pub value_number: u32,
    /// The type.
    pub ty: Type,
}

#[derive(Clone,Debug,PartialEq,Eq)]
pub enum Value
{
    /// An argument to the function.
    Argument {
        number: u32,
        ty: Type,
    },
    /// A constant integer.
    ConstantInteger {
        bit_width: u32,
        value: i64,
    },
    /// A register.
    Register(Register),
}

impl Value
{
    /// Gets the type of the value.
    pub fn ty(&self) -> Type {
        match *self {
            Value::Argument { ref ty, .. } => ty.clone(),
            Value::ConstantInteger { bit_width, .. } => {
                Type::Integer { bit_width: bit_width }
            },
            Value::Register(ref reg)  => reg.ty.clone(),
        }
    }

    /// Creates a new n-bit constant integer.
    pub fn i(width: u32, value: i64) -> Self {
        Value::ConstantInteger {
            bit_width: width,
            value: value,
        }
    }

    pub fn expect_constant_integer(&self) -> i64 {
        if let Value::ConstantInteger { value, .. } = *self {
            value
        } else {
            panic!("expected a constant integer");
        }
    }
}
<|endoftext|>


<commit_before>pub use self::client::{Client, ClientResponse};
pub use self::error::Error;
pub use self::publisher::{Publisher, PublisherStream};
pub use self::service::Service;
pub use self::subscriber::Subscriber;

use crate::rosmsg::RosMsg;
use crate::Clock;
use std::fmt::Debug;
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;

mod client;
pub mod error;
mod header;
mod publisher;
mod service;
mod subscriber;
mod util;

pub type ServiceResult<T> = Result<T, String>;

pub trait Message: Clone + Debug + Default + PartialEq + RosMsg + Send + 'static {
    fn msg_definition() -> String;
    fn md5sum() -> String;
    fn msg_type() -> String;
    fn set_header(&mut self, _clock: &Arc<Clock>, _seq: &Arc<AtomicUsize>) {}
}

pub trait ServicePair: Clone + Debug + Default + PartialEq + Message {
    type Request: RosMsg + Send + 'static;
    type Response: RosMsg + Send + 'static;
}

#[derive(Clone, Debug)]
pub struct Topic {
    pub name: String,
    pub msg_type: String,
}
<commit_msg>Fix missing Sync trait in messages<commit_after>pub use self::client::{Client, ClientResponse};
pub use self::error::Error;
pub use self::publisher::{Publisher, PublisherStream};
pub use self::service::Service;
pub use self::subscriber::Subscriber;

use crate::rosmsg::RosMsg;
use crate::Clock;
use std::fmt::Debug;
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;

mod client;
pub mod error;
mod header;
mod publisher;
mod service;
mod subscriber;
mod util;

pub type ServiceResult<T> = Result<T, String>;

pub trait Message: Clone + Debug + Default + PartialEq + RosMsg + Send + Sync + 'static {
    fn msg_definition() -> String;
    fn md5sum() -> String;
    fn msg_type() -> String;
    fn set_header(&mut self, _clock: &Arc<Clock>, _seq: &Arc<AtomicUsize>) {}
}

pub trait ServicePair: Clone + Debug + Default + PartialEq + Message {
    type Request: RosMsg + Send + 'static;
    type Response: RosMsg + Send + 'static;
}

#[derive(Clone, Debug)]
pub struct Topic {
    pub name: String,
    pub msg_type: String,
}
<|endoftext|>


<commit_before>// compile-flags: -C no-prepopulate-passes

#![crate_type = "lib"]
#![feature(core_intrinsics)]

use std::intrinsics::exact_div;

// CHECK-LABEL: @exact_sdiv
#[no_mangle]
pub unsafe fn exact_sdiv(x: i32, y: i32) -> i32 {
// CHECK: sdiv exact
    exact_div(x, y)
}

// CHECK-LABEL: @exact_udiv
#[no_mangle]
pub unsafe fn exact_udiv(x: u32, y: u32) -> u32 {
// CHECK: udiv exact
    exact_div(x, y)
}
<commit_msg>improve test indentation<commit_after>// compile-flags: -C no-prepopulate-passes

#![crate_type = "lib"]
#![feature(core_intrinsics)]

use std::intrinsics::exact_div;

// CHECK-LABEL: @exact_sdiv
#[no_mangle]
pub unsafe fn exact_sdiv(x: i32, y: i32) -> i32 {
    // CHECK: sdiv exact
    exact_div(x, y)
}

// CHECK-LABEL: @exact_udiv
#[no_mangle]
pub unsafe fn exact_udiv(x: u32, y: u32) -> u32 {
    // CHECK: udiv exact
    exact_div(x, y)
}
<|endoftext|>


<commit_before>extern crate pom;
use pom::parser::*;
use pom::Parser;

use std::str::{self, FromStr};

#[derive(Debug, PartialEq)]
struct Duration {
	years: Option<f32>,
	months: Option<f32>,
	weeks: Option<f32>,
	days: Option<f32>,
	hours: Option<f32>,
	minutes: Option<f32>,
	seconds: Option<f32>,
}

fn number_separator() -> Parser<u8, ()> {
	// either '.' or ',' can be used as a separator between the whole and decimal part of a number
	one_of(b".,").discard()
}

fn number() -> Parser<u8, f32> {
	let integer = one_of(b"0123456789").repeat(0..);
	let frac = number_separator() + one_of(b"0123456789").repeat(1..);
	let number = integer + frac.opt();
	number.collect().convert(str::from_utf8).convert(f32::from_str)
}

fn date_part() -> Parser<u8, (Option<f32>, Option<f32>, Option<f32>, Option<f32>)> {
	(
		(number() - sym(b'Y')).opt() +
		(number() - sym(b'M')).opt() +
		(number() - sym(b'W')).opt() +
		(number() - sym(b'D')).opt()
	)
		.map(|(((years,months), weeks), days)| {
			(years, months, weeks, days)
		})
}

fn time_part() -> Parser<u8, Option<(Option<f32>, Option<f32>, Option<f32>)>> {
	(
		sym(b'T') *
			(
				(number() - sym(b'H')).opt() +
					(number() - sym(b'M')).opt() +
					(number() - sym(b'S')).opt()
			)
				.map(|((hours,minutes), seconds)| {
					(hours, minutes, seconds)
				})
	).opt()
}

fn parser() -> Parser<u8, Duration> {
	(
		sym(b'P') *
		date_part() +
		time_part()
	)
		.map(|(date_elements, time_elements)|{
			let (years, months, weeks, days) = date_elements;
			let (hours, minutes, seconds) = match time_elements {
				None => (None, None, None),
				Some(elements) => elements,
			};

			Duration {
				years,
				months,
				weeks,
				days,
				hours,
				minutes,
				seconds,
			}
		})
}

/// Parses the ISO 8601 Duration standard
/// https://en.wikipedia.org/wiki/ISO_8601#Durations
fn main() {
	let input = "P3Y6M4DT12H30M5S";
	let result = parser().parse(input.as_bytes());

	assert_eq!(
		Duration {
			years: Some(3f32),
			months: Some(6f32),
			weeks: None,
			days: Some(4f32),
			hours: Some(12f32),
			minutes: Some(30f32),
			seconds: Some(5f32)
		},
		result.unwrap()
	);

}
<commit_msg>Example: avoid parsing a single "P" as duration<commit_after>extern crate pom;
use pom::parser::*;
use pom::Parser;

use std::str::{self, FromStr};

#[derive(Debug, PartialEq)]
struct Duration {
	years: Option<f32>,
	months: Option<f32>,
	weeks: Option<f32>,
	days: Option<f32>,
	hours: Option<f32>,
	minutes: Option<f32>,
	seconds: Option<f32>,
}

fn number_separator() -> Parser<u8, ()> {
	// either '.' or ',' can be used as a separator between the whole and decimal part of a number
	one_of(b".,").discard()
}

fn number() -> Parser<u8, f32> {
	let integer = one_of(b"0123456789").repeat(0..);
	let frac = number_separator() + one_of(b"0123456789").repeat(1..);
	let number = integer + frac.opt();
	number
		.collect()
		.convert(str::from_utf8)
		.convert(f32::from_str)
}

fn date_part() -> Parser<u8, (Option<f32>, Option<f32>, Option<f32>, Option<f32>)> {
	((number() - sym(b'Y')).opt()
		+ (number() - sym(b'M')).opt()
		+ (number() - sym(b'W')).opt()
		+ (number() - sym(b'D')).opt())
	.map(|(((years, months), weeks), days)| (years, months, weeks, days))
}

fn time_part() -> Parser<u8, (Option<f32>, Option<f32>, Option<f32>)> {
	sym(b'T')
		* ((number() - sym(b'H')).opt()
			+ (number() - sym(b'M')).opt()
			+ (number() - sym(b'S')).opt())
		.map(|((hours, minutes), seconds)| (hours, minutes, seconds))
}

fn parser() -> Parser<u8, Duration> {
	sym(b'P')
		* (time_part().map(|(hours, minutes, seconds)| Duration {
			years: None,
			months: None,
			weeks: None,
			days: None,
			hours,
			minutes,
			seconds,
		}) | (date_part() + time_part()).map(|(date_elements, time_elements)| {
			let (years, months, weeks, days) = date_elements;
			let (hours, minutes, seconds) = time_elements;
			Duration {
				years,
				months,
				weeks,
				days,
				hours,
				minutes,
				seconds,
			}
		}))
}

/// Parses the ISO 8601 Duration standard
/// https://en.wikipedia.org/wiki/ISO_8601#Durations
fn main() {
	let input = "P3Y6M4DT12H30M5S";
	let result = parser().parse(input.as_bytes());

	assert_eq!(
		Duration {
			years: Some(3f32),
			months: Some(6f32),
			weeks: None,
			days: Some(4f32),
			hours: Some(12f32),
			minutes: Some(30f32),
			seconds: Some(5f32)
		},
		result.unwrap()
	);
}
<|endoftext|>


<commit_before>use rustc::lint::*;
use syntax::ast::*;
use std::ops::Deref;
use syntax::ext::quote::rt::Span;

/// **What it does:** Checks for
///  - () being assigned to a variable
///  - () being passed to a function
///
/// **Why is this bad?** It is extremely unlikely that a user intended to
/// assign '()' to valiable. Instead,
/// Unit is what a block evaluates to when it returns nothing. This is
/// typically caused by a trailing
///   unintended semicolon.
///
/// **Known problems:** None.
///
/// **Example:**
/// * `let x = {"foo" ;}` when the user almost certainly intended `let x
/// ={"foo"}`

declare_lint! {
    pub UNIT_EXPR,
    Warn,
    "unintended assignment or use of a unit typed value"
}

#[derive(Copy, Clone)]
pub struct UnitExpr;

impl LintPass for UnitExpr {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNIT_EXPR)
    }
}

impl EarlyLintPass for UnitExpr {
    fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
        if let ExprKind::Assign(ref _left, ref right) = expr.node {
            if let Some(span) = is_unit_expr(right) {
                cx.span_lint(UNIT_EXPR, span, "Consider removing the trailing semicolon");
            }
        }
        if let ExprKind::MethodCall(ref _left, ref args) = expr.node {
            for ref arg in args {
                if let Some(span) = is_unit_expr(arg) {
                    cx.span_lint(UNIT_EXPR, span, "Consider removing the trailing semicolon");
                }
            }
        }
        if let ExprKind::Call(_, ref args) = expr.node {
            for ref arg in args {
                if let Some(span) = is_unit_expr(arg) {
                    cx.span_lint(UNIT_EXPR, span, "Consider removing the trailing semicolon");
                }
            }
        }
    }

    fn check_stmt(&mut self, cx: &EarlyContext, stmt: &Stmt) {
        if let StmtKind::Local(ref local) = stmt.node {
            if local.pat.node == PatKind::Wild {
                return;
            }
            if let Some(ref expr) = local.init {
                if let Some(span) = is_unit_expr(expr) {
                    cx.span_lint(UNIT_EXPR, span, "Consider removing the trailing semicolon");
                }
            }
        }
    }
}
fn is_unit_expr(expr: &Expr) -> Option<Span> {
    match expr.node {
        ExprKind::Block(ref block) => if check_last_stmt_in_block(block) {
            return Some(block.stmts[block.stmts.len() - 1].span.clone());
        } else {
            return None;
        },
        ExprKind::If(_, ref then, ref else_) => {
            let check_then = check_last_stmt_in_block(then);
            if let Some(ref else_) = *else_ {
                let check_else = is_unit_expr(else_.deref());
                if let Some(ref expr_else) = check_else {
                    return Some(expr_else.clone());
                } else {
                    return Some(expr.span.clone());
                }
            }
            if check_then {
                return Some(expr.span.clone());
            } else {
                return Some(expr.span.clone());
            }
        },
        ExprKind::Match(ref _pattern, ref arms) => {
            for ref arm in arms {
                if let Some(expr) = is_unit_expr(&arm.body) {
                    return Some(expr);
                }
            }
            return None;
        },
        _ => return None,
    }
}

fn check_last_stmt_in_block(block: &Block) -> bool {
    let ref final_stmt = &block.stmts[block.stmts.len() - 1];
    if let StmtKind::Expr(_) = final_stmt.node {
        return false;
    } else {
        return true;
    }
}
<commit_msg>Fix false positives in assignment inside the else condition<commit_after>use rustc::lint::*;
use syntax::ast::*;
use std::ops::Deref;
use syntax::ext::quote::rt::Span;

/// **What it does:** Checks for
///  - () being assigned to a variable
///  - () being passed to a function
///
/// **Why is this bad?** It is extremely unlikely that a user intended to
/// assign '()' to valiable. Instead,
/// Unit is what a block evaluates to when it returns nothing. This is
/// typically caused by a trailing
///   unintended semicolon.
///
/// **Known problems:** None.
///
/// **Example:**
/// * `let x = {"foo" ;}` when the user almost certainly intended `let x
/// ={"foo"}`

declare_lint! {
    pub UNIT_EXPR,
    Warn,
    "unintended assignment or use of a unit typed value"
}

#[derive(Copy, Clone)]
pub struct UnitExpr;

impl LintPass for UnitExpr {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNIT_EXPR)
    }
}

impl EarlyLintPass for UnitExpr {
    fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
        if let ExprKind::Assign(ref _left, ref right) = expr.node {
            if let Some(span) = is_unit_expr(right) {
                cx.span_lint(UNIT_EXPR, span, "Consider removing the trailing semicolon");
            }
        }
        if let ExprKind::MethodCall(ref _left, ref args) = expr.node {
            for ref arg in args {
                if let Some(span) = is_unit_expr(arg) {
                    cx.span_lint(UNIT_EXPR, span, "Consider removing the trailing semicolon");
                }
            }
        }
        if let ExprKind::Call(_, ref args) = expr.node {
            for ref arg in args {
                if let Some(span) = is_unit_expr(arg) {
                    cx.span_lint(UNIT_EXPR, span, "Consider removing the trailing semicolon");
                }
            }
        }
    }

    fn check_stmt(&mut self, cx: &EarlyContext, stmt: &Stmt) {
        if let StmtKind::Local(ref local) = stmt.node {
            if local.pat.node == PatKind::Wild {
                return;
            }
            if let Some(ref expr) = local.init {
                if let Some(span) = is_unit_expr(expr) {
                    cx.span_lint(UNIT_EXPR, span, "Consider removing the trailing semicolon");
                }
            }
        }
    }
}
fn is_unit_expr(expr: &Expr) -> Option<Span> {
    match expr.node {
        ExprKind::Block(ref block) => if check_last_stmt_in_block(block) {
            return Some(block.stmts[block.stmts.len() - 1].span.clone());
        } else {
            return None;
        },
        ExprKind::If(_, ref then, ref else_) => {
            let check_then = check_last_stmt_in_block(then);
            if let Some(ref else_) = *else_ {
                let check_else = is_unit_expr(else_.deref());
                if let Some(ref expr_else) = check_else {
                    return Some(expr_else.clone());
                }
            }
            if check_then {
                return Some(expr.span.clone());
            } else {
                return None;
            }
        },
        ExprKind::Match(ref _pattern, ref arms) => {
            for ref arm in arms {
                if let Some(expr) = is_unit_expr(&arm.body) {
                    return Some(expr);
                }
            }
            return None;
        },
        _ => return None,
    }
}

fn check_last_stmt_in_block(block: &Block) -> bool {
    let ref final_stmt = &block.stmts[block.stmts.len() - 1];
    if let StmtKind::Expr(_) = final_stmt.node {
        return false;
    } else {
        return true;
    }
}
<|endoftext|>


<commit_before>
#![cfg(test)]

use crypto::sha3::Sha3;

use merkletree::{ MerkleTree };
use merkledigest::{ MerkleDigest };
use proof::{ Positioned };

#[test]
fn test_from_str_vec() {
    let mut digest = Sha3::sha3_256();

    let values = vec![
                        "one",
                        "two",
                        "three",
                        "four"
                    ];

    let hashes = vec![
                        digest.hash_bytes(&values[0].into()),
                        digest.hash_bytes(&values[1].into()),
                        digest.hash_bytes(&values[2].into()),
                        digest.hash_bytes(&values[3].into())
                    ];

    let count  = values.len();

    let tree   = MerkleTree::from_vec(digest, values);

    let mut d = Sha3::sha3_256();

    let h01 = &d.combine_hashes(&hashes[0], &hashes[1]);
    let h23 = &d.combine_hashes(&hashes[2], &hashes[3]);

    let root_hash = d.combine_hashes(h01, h23);

    assert_eq!(tree.count(), count);
    assert_eq!(tree.height(), 2);
    assert_eq!(tree.root_hash().as_slice(), root_hash.as_slice());
}

#[test]
#[should_panic]
fn test_from_vec_empty() {
    let digest          = Sha3::sha3_256();
    let values: Vec<Vec<u8>> = vec![];

    MerkleTree::from_vec(digest, values);
}

#[test]
fn test_from_vec1() {
    let digest = Sha3::sha3_256();

    let values = vec!["hello, world".to_string()];
    let tree = MerkleTree::from_vec(digest, values);

    let mut d = Sha3::sha3_256();

    let root_hash = &d.hash_bytes(&"hello, world".to_string().into());

    assert_eq!(tree.count(), 1);
    assert_eq!(tree.height(), 0);
    assert_eq!(tree.root_hash().as_slice(), root_hash.as_slice());
}

#[test]
fn test_from_vec3() {
    let digest = Sha3::sha3_256();

    let values = vec![vec![1], vec![2], vec![3]];
    let tree = MerkleTree::from_vec(digest, values);

    let mut d = Sha3::sha3_256();

    let hashes = vec![
        d.hash_bytes(&vec![1].into()),
        d.hash_bytes(&vec![2].into()),
        d.hash_bytes(&vec![3].into())
    ];

    let h01       = &d.combine_hashes(&hashes[0], &hashes[1]);
    let h2        = &hashes[2];
    let root_hash = &d.combine_hashes(h01, h2);

    assert_eq!(tree.count(), 3);
    assert_eq!(tree.height(), 2);
    assert_eq!(tree.root_hash().as_slice(), root_hash.as_slice());
}

#[test]
fn test_from_vec9() {
    let digest = Sha3::sha3_256();

    let values = vec![vec![1], vec![2], vec![3], vec![4], vec![5], vec![6], vec![7], vec![8], vec![9]];
    let count  = values.len();

    let tree = MerkleTree::from_vec(digest, values.clone());

    let mut d = Sha3::sha3_256();

    let hashes = values.iter().map(|v| d.hash_bytes(v.into())).collect::<Vec<_>>();

    let h01   = &d.combine_hashes(&hashes[0], &hashes[1]);
    let h23   = &d.combine_hashes(&hashes[2], &hashes[3]);
    let h45   = &d.combine_hashes(&hashes[4], &hashes[5]);
    let h67   = &d.combine_hashes(&hashes[6], &hashes[7]);
    let h8    = &hashes[8];
    let h0123 = &d.combine_hashes(h01, h23);
    let h4567 = &d.combine_hashes(h45, h67);
    let h1to7 = &d.combine_hashes(h0123, h4567);

    let root_hash = &d.combine_hashes(h1to7, h8);

    assert_eq!(tree.count(), count);
    assert_eq!(tree.height(), 4);
    assert_eq!(tree.root_hash().as_slice(), root_hash.as_slice());
}

#[test]
fn test_valid_proof() {
    let digest               = Sha3::sha3_256();
    let values: Vec<Vec<u8>> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9].iter().map(|x| vec![*x]).collect();
    let tree                 = MerkleTree::from_vec(digest, values.clone());
    let root_hash            = tree.root_hash();

    for value in values.iter() {
        let proof    = tree.gen_proof(value);
        let is_valid = proof.map(|p| p.validate(&root_hash)).unwrap_or(false);

        assert!(is_valid);
    }
}

#[test]
fn test_valid_proof_str() {
    let digest    = Sha3::sha3_256();
    let values    = vec!["Hello", "my", "name", "is", "Rusty"];
    let tree      = MerkleTree::from_vec(digest, values.clone());
    let root_hash = tree.root_hash();

    let value = "Rusty";

    let proof    = tree.gen_proof(&value);
    let is_valid = proof.map(|p| p.validate(&root_hash)).unwrap_or(false);

    assert!(is_valid);
}

#[test]
fn test_wrong_proof() {
    let digest1   = Sha3::sha3_256();
    let values1   = vec![vec![1], vec![2], vec![3], vec![4]];
    let tree1     = MerkleTree::from_vec(digest1, values1.clone());

    let digest2   = Sha3::sha3_256();
    let values2   = vec![vec![4], vec![5], vec![6], vec![7]];
    let tree2     = MerkleTree::from_vec(digest2, values2.clone());
    let root_hash = tree2.root_hash();

    for value in values1.iter() {
        let proof    = tree1.gen_proof(value);
        let is_valid = proof.map(|p| p.validate(root_hash)).unwrap_or(false);

        assert_eq!(is_valid, false);
    }
}

#[test]
fn test_mutate_proof_first_lemma() {
    let digest    = Sha3::sha3_256();
    let values    = vec![1, 2, 3, 4].iter().map(|x| vec![*x]).collect::<Vec<Vec<u8>>>();
    let tree      = MerkleTree::from_vec(digest, values.clone());
    let root_hash = tree.root_hash();

    let mut i = 0;

    for value in values.iter() {
        let mut proof = tree.gen_proof(value).unwrap();

        if i % 2 == 0 {
            let sibling_hash = proof.lemma_mut().node_hash_mut();
            *sibling_hash = vec![1,2,3];
        } else {
            let sibling_hash = proof.lemma_mut().sibling_hash_mut();
            *sibling_hash = Positioned::Left(vec![1,2,3]);
        }

        let is_valid = proof.validate(root_hash);
        assert_eq!(is_valid, false);

        i += 1;
    }
}
<commit_msg>Cleanup tests a bit.<commit_after>
#![cfg(test)]

use crypto::sha3::Sha3;

use merkletree::{ MerkleTree };
use merkledigest::{ MerkleDigest };
use proof::{ Positioned };

#[test]
fn test_from_str_vec() {
    let mut digest = Sha3::sha3_256();

    let values = vec![ "one", "two", "three", "four" ];

    let hashes = vec![
        digest.hash_bytes(&values[0].into()),
        digest.hash_bytes(&values[1].into()),
        digest.hash_bytes(&values[2].into()),
        digest.hash_bytes(&values[3].into())
    ];

    let count = values.len();
    let tree  = MerkleTree::from_vec(Sha3::sha3_256(), values);

    let h01 = digest.combine_hashes(&hashes[0], &hashes[1]);
    let h23 = digest.combine_hashes(&hashes[2], &hashes[3]);

    let root_hash = digest.combine_hashes(&h01, &h23);

    assert_eq!(tree.count(), count);
    assert_eq!(tree.height(), 2);
    assert_eq!(tree.root_hash().as_slice(), root_hash.as_slice());
}

#[test]
#[should_panic]
fn test_from_vec_empty() {
    let values: Vec<Vec<u8>> = vec![];
    MerkleTree::from_vec(Sha3::sha3_256(), values);
}

#[test]
fn test_from_vec1() {
    let values = vec!["hello, world".to_string()];
    let tree   = MerkleTree::from_vec(Sha3::sha3_256(), values);

    let mut d     = Sha3::sha3_256();
    let root_hash = &d.hash_bytes(&"hello, world".to_string().into());

    assert_eq!(tree.count(), 1);
    assert_eq!(tree.height(), 0);
    assert_eq!(tree.root_hash().as_slice(), root_hash.as_slice());
}

#[test]
fn test_from_vec3() {
    let values = vec![vec![1], vec![2], vec![3]];
    let tree   = MerkleTree::from_vec(Sha3::sha3_256(), values);

    let mut d = Sha3::sha3_256();

    let hashes = vec![
        d.hash_bytes(&vec![1].into()),
        d.hash_bytes(&vec![2].into()),
        d.hash_bytes(&vec![3].into())
    ];

    let h01       = &d.combine_hashes(&hashes[0], &hashes[1]);
    let h2        = &hashes[2];
    let root_hash = &d.combine_hashes(h01, h2);

    assert_eq!(tree.count(), 3);
    assert_eq!(tree.height(), 2);
    assert_eq!(tree.root_hash().as_slice(), root_hash.as_slice());
}

#[test]
fn test_from_vec9() {
    let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
    let tree   = MerkleTree::from_vec(Sha3::sha3_256(), values.clone());

    let mut d = Sha3::sha3_256();

    let hashes = values.iter().map(|v| d.hash_bytes(v.into())).collect::<Vec<_>>();

    let h01   = &d.combine_hashes(&hashes[0], &hashes[1]);
    let h23   = &d.combine_hashes(&hashes[2], &hashes[3]);
    let h45   = &d.combine_hashes(&hashes[4], &hashes[5]);
    let h67   = &d.combine_hashes(&hashes[6], &hashes[7]);
    let h8    = &hashes[8];
    let h0123 = &d.combine_hashes(h01, h23);
    let h4567 = &d.combine_hashes(h45, h67);
    let h1to7 = &d.combine_hashes(h0123, h4567);

    let root_hash = &d.combine_hashes(h1to7, h8);

    assert_eq!(tree.count(), 9);
    assert_eq!(tree.height(), 4);
    assert_eq!(tree.root_hash().as_slice(), root_hash.as_slice());
}

#[test]
fn test_valid_proof() {
    let values    = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
    let tree      = MerkleTree::from_vec(Sha3::sha3_256(), values.clone());
    let root_hash = tree.root_hash();

    for value in values.iter() {
        let proof    = tree.gen_proof(value);
        let is_valid = proof.map(|p| p.validate(&root_hash)).unwrap_or(false);

        assert!(is_valid);
    }
}

#[test]
fn test_valid_proof_str() {
    let values    = vec!["Hello", "my", "name", "is", "Rusty"];
    let tree      = MerkleTree::from_vec(Sha3::sha3_256(), values.clone());
    let root_hash = tree.root_hash();

    let value = "Rusty";

    let proof    = tree.gen_proof(&value);
    let is_valid = proof.map(|p| p.validate(&root_hash)).unwrap_or(false);

    assert!(is_valid);
}

#[test]
fn test_wrong_proof() {
    let values1   = vec![vec![1], vec![2], vec![3], vec![4]];
    let tree1     = MerkleTree::from_vec(Sha3::sha3_256(), values1.clone());

    let values2   = vec![vec![4], vec![5], vec![6], vec![7]];
    let tree2     = MerkleTree::from_vec(Sha3::sha3_256(), values2.clone());

    let root_hash = tree2.root_hash();

    for value in values1.iter() {
        let proof    = tree1.gen_proof(value);
        let is_valid = proof.map(|p| p.validate(root_hash)).unwrap_or(false);

        assert_eq!(is_valid, false);
    }
}

#[test]
fn test_mutate_proof_first_lemma() {
    let values    = (1..5).map(|x| vec![x]).collect::<Vec<_>>();
    let tree      = MerkleTree::from_vec(Sha3::sha3_256(), values.clone());
    let root_hash = tree.root_hash();

    let mut i = 0;

    for value in values.iter() {
        let mut proof = tree.gen_proof(value).unwrap();

        if i % 2 == 0 {
            let sibling_hash = proof.lemma_mut().node_hash_mut();
            *sibling_hash    = vec![1,2,3];
        } else {
            let sibling_hash = proof.lemma_mut().sibling_hash_mut();
            *sibling_hash    = Positioned::Left(vec![1, 2, 3]);
        }

        let is_valid = proof.validate(root_hash);
        assert_eq!(is_valid, false);

        i += 1;
    }
}

<|endoftext|>