<commit_before>// Copyright 2015 Pierre Talbot (IRCAM)

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

//! AST of a PEG expression that is shared across all the compiling steps.

pub use identifier::*;

use rust;
use std::fmt::{Formatter, Display, Error};

pub type RTy = rust::P<rust::Ty>;
pub type RExpr = rust::P<rust::Expr>;
pub type RItem = rust::P<rust::Item>;
pub type RStmt = Option<rust::Stmt>;
pub type RPat = rust::P<rust::Pat>;
pub type RArg = rust::Arg;

pub use rust::{ExtCtxt, Attribute, SpannedIdent};
pub use partial::Partial;

pub use middle::typing::ast::IType;
pub use middle::typing::ast::Type;

use middle::analysis::ast::GrammarAttributes;

use std::collections::HashMap;
use std::default::Default;
use std::ops::{Index, IndexMut};

pub trait ExprByIndex
{
  fn expr_by_index(&self, index: usize) -> Expression;
}

pub struct Grammar<'a, 'b:'a, ExprInfo>
{
  pub cx: &'a ExtCtxt<'b>,
  pub name: Ident,
  pub rules: Vec<Rule>,
  pub exprs: Vec<Expression>,
  pub exprs_info: Vec<ExprInfo>,
  pub stream_alias: RItem,
  pub rust_functions: HashMap<Ident, RItem>,
  pub rust_items: Vec<RItem>,
  pub attributes: GrammarAttributes
}

impl<'a, 'b, ExprInfo> Grammar<'a, 'b, ExprInfo>
{
  pub fn new(cx: &'a ExtCtxt<'b>, name: Ident, exprs: Vec<Expression>,
    exprs_info: Vec<ExprInfo>) -> Grammar<'a, 'b, ExprInfo>
  {
    Grammar {
      cx: cx,
      name: name,
      rules: vec![],
      exprs: exprs,
      exprs_info: exprs_info,
      stream_alias: quote_item!(cx, pub type Stream<'a> = StrStream<'a>;).unwrap(),
      rust_functions: HashMap::new(),
      rust_items: vec![],
      attributes: GrammarAttributes::default()
    }
  }

  pub fn warn(&self, msg: String) {
    self.cx.parse_sess.span_diagnostic.warn(msg.as_str());
  }

  /// The first element of `errors` will be rendered as an error and the other one as notes.
  pub fn multi_locations_err(&self, errors: Vec<(Span, String)>) {
    assert!(errors.len() > 0, "`errors` must at least contain one element.");
    let mut errors_iter = errors.into_iter();
    let (span, msg) = errors_iter.next().unwrap();
    let mut db = self.cx.struct_span_err(span, msg.as_str());
    for (span, msg) in errors_iter {
      db.span_note(span, msg.as_str());
    }
    db.emit();
  }

  /// The first element of `errors` will be rendered as an error and the other one as notes.
  pub fn multi_locations_warn(&self, warnings: Vec<(Span, String)>) {
    for (span, msg) in warnings {
      self.cx.span_warn(span, msg.as_str());
    }
  }

  pub fn span_err(&self, span: Span, msg: String) {
    self.cx.span_err(span, msg.as_str());
  }

  pub fn span_note(&self, span: Span, msg: String) {
    self.cx.parse_sess.span_diagnostic
      .span_note_without_error(span, msg.as_str());
  }

  pub fn find_rule_by_ident(&self, id: Ident) -> Rule {
    self.rules.iter()
      .find(|r| r.ident() == id)
      .expect("Rule ident not registered in the known rules.")
      .clone()
  }

  pub fn expr_index_of_rule(&self, id: Ident) -> usize {
    self.find_rule_by_ident(id).expr_idx
  }

  pub fn stream_generics(&self) -> rust::Generics {
    match &self.stream_alias.node {
      &rust::ItemKind::Ty(_, ref generics) => generics.clone(),
      _ => unreachable!()
    }
  }

  pub fn stream_type(&self) -> RTy {
    use rust::*;
    let generics = self.stream_generics();
    let generics_params = PathParameters::AngleBracketed(
      AngleBracketedParameterData {
        lifetimes: generics.lifetimes.into_iter().map(|l| l.lifetime).collect(),
        types: P::from_vec(generics.ty_params.into_iter()
          .map(|ty| ty.ident)
          .map(|ty| quote_ty!(self.cx, $ty))
          .collect()),
        bindings: P::new(),
      });

    let stream_ty = quote_ty!(self.cx, Stream);
    if let TyKind::Path(qself, mut path) = stream_ty.node.clone() {
      path.segments.last_mut().unwrap().parameters = generics_params;
      let ty_path = TyKind::Path(qself, path);
      let ty = Ty {
        id: stream_ty.id,
        node: ty_path,
        span: stream_ty.span
      };
      quote_ty!(self.cx, $ty)
    } else { unreachable!() }
  }
}

impl<'a, 'b, ExprInfo> Index<usize> for Grammar<'a, 'b, ExprInfo>
{
  type Output = ExprInfo;

  fn index<'c>(&'c self, index: usize) -> &'c Self::Output {
    &self.exprs_info[index]
  }
}

impl<'a, 'b, ExprInfo> IndexMut<usize> for Grammar<'a, 'b, ExprInfo>
{
  fn index_mut<'c>(&'c mut self, index: usize) -> &'c mut Self::Output {
    &mut self.exprs_info[index]
  }
}

impl<'a, 'b, ExprInfo> Grammar<'a, 'b, ExprInfo> where
 ExprInfo: ItemSpan
{
  pub fn expr_err(&self, expr_idx: usize, msg: String) {
    self.span_err(self[expr_idx].span(), msg);
  }
}

impl<'a, 'b, ExprInfo> ExprByIndex for Grammar<'a, 'b, ExprInfo>
{
  fn expr_by_index(&self, index: usize) -> Expression {
    self.exprs[index].clone()
  }
}

#[derive(Clone, Copy)]
pub struct Rule
{
  pub name: SpannedIdent,
  pub expr_idx: usize,
}

impl Rule
{
  pub fn new(name: SpannedIdent, expr_idx: usize) -> Rule {
    Rule{
      name: name,
      expr_idx: expr_idx
    }
  }
}

impl ItemIdent for Rule
{
  fn ident(&self) -> Ident {
    self.name.node.clone()
  }
}

impl ItemSpan for Rule
{
  fn span(&self) -> Span {
    self.name.span.clone()
  }
}

#[derive(Clone, Debug)]
pub enum Expression
{
  StrLiteral(String), // "match me"
  AnySingleChar, // .
  CharacterClass(CharacterClassExpr), // [0-9]
  NonTerminalSymbol(Ident), // a_rule
  Sequence(Vec<usize>), // a_rule next_rule
  Choice(Vec<usize>), // try_this / or_try_this_one
  ZeroOrMore(usize), // expr*
  OneOrMore(usize), // expr+
  ZeroOrOne(usize), // expr?
  NotPredicate(usize), // !expr
  AndPredicate(usize), // &expr
  SemanticAction(usize, Ident), // expr > function
  TypeAscription(usize, IType), // expr -> () or expr -> (^)
  SpannedExpr(usize), // .. expr
}

#[derive(Clone, Debug)]
pub struct CharacterClassExpr
{
  pub intervals: Vec<CharacterInterval>
}

impl CharacterClassExpr
{
  pub fn new(intervals: Vec<CharacterInterval>) -> CharacterClassExpr {
    CharacterClassExpr {
      intervals: intervals
    }
  }
}

impl Display for CharacterClassExpr
{
  fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
    formatter.write_str("[\"")?;
    for interval in &self.intervals {
      interval.fmt(formatter)?;
    }
    formatter.write_str("\"]")
  }
}

#[derive(Clone, Debug)]
pub struct CharacterInterval
{
  pub lo: char,
  pub hi: char
}

impl CharacterInterval
{
  pub fn new(lo: char, hi: char) -> CharacterInterval {
    CharacterInterval {
      lo: lo,
      hi: hi
    }
  }

  pub fn escape_lo(&self) -> String {
    self.lo.escape_default().collect()
  }

  pub fn escape_hi(&self) -> String {
    self.hi.escape_default().collect()
  }
}

impl Display for CharacterInterval
{
  fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
    if self.lo == self.hi {
      formatter.write_str(self.escape_lo().as_str())
    }
    else {
      formatter.write_fmt(format_args!("{}-{}", self.escape_lo(), self.escape_hi()))
    }
  }
}

pub fn display_path_cycle(path: &Vec<Ident>) -> String {
  let mut path_desc = String::new();
  for rule in path {
    path_desc.extend(format!("{} -> ", rule).chars());
  }
  path_desc.extend(format!("{}", path[0]).chars());
  path_desc
}
<commit_msg>Fixing AST to make it compile on 1.16.0-nightly.<commit_after>// Copyright 2015 Pierre Talbot (IRCAM)

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

//! AST of a PEG expression that is shared across all the compiling steps.

pub use identifier::*;

use rust;
use std::fmt::{Formatter, Display, Error};

pub type RTy = rust::P<rust::Ty>;
pub type RExpr = rust::P<rust::Expr>;
pub type RItem = rust::P<rust::Item>;
pub type RStmt = Option<rust::Stmt>;
pub type RPat = rust::P<rust::Pat>;
pub type RArg = rust::Arg;

pub use rust::{ExtCtxt, Attribute, SpannedIdent};
pub use partial::Partial;

pub use middle::typing::ast::IType;
pub use middle::typing::ast::Type;

use middle::analysis::ast::GrammarAttributes;

use std::collections::HashMap;
use std::default::Default;
use std::ops::{Index, IndexMut};

pub trait ExprByIndex
{
  fn expr_by_index(&self, index: usize) -> Expression;
}

pub struct Grammar<'a, 'b:'a, ExprInfo>
{
  pub cx: &'a ExtCtxt<'b>,
  pub name: Ident,
  pub rules: Vec<Rule>,
  pub exprs: Vec<Expression>,
  pub exprs_info: Vec<ExprInfo>,
  pub stream_alias: RItem,
  pub rust_functions: HashMap<Ident, RItem>,
  pub rust_items: Vec<RItem>,
  pub attributes: GrammarAttributes
}

impl<'a, 'b, ExprInfo> Grammar<'a, 'b, ExprInfo>
{
  pub fn new(cx: &'a ExtCtxt<'b>, name: Ident, exprs: Vec<Expression>,
    exprs_info: Vec<ExprInfo>) -> Grammar<'a, 'b, ExprInfo>
  {
    Grammar {
      cx: cx,
      name: name,
      rules: vec![],
      exprs: exprs,
      exprs_info: exprs_info,
      stream_alias: quote_item!(cx, pub type Stream<'a> = StrStream<'a>;).unwrap(),
      rust_functions: HashMap::new(),
      rust_items: vec![],
      attributes: GrammarAttributes::default()
    }
  }

  pub fn warn(&self, msg: String) {
    self.cx.parse_sess.span_diagnostic.warn(msg.as_str());
  }

  /// The first element of `errors` will be rendered as an error and the other one as notes.
  pub fn multi_locations_err(&self, errors: Vec<(Span, String)>) {
    assert!(errors.len() > 0, "`errors` must at least contain one element.");
    let mut errors_iter = errors.into_iter();
    let (span, msg) = errors_iter.next().unwrap();
    let mut db = self.cx.struct_span_err(span, msg.as_str());
    for (span, msg) in errors_iter {
      db.span_note(span, msg.as_str());
    }
    db.emit();
  }

  /// The first element of `errors` will be rendered as an error and the other one as notes.
  pub fn multi_locations_warn(&self, warnings: Vec<(Span, String)>) {
    for (span, msg) in warnings {
      self.cx.span_warn(span, msg.as_str());
    }
  }

  pub fn span_err(&self, span: Span, msg: String) {
    self.cx.span_err(span, msg.as_str());
  }

  pub fn span_note(&self, span: Span, msg: String) {
    self.cx.parse_sess.span_diagnostic
      .span_note_without_error(span, msg.as_str());
  }

  pub fn find_rule_by_ident(&self, id: Ident) -> Rule {
    self.rules.iter()
      .find(|r| r.ident() == id)
      .expect("Rule ident not registered in the known rules.")
      .clone()
  }

  pub fn expr_index_of_rule(&self, id: Ident) -> usize {
    self.find_rule_by_ident(id).expr_idx
  }

  pub fn stream_generics(&self) -> rust::Generics {
    match &self.stream_alias.node {
      &rust::ItemKind::Ty(_, ref generics) => generics.clone(),
      _ => unreachable!()
    }
  }

  pub fn stream_type(&self) -> RTy {
    use rust::*;
    let generics = self.stream_generics();
    let generics_params = PathParameters::AngleBracketed(
      AngleBracketedParameterData {
        lifetimes: generics.lifetimes.into_iter().map(|l| l.lifetime).collect(),
        types: P::from_vec(generics.ty_params.into_iter()
          .map(|ty| ty.ident)
          .map(|ty| quote_ty!(self.cx, $ty))
          .collect()),
        bindings: P::new(),
      });

    let stream_ty = quote_ty!(self.cx, Stream);
    if let TyKind::Path(qself, mut path) = stream_ty.node.clone() {
      path.segments.last_mut().unwrap().parameters = Some(P(generics_params));
      let ty_path = TyKind::Path(qself, path);
      let ty = Ty {
        id: stream_ty.id,
        node: ty_path,
        span: stream_ty.span
      };
      quote_ty!(self.cx, $ty)
    } else { unreachable!() }
  }
}

impl<'a, 'b, ExprInfo> Index<usize> for Grammar<'a, 'b, ExprInfo>
{
  type Output = ExprInfo;

  fn index<'c>(&'c self, index: usize) -> &'c Self::Output {
    &self.exprs_info[index]
  }
}

impl<'a, 'b, ExprInfo> IndexMut<usize> for Grammar<'a, 'b, ExprInfo>
{
  fn index_mut<'c>(&'c mut self, index: usize) -> &'c mut Self::Output {
    &mut self.exprs_info[index]
  }
}

impl<'a, 'b, ExprInfo> Grammar<'a, 'b, ExprInfo> where
 ExprInfo: ItemSpan
{
  pub fn expr_err(&self, expr_idx: usize, msg: String) {
    self.span_err(self[expr_idx].span(), msg);
  }
}

impl<'a, 'b, ExprInfo> ExprByIndex for Grammar<'a, 'b, ExprInfo>
{
  fn expr_by_index(&self, index: usize) -> Expression {
    self.exprs[index].clone()
  }
}

#[derive(Clone, Copy)]
pub struct Rule
{
  pub name: SpannedIdent,
  pub expr_idx: usize,
}

impl Rule
{
  pub fn new(name: SpannedIdent, expr_idx: usize) -> Rule {
    Rule{
      name: name,
      expr_idx: expr_idx
    }
  }
}

impl ItemIdent for Rule
{
  fn ident(&self) -> Ident {
    self.name.node.clone()
  }
}

impl ItemSpan for Rule
{
  fn span(&self) -> Span {
    self.name.span.clone()
  }
}

#[derive(Clone, Debug)]
pub enum Expression
{
  StrLiteral(String), // "match me"
  AnySingleChar, // .
  CharacterClass(CharacterClassExpr), // [0-9]
  NonTerminalSymbol(Ident), // a_rule
  Sequence(Vec<usize>), // a_rule next_rule
  Choice(Vec<usize>), // try_this / or_try_this_one
  ZeroOrMore(usize), // expr*
  OneOrMore(usize), // expr+
  ZeroOrOne(usize), // expr?
  NotPredicate(usize), // !expr
  AndPredicate(usize), // &expr
  SemanticAction(usize, Ident), // expr > function
  TypeAscription(usize, IType), // expr -> () or expr -> (^)
  SpannedExpr(usize), // .. expr
}

#[derive(Clone, Debug)]
pub struct CharacterClassExpr
{
  pub intervals: Vec<CharacterInterval>
}

impl CharacterClassExpr
{
  pub fn new(intervals: Vec<CharacterInterval>) -> CharacterClassExpr {
    CharacterClassExpr {
      intervals: intervals
    }
  }
}

impl Display for CharacterClassExpr
{
  fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
    formatter.write_str("[\"")?;
    for interval in &self.intervals {
      interval.fmt(formatter)?;
    }
    formatter.write_str("\"]")
  }
}

#[derive(Clone, Debug)]
pub struct CharacterInterval
{
  pub lo: char,
  pub hi: char
}

impl CharacterInterval
{
  pub fn new(lo: char, hi: char) -> CharacterInterval {
    CharacterInterval {
      lo: lo,
      hi: hi
    }
  }

  pub fn escape_lo(&self) -> String {
    self.lo.escape_default().collect()
  }

  pub fn escape_hi(&self) -> String {
    self.hi.escape_default().collect()
  }
}

impl Display for CharacterInterval
{
  fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
    if self.lo == self.hi {
      formatter.write_str(self.escape_lo().as_str())
    }
    else {
      formatter.write_fmt(format_args!("{}-{}", self.escape_lo(), self.escape_hi()))
    }
  }
}

pub fn display_path_cycle(path: &Vec<Ident>) -> String {
  let mut path_desc = String::new();
  for rule in path {
    path_desc.extend(format!("{} -> ", rule).chars());
  }
  path_desc.extend(format!("{}", path[0]).chars());
  path_desc
}
<|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 std::ascii::AsciiExt;
use std::cell::Cell;
use std::iter::Iterator;
use std::slice;
use url::Url;

use encoding::EncodingRef;

use cssparser::{Parser, decode_stylesheet_bytes, QualifiedRuleParser, AtRuleParser};
use cssparser::{RuleListParser, AtRuleType};
use font_face::{FontFaceRule, parse_font_face_block};
use media_queries::{Device, MediaQueryList, parse_media_query_list};
use parser::{ParserContext, log_css_error};
use properties::{PropertyDeclarationBlock, parse_property_declaration_list};
use selectors::parser::{Selector, parse_selector_list};
use smallvec::SmallVec;
use string_cache::{Atom, Namespace};
use viewport::ViewportRule;

/// Each style rule has an origin, which determines where it enters the cascade.
///
/// http://dev.w3.org/csswg/css-cascade/#cascading-origins
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
pub enum Origin {
    /// http://dev.w3.org/csswg/css-cascade/#cascade-origin-ua
    UserAgent,

    /// http://dev.w3.org/csswg/css-cascade/#cascade-origin-author
    Author,

    /// http://dev.w3.org/csswg/css-cascade/#cascade-origin-user
    User,
}

#[derive(Debug, PartialEq)]
pub struct Stylesheet {
    /// List of rules in the order they were found (important for
    /// cascading order)
    pub rules: Vec<CSSRule>,
    pub origin: Origin,
}

#[derive(Debug, PartialEq)]
pub enum CSSRule {
    Charset(String),
    Namespace(Option<String>, Namespace),
    Style(StyleRule),
    Media(MediaRule),
    FontFace(FontFaceRule),
    Viewport(ViewportRule),
}

#[derive(Debug, PartialEq)]
pub struct MediaRule {
    pub media_queries: MediaQueryList,
    pub rules: Vec<CSSRule>,
}

impl MediaRule {
    #[inline]
    pub fn evaluate(&self, device: &Device) -> bool {
        self.media_queries.evaluate(device)
    }
}

#[derive(Debug, PartialEq)]
pub struct StyleRule {
    pub selectors: Vec<Selector>,
    pub declarations: PropertyDeclarationBlock,
}

impl Stylesheet {
    pub fn from_bytes_iter<I: Iterator<Item=Vec<u8>>>(
            input: I, base_url: Url, protocol_encoding_label: Option<&str>,
            environment_encoding: Option<EncodingRef>, origin: Origin) -> Stylesheet {
        let mut bytes = vec![];
        // TODO: incremental decoding and tokenization/parsing
        for chunk in input {
            bytes.push_all(&chunk)
        }
        Stylesheet::from_bytes(&bytes, base_url, protocol_encoding_label,
                               environment_encoding, origin)
    }

    pub fn from_bytes(bytes: &[u8],
                      base_url: Url,
                      protocol_encoding_label: Option<&str>,
                      environment_encoding: Option<EncodingRef>,
                      origin: Origin)
                      -> Stylesheet {
        // TODO: bytes.as_slice could be bytes.container_as_bytes()
        let (string, _) = decode_stylesheet_bytes(
            bytes, protocol_encoding_label, environment_encoding);
        Stylesheet::from_str(&string, base_url, origin)
    }

    pub fn from_str<'i>(css: &'i str, base_url: Url, origin: Origin) -> Stylesheet {
        let rule_parser = TopLevelRuleParser {
            context: ParserContext::new(origin, &base_url),
            state: Cell::new(State::Start),
        };
        let mut input = Parser::new(css);
        let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser);
        let mut rules = Vec::new();
        while let Some(result) = iter.next() {
            match result {
                Ok(rule) => {
                    if let CSSRule::Namespace(ref prefix, ref namespace) = rule {
                        if let Some(prefix) = prefix.as_ref() {
                            iter.parser.context.selector_context.namespace_prefixes.insert(
                                prefix.clone(), namespace.clone());
                        } else {
                            iter.parser.context.selector_context.default_namespace =
                                Some(namespace.clone());
                        }
                    }
                    rules.push(rule);
                }
                Err(range) => {
                    let pos = range.start;
                    let message = format!("Invalid rule: '{}'", iter.input.slice(range));
                    log_css_error(iter.input, pos, &*message);
                }
            }
        }
        Stylesheet {
            origin: origin,
            rules: rules,
        }
    }

    /// Return an iterator over all the rules within the style-sheet.
    #[inline]
    pub fn rules<'a>(&'a self) -> Rules<'a> {
        Rules::new(self.rules.iter(), None)
    }

    /// Return an iterator over the effective rules within the style-sheet, as
    /// according to the supplied `Device`.
    ///
    /// If a condition does not hold, its associated conditional group rule and
    /// nested rules will be skipped. Use `rules` if all rules need to be
    /// examined.
    #[inline]
    pub fn effective_rules<'a>(&'a self, device: &'a Device) -> Rules<'a> {
        Rules::new(self.rules.iter(), Some(device))
    }
}

/// `CSSRule` iterator.
///
/// The iteration order is pre-order. Specifically, this implies that a
/// conditional group rule will come before its nested rules.
pub struct Rules<'a> {
    // 2 because normal case is likely to be just one level of nesting (@media)
    stack: SmallVec<[slice::Iter<'a, CSSRule>; 2]>,
    device: Option<&'a Device>
}

impl<'a> Rules<'a> {
    fn new(iter: slice::Iter<'a, CSSRule>, device: Option<&'a Device>) -> Rules<'a> {
        let mut stack: SmallVec<[slice::Iter<'a, CSSRule>; 2]> = SmallVec::new();
        stack.push(iter);

        Rules { stack: stack, device: device }
    }
}

impl<'a> Iterator for Rules<'a> {
    type Item = &'a CSSRule;

    fn next(&mut self) -> Option<&'a CSSRule> {
        while !self.stack.is_empty() {
            let top = self.stack.len() - 1;
            while let Some(rule) = self.stack[top].next() {
                // handle conditional group rules
                match rule {
                    &CSSRule::Media(ref rule) => {
                        if let Some(device) = self.device {
                            if rule.evaluate(device) {
                                self.stack.push(rule.rules.iter());
                            } else {
                                continue
                            }
                        } else {
                            self.stack.push(rule.rules.iter());
                        }
                    }
                    _ => {}
                }

                return Some(rule)
            }

            self.stack.pop();
        }
        None
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        // TODO: track total number of rules in style-sheet for upper bound?
        (0, None)
    }
}

pub mod rule_filter {
    //! Specific `CSSRule` variant iterators.

    use std::marker::PhantomData;
    use super::super::font_face::FontFaceRule;
    use super::super::viewport::ViewportRule;
    use super::{CSSRule, MediaRule, StyleRule};

    macro_rules! rule_filter {
        ($variant:ident -> $value:ty) => {
            /// An iterator that only yields rules that are of the synonymous `CSSRule` variant.
            #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
            pub struct $variant<'a, I> {
                iter: I,
                _lifetime: PhantomData<&'a ()>
            }

            impl<'a, I> $variant<'a, I> where I: Iterator<Item=&'a CSSRule> {
                pub fn new(iter: I) -> $variant<'a, I> {
                    $variant {
                        iter: iter,
                        _lifetime: PhantomData
                    }
                }
            }

            impl<'a, I> Iterator for $variant<'a, I> where I: Iterator<Item=&'a CSSRule> {
                type Item = &'a $value;

                fn next(&mut self) -> Option<&'a $value> {
                    while let Some(rule) = self.iter.next() {
                        match rule {
                            &CSSRule::$variant(ref value) => return Some(value),
                            _ => continue
                        }
                    }
                    None
                }

                #[inline]
                fn size_hint(&self) -> (usize, Option<usize>) {
                    (0, self.iter.size_hint().1)
                }
            }
        }
    }

    rule_filter!(FontFace -> FontFaceRule);
    rule_filter!(Media -> MediaRule);
    rule_filter!(Style -> StyleRule);
    rule_filter!(Viewport -> ViewportRule);
}

/// Extension methods for `CSSRule` iterators.
pub trait CSSRuleIteratorExt<'a>: Iterator<Item=&'a CSSRule> + Sized {
    /// Yield only @font-face rules.
    fn font_face(self) -> rule_filter::FontFace<'a, Self>;

    /// Yield only @media rules.
    fn media(self) -> rule_filter::Media<'a, Self>;

    /// Yield only style rules.
    fn style(self) -> rule_filter::Style<'a, Self>;

    /// Yield only @viewport rules.
    fn viewport(self) -> rule_filter::Viewport<'a, Self>;
}

impl<'a, I> CSSRuleIteratorExt<'a> for I where I: Iterator<Item=&'a CSSRule> {
    #[inline]
    fn font_face(self) -> rule_filter::FontFace<'a, I> {
        rule_filter::FontFace::new(self)
    }

    #[inline]
    fn media(self) -> rule_filter::Media<'a, I> {
        rule_filter::Media::new(self)
    }

    #[inline]
    fn style(self) -> rule_filter::Style<'a, I> {
        rule_filter::Style::new(self)
    }

    #[inline]
    fn viewport(self) -> rule_filter::Viewport<'a, I> {
        rule_filter::Viewport::new(self)
    }
}

fn parse_nested_rules(context: &ParserContext, input: &mut Parser) -> Vec<CSSRule> {
    let mut iter = RuleListParser::new_for_nested_rule(input, NestedRuleParser { context: context });
    let mut rules = Vec::new();
    while let Some(result) = iter.next() {
        match result {
            Ok(rule) => rules.push(rule),
            Err(range) => {
                let pos = range.start;
                let message = format!("Unsupported rule: '{}'", iter.input.slice(range));
                log_css_error(iter.input, pos, &*message);
            }
        }
    }
    rules
}

struct TopLevelRuleParser<'a> {
    context: ParserContext<'a>,
    state: Cell<State>,
}

#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
enum State {
    Start = 1,
    Imports = 2,
    Namespaces = 3,
    Body = 4,
}

enum AtRulePrelude {
    FontFace,
    Media(MediaQueryList),
    Viewport,
}

impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
    type Prelude = AtRulePrelude;
    type AtRule = CSSRule;

    fn parse_prelude(&self, name: &str, input: &mut Parser)
                     -> Result<AtRuleType<AtRulePrelude, CSSRule>, ()> {
        match_ignore_ascii_case! { name,
            "charset" => {
                if self.state.get() <= State::Start {
                    // Valid @charset rules are just ignored
                    self.state.set(State::Imports);
                    let charset = try!(input.expect_string()).into_owned();
                    return Ok(AtRuleType::WithoutBlock(CSSRule::Charset(charset)))
                } else {
                    return Err(())  // "@charset must be the first rule"
                }
            },
            "import" => {
                if self.state.get() <= State::Imports {
                    self.state.set(State::Imports);
                    // TODO: support @import
                    return Err(())  // "@import is not supported yet"
                } else {
                    return Err(())  // "@import must be before any rule but @charset"
                }
            },
            "namespace" => {
                if self.state.get() <= State::Namespaces {
                    self.state.set(State::Namespaces);

                    let prefix = input.try(|input| input.expect_ident()).ok().map(|p| p.into_owned());
                    let url = Namespace(Atom::from_slice(&*try!(input.expect_url_or_string())));
                    return Ok(AtRuleType::WithoutBlock(CSSRule::Namespace(prefix, url)))
                } else {
                    return Err(())  // "@namespace must be before any rule but @charset and @import"
                }
            }
            _ => {}
        }

        self.state.set(State::Body);
        AtRuleParser::parse_prelude(&NestedRuleParser { context: &self.context }, name, input)
    }

    #[inline]
    fn parse_block(&self, prelude: AtRulePrelude, input: &mut Parser) -> Result<CSSRule, ()> {
        AtRuleParser::parse_block(&NestedRuleParser { context: &self.context }, prelude, input)
    }
}

impl<'a> QualifiedRuleParser for TopLevelRuleParser<'a> {
    type Prelude = Vec<Selector>;
    type QualifiedRule = CSSRule;

    #[inline]
    fn parse_prelude(&self, input: &mut Parser) -> Result<Vec<Selector>, ()> {
        self.state.set(State::Body);
        QualifiedRuleParser::parse_prelude(&NestedRuleParser { context: &self.context }, input)
    }

    #[inline]
    fn parse_block(&self, prelude: Vec<Selector>, input: &mut Parser) -> Result<CSSRule, ()> {
        QualifiedRuleParser::parse_block(&NestedRuleParser { context: &self.context },
                                         prelude, input)
    }
}

struct NestedRuleParser<'a, 'b: 'a> {
    context: &'a ParserContext<'b>,
}

impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
    type Prelude = AtRulePrelude;
    type AtRule = CSSRule;

    fn parse_prelude(&self, name: &str, input: &mut Parser)
                     -> Result<AtRuleType<AtRulePrelude, CSSRule>, ()> {
        match_ignore_ascii_case! { name,
            "media" => {
                let media_queries = parse_media_query_list(input);
                Ok(AtRuleType::WithBlock(AtRulePrelude::Media(media_queries)))
            },
            "font-face" => {
                Ok(AtRuleType::WithBlock(AtRulePrelude::FontFace))
            },
            "viewport" => {
                if ::util::prefs::get_pref("layout.viewport.enabled", false) {
                    Ok(AtRuleType::WithBlock(AtRulePrelude::Viewport))
                } else {
                    Err(())
                }
            }
            _ => Err(())
        }
    }

    fn parse_block(&self, prelude: AtRulePrelude, input: &mut Parser) -> Result<CSSRule, ()> {
        match prelude {
            AtRulePrelude::FontFace => {
                parse_font_face_block(self.context, input).map(CSSRule::FontFace)
            }
            AtRulePrelude::Media(media_queries) => {
                Ok(CSSRule::Media(MediaRule {
                    media_queries: media_queries,
                    rules: parse_nested_rules(self.context, input),
                }))
            }
            AtRulePrelude::Viewport => {
                ViewportRule::parse(input, self.context).map(CSSRule::Viewport)
            }
        }
    }
}

impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> {
    type Prelude = Vec<Selector>;
    type QualifiedRule = CSSRule;

    fn parse_prelude(&self, input: &mut Parser) -> Result<Vec<Selector>, ()> {
        parse_selector_list(&self.context.selector_context, input)
    }

    fn parse_block(&self, prelude: Vec<Selector>, input: &mut Parser) -> Result<CSSRule, ()> {
        Ok(CSSRule::Style(StyleRule {
            selectors: prelude,
            declarations: parse_property_declaration_list(self.context, input)
        }))
    }
}
<commit_msg>Various fixes in stylesheets<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 std::ascii::AsciiExt;
use std::cell::Cell;
use std::iter::Iterator;
use std::slice;
use url::Url;

use encoding::EncodingRef;

use cssparser::{Parser, decode_stylesheet_bytes, QualifiedRuleParser, AtRuleParser};
use cssparser::{RuleListParser, AtRuleType};
use font_face::{FontFaceRule, parse_font_face_block};
use media_queries::{Device, MediaQueryList, parse_media_query_list};
use parser::{ParserContext, log_css_error};
use properties::{PropertyDeclarationBlock, parse_property_declaration_list};
use selectors::parser::{Selector, parse_selector_list};
use smallvec::SmallVec;
use string_cache::{Atom, Namespace};
use viewport::ViewportRule;

/// Each style rule has an origin, which determines where it enters the cascade.
///
/// http://dev.w3.org/csswg/css-cascade/#cascading-origins
#[derive(Clone, PartialEq, Eq, Copy, Debug)]
pub enum Origin {
    /// http://dev.w3.org/csswg/css-cascade/#cascade-origin-ua
    UserAgent,

    /// http://dev.w3.org/csswg/css-cascade/#cascade-origin-author
    Author,

    /// http://dev.w3.org/csswg/css-cascade/#cascade-origin-user
    User,
}

#[derive(Debug, PartialEq)]
pub struct Stylesheet {
    /// List of rules in the order they were found (important for
    /// cascading order)
    pub rules: Vec<CSSRule>,
    pub origin: Origin,
}

#[derive(Debug, PartialEq)]
pub enum CSSRule {
    Charset(String),
    Namespace(Option<String>, Namespace),
    Style(StyleRule),
    Media(MediaRule),
    FontFace(FontFaceRule),
    Viewport(ViewportRule),
}

#[derive(Debug, PartialEq)]
pub struct MediaRule {
    pub media_queries: MediaQueryList,
    pub rules: Vec<CSSRule>,
}

impl MediaRule {
    #[inline]
    pub fn evaluate(&self, device: &Device) -> bool {
        self.media_queries.evaluate(device)
    }
}

#[derive(Debug, PartialEq)]
pub struct StyleRule {
    pub selectors: Vec<Selector>,
    pub declarations: PropertyDeclarationBlock,
}

impl Stylesheet {
    pub fn from_bytes_iter<I: Iterator<Item=Vec<u8>>>(
            input: I, base_url: Url, protocol_encoding_label: Option<&str>,
            environment_encoding: Option<EncodingRef>, origin: Origin) -> Stylesheet {
        let mut bytes = vec![];
        // TODO: incremental decoding and tokenization/parsing
        for chunk in input {
            bytes.push_all(&chunk)
        }
        Stylesheet::from_bytes(&bytes, base_url, protocol_encoding_label,
                               environment_encoding, origin)
    }

    pub fn from_bytes(bytes: &[u8],
                      base_url: Url,
                      protocol_encoding_label: Option<&str>,
                      environment_encoding: Option<EncodingRef>,
                      origin: Origin)
                      -> Stylesheet {
        // TODO: bytes.as_slice could be bytes.container_as_bytes()
        let (string, _) = decode_stylesheet_bytes(
            bytes, protocol_encoding_label, environment_encoding);
        Stylesheet::from_str(&string, base_url, origin)
    }

    pub fn from_str(css: &str, base_url: Url, origin: Origin) -> Stylesheet {
        let rule_parser = TopLevelRuleParser {
            context: ParserContext::new(origin, &base_url),
            state: Cell::new(State::Start),
        };
        let mut input = Parser::new(css);
        let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser);
        let mut rules = Vec::new();
        while let Some(result) = iter.next() {
            match result {
                Ok(rule) => {
                    if let CSSRule::Namespace(ref prefix, ref namespace) = rule {
                        if let Some(prefix) = prefix.as_ref() {
                            iter.parser.context.selector_context.namespace_prefixes.insert(
                                prefix.clone(), namespace.clone());
                        } else {
                            iter.parser.context.selector_context.default_namespace =
                                Some(namespace.clone());
                        }
                    }
                    rules.push(rule);
                }
                Err(range) => {
                    let pos = range.start;
                    let message = format!("Invalid rule: '{}'", iter.input.slice(range));
                    log_css_error(iter.input, pos, &*message);
                }
            }
        }
        Stylesheet {
            origin: origin,
            rules: rules,
        }
    }

    /// Return an iterator over all the rules within the style-sheet.
    #[inline]
    pub fn rules(&self) -> Rules {
        Rules::new(self.rules.iter(), None)
    }

    /// Return an iterator over the effective rules within the style-sheet, as
    /// according to the supplied `Device`.
    ///
    /// If a condition does not hold, its associated conditional group rule and
    /// nested rules will be skipped. Use `rules` if all rules need to be
    /// examined.
    #[inline]
    pub fn effective_rules<'a>(&'a self, device: &'a Device) -> Rules<'a> {
        Rules::new(self.rules.iter(), Some(device))
    }
}

/// `CSSRule` iterator.
///
/// The iteration order is pre-order. Specifically, this implies that a
/// conditional group rule will come before its nested rules.
pub struct Rules<'a> {
    // 2 because normal case is likely to be just one level of nesting (@media)
    stack: SmallVec<[slice::Iter<'a, CSSRule>; 2]>,
    device: Option<&'a Device>
}

impl<'a> Rules<'a> {
    fn new(iter: slice::Iter<'a, CSSRule>, device: Option<&'a Device>) -> Rules<'a> {
        let mut stack: SmallVec<[slice::Iter<'a, CSSRule>; 2]> = SmallVec::new();
        stack.push(iter);

        Rules { stack: stack, device: device }
    }
}

impl<'a> Iterator for Rules<'a> {
    type Item = &'a CSSRule;

    fn next(&mut self) -> Option<&'a CSSRule> {
        while !self.stack.is_empty() {
            let top = self.stack.len() - 1;
            while let Some(rule) = self.stack[top].next() {
                // handle conditional group rules
                match rule {
                    &CSSRule::Media(ref rule) => {
                        if let Some(device) = self.device {
                            if rule.evaluate(device) {
                                self.stack.push(rule.rules.iter());
                            } else {
                                continue
                            }
                        } else {
                            self.stack.push(rule.rules.iter());
                        }
                    }
                    _ => {}
                }

                return Some(rule)
            }

            self.stack.pop();
        }
        None
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        // TODO: track total number of rules in style-sheet for upper bound?
        (0, None)
    }
}

pub mod rule_filter {
    //! Specific `CSSRule` variant iterators.

    use std::marker::PhantomData;
    use super::super::font_face::FontFaceRule;
    use super::super::viewport::ViewportRule;
    use super::{CSSRule, MediaRule, StyleRule};

    macro_rules! rule_filter {
        ($variant:ident -> $value:ty) => {
            /// An iterator that only yields rules that are of the synonymous `CSSRule` variant.
            #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
            pub struct $variant<'a, I> {
                iter: I,
                _lifetime: PhantomData<&'a ()>
            }

            impl<'a, I> $variant<'a, I> where I: Iterator<Item=&'a CSSRule> {
                pub fn new(iter: I) -> $variant<'a, I> {
                    $variant {
                        iter: iter,
                        _lifetime: PhantomData
                    }
                }
            }

            impl<'a, I> Iterator for $variant<'a, I> where I: Iterator<Item=&'a CSSRule> {
                type Item = &'a $value;

                fn next(&mut self) -> Option<&'a $value> {
                    while let Some(rule) = self.iter.next() {
                        match *rule {
                            CSSRule::$variant(ref value) => return Some(value),
                            _ => continue
                        }
                    }
                    None
                }

                #[inline]
                fn size_hint(&self) -> (usize, Option<usize>) {
                    (0, self.iter.size_hint().1)
                }
            }
        }
    }

    rule_filter!(FontFace -> FontFaceRule);
    rule_filter!(Media -> MediaRule);
    rule_filter!(Style -> StyleRule);
    rule_filter!(Viewport -> ViewportRule);
}

/// Extension methods for `CSSRule` iterators.
pub trait CSSRuleIteratorExt<'a>: Iterator<Item=&'a CSSRule> + Sized {
    /// Yield only @font-face rules.
    fn font_face(self) -> rule_filter::FontFace<'a, Self>;

    /// Yield only @media rules.
    fn media(self) -> rule_filter::Media<'a, Self>;

    /// Yield only style rules.
    fn style(self) -> rule_filter::Style<'a, Self>;

    /// Yield only @viewport rules.
    fn viewport(self) -> rule_filter::Viewport<'a, Self>;
}

impl<'a, I> CSSRuleIteratorExt<'a> for I where I: Iterator<Item=&'a CSSRule> {
    #[inline]
    fn font_face(self) -> rule_filter::FontFace<'a, I> {
        rule_filter::FontFace::new(self)
    }

    #[inline]
    fn media(self) -> rule_filter::Media<'a, I> {
        rule_filter::Media::new(self)
    }

    #[inline]
    fn style(self) -> rule_filter::Style<'a, I> {
        rule_filter::Style::new(self)
    }

    #[inline]
    fn viewport(self) -> rule_filter::Viewport<'a, I> {
        rule_filter::Viewport::new(self)
    }
}

fn parse_nested_rules(context: &ParserContext, input: &mut Parser) -> Vec<CSSRule> {
    let mut iter = RuleListParser::new_for_nested_rule(input, NestedRuleParser { context: context });
    let mut rules = Vec::new();
    while let Some(result) = iter.next() {
        match result {
            Ok(rule) => rules.push(rule),
            Err(range) => {
                let pos = range.start;
                let message = format!("Unsupported rule: '{}'", iter.input.slice(range));
                log_css_error(iter.input, pos, &*message);
            }
        }
    }
    rules
}

struct TopLevelRuleParser<'a> {
    context: ParserContext<'a>,
    state: Cell<State>,
}

#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
enum State {
    Start = 1,
    Imports = 2,
    Namespaces = 3,
    Body = 4,
}

enum AtRulePrelude {
    FontFace,
    Media(MediaQueryList),
    Viewport,
}

impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
    type Prelude = AtRulePrelude;
    type AtRule = CSSRule;

    fn parse_prelude(&self, name: &str, input: &mut Parser)
                     -> Result<AtRuleType<AtRulePrelude, CSSRule>, ()> {
        match_ignore_ascii_case! { name,
            "charset" => {
                if self.state.get() <= State::Start {
                    // Valid @charset rules are just ignored
                    self.state.set(State::Imports);
                    let charset = try!(input.expect_string()).into_owned();
                    return Ok(AtRuleType::WithoutBlock(CSSRule::Charset(charset)))
                } else {
                    return Err(())  // "@charset must be the first rule"
                }
            },
            "import" => {
                if self.state.get() <= State::Imports {
                    self.state.set(State::Imports);
                    // TODO: support @import
                    return Err(())  // "@import is not supported yet"
                } else {
                    return Err(())  // "@import must be before any rule but @charset"
                }
            },
            "namespace" => {
                if self.state.get() <= State::Namespaces {
                    self.state.set(State::Namespaces);

                    let prefix = input.try(|input| input.expect_ident()).ok().map(|p| p.into_owned());
                    let url = Namespace(Atom::from_slice(&*try!(input.expect_url_or_string())));
                    return Ok(AtRuleType::WithoutBlock(CSSRule::Namespace(prefix, url)))
                } else {
                    return Err(())  // "@namespace must be before any rule but @charset and @import"
                }
            }
            _ => {}
        }

        self.state.set(State::Body);
        AtRuleParser::parse_prelude(&NestedRuleParser { context: &self.context }, name, input)
    }

    #[inline]
    fn parse_block(&self, prelude: AtRulePrelude, input: &mut Parser) -> Result<CSSRule, ()> {
        AtRuleParser::parse_block(&NestedRuleParser { context: &self.context }, prelude, input)
    }
}

impl<'a> QualifiedRuleParser for TopLevelRuleParser<'a> {
    type Prelude = Vec<Selector>;
    type QualifiedRule = CSSRule;

    #[inline]
    fn parse_prelude(&self, input: &mut Parser) -> Result<Vec<Selector>, ()> {
        self.state.set(State::Body);
        QualifiedRuleParser::parse_prelude(&NestedRuleParser { context: &self.context }, input)
    }

    #[inline]
    fn parse_block(&self, prelude: Vec<Selector>, input: &mut Parser) -> Result<CSSRule, ()> {
        QualifiedRuleParser::parse_block(&NestedRuleParser { context: &self.context },
                                         prelude, input)
    }
}

struct NestedRuleParser<'a, 'b: 'a> {
    context: &'a ParserContext<'b>,
}

impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> {
    type Prelude = AtRulePrelude;
    type AtRule = CSSRule;

    fn parse_prelude(&self, name: &str, input: &mut Parser)
                     -> Result<AtRuleType<AtRulePrelude, CSSRule>, ()> {
        match_ignore_ascii_case! { name,
            "media" => {
                let media_queries = parse_media_query_list(input);
                Ok(AtRuleType::WithBlock(AtRulePrelude::Media(media_queries)))
            },
            "font-face" => {
                Ok(AtRuleType::WithBlock(AtRulePrelude::FontFace))
            },
            "viewport" => {
                if ::util::prefs::get_pref("layout.viewport.enabled", false) {
                    Ok(AtRuleType::WithBlock(AtRulePrelude::Viewport))
                } else {
                    Err(())
                }
            }
            _ => Err(())
        }
    }

    fn parse_block(&self, prelude: AtRulePrelude, input: &mut Parser) -> Result<CSSRule, ()> {
        match prelude {
            AtRulePrelude::FontFace => {
                parse_font_face_block(self.context, input).map(CSSRule::FontFace)
            }
            AtRulePrelude::Media(media_queries) => {
                Ok(CSSRule::Media(MediaRule {
                    media_queries: media_queries,
                    rules: parse_nested_rules(self.context, input),
                }))
            }
            AtRulePrelude::Viewport => {
                ViewportRule::parse(input, self.context).map(CSSRule::Viewport)
            }
        }
    }
}

impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> {
    type Prelude = Vec<Selector>;
    type QualifiedRule = CSSRule;

    fn parse_prelude(&self, input: &mut Parser) -> Result<Vec<Selector>, ()> {
        parse_selector_list(&self.context.selector_context, input)
    }

    fn parse_block(&self, prelude: Vec<Selector>, input: &mut Parser) -> Result<CSSRule, ()> {
        Ok(CSSRule::Style(StyleRule {
            selectors: prelude,
            declarations: parse_property_declaration_list(self.context, input)
        }))
    }
}
<|endoftext|>


<commit_before>use std::ops::{Index, IndexMut};

#[derive(Debug)]
pub struct SquareMatrix<T> {
    n: usize,
    data: Vec<T>
}

impl<T> Index<(usize, usize)> for SquareMatrix<T> {
    type Output = T;

    /// (row, col)
    #[inline(always)]
    fn index<'a>(&'a self, pos: (usize, usize)) -> &'a T {
        match pos {
            (row, col) => {
                let idx = row * self.n + col;
                &self.data[idx]
            }
        }
    }
}

impl<T> IndexMut<(usize, usize)> for SquareMatrix<T> {
    /// (row, col)
    #[inline(always)]
    fn index_mut<'a>(&'a mut self, pos: (usize, usize)) -> &'a mut T {
        match pos {
            (row, col) => {
                let idx = row * self.n + col;
                &mut self.data[idx]
            }
        }
    }
}

impl<T: Copy> SquareMatrix<T> {
    pub fn from_fn<F: Fn((usize,usize)) -> T>(n: usize, f: F) -> SquareMatrix<T> {
        let data = (0..n*n).map(|i| f((i/n, i%n))).collect();
        SquareMatrix::from_row_vec(n, data)
    }

    pub fn from_row_vec(n: usize, data: Vec<T>) -> SquareMatrix<T> {
        assert!(n > 0);
        assert!(data.len() == n*n);
        SquareMatrix {n: n, data: data}
    }
    #[inline(always)]
    pub fn n(&self) -> usize { self.n }
    pub fn into_vec(self) -> Vec<T> { self.data }

    #[inline(always)]
    pub fn map_row<F: Fn(T) -> T>(&mut self, row: usize, f: F) {
        for col in 0..self.n {
            let n = f(self[(row, col)]);
            self[(row, col)] = n;
        }
    }

    #[inline(always)]
    pub fn map_col<F: Fn(T) -> T>(&mut self, col: usize, f: F) {
        for row in 0..self.n {
            let n = f(self[(row, col)]);
            self[(row, col)] = n;
        }
    }

}
<commit_msg>Improve performance of map_row()<commit_after>use std::ops::{Index, IndexMut};

#[derive(Debug)]
pub struct SquareMatrix<T> {
    n: usize,
    data: Vec<T>
}

impl<T> Index<(usize, usize)> for SquareMatrix<T> {
    type Output = T;

    /// (row, col)
    #[inline(always)]
    fn index<'a>(&'a self, pos: (usize, usize)) -> &'a T {
        match pos {
            (row, col) => {
                let idx = row * self.n + col;
                &self.data[idx]
            }
        }
    }
}

impl<T> IndexMut<(usize, usize)> for SquareMatrix<T> {
    /// (row, col)
    #[inline(always)]
    fn index_mut<'a>(&'a mut self, pos: (usize, usize)) -> &'a mut T {
        match pos {
            (row, col) => {
                let idx = row * self.n + col;
                &mut self.data[idx]
            }
        }
    }
}

impl<T: Copy> SquareMatrix<T> {
    pub fn from_fn<F: Fn((usize,usize)) -> T>(n: usize, f: F) -> SquareMatrix<T> {
        let data = (0..n*n).map(|i| f((i/n, i%n))).collect();
        SquareMatrix::from_row_vec(n, data)
    }

    pub fn from_row_vec(n: usize, data: Vec<T>) -> SquareMatrix<T> {
        assert!(n > 0);
        assert!(data.len() == n*n);
        SquareMatrix {n: n, data: data}
    }
    #[inline(always)]
    pub fn n(&self) -> usize { self.n }
    pub fn into_vec(self) -> Vec<T> { self.data }

    #[inline(always)]
    pub fn map_row<F: Fn(T) -> T>(&mut self, row: usize, f: F) {
        assert!(row < self.n);

        let mut row_slice = &mut self.data[row*self.n .. (row+1)*self.n];
        debug_assert!(row_slice.len() == self.n);

        for elm in row_slice.iter_mut() {
            *elm = f(*elm);
        }
    }

    #[inline(always)]
    pub fn map_col<F: Fn(T) -> T>(&mut self, col: usize, f: F) {
        for row in 0..self.n {
            let n = f(self[(row, col)]);
            self[(row, col)] = n;
        }
    }

}
<|endoftext|>


<commit_before>use libc::c_void;

use std::ffi::CString;

use tree::{ParseOption, ParseResult, Encoding, ParseStatus, FormatOption};

use tree::NodeBase;

use wrapper::*;

pub enum CDocument {}

pub struct Document {
    ptr: *mut CDocument,
}

impl NodeBase for Document {
    fn get_ptr(&self) -> *mut c_void {
        self.ptr as *mut c_void
    }
}

impl Drop for Document {
    fn drop(&mut self) {
        unsafe {
            pugi_delete_document(self.ptr);
        }
    }
}

impl Document {
    fn new() -> Result<Self, ParseResult> {
        let document = unsafe { pugi_new_document() };
        if document.is_null() {
            Err(ParseResult::default())
        } else {
            Ok(Document { ptr: document })
        }
    }
}

#[derive(PartialEq)]
enum DataType {
    File,
    String,
    None,
}

pub struct DocumentBuilder {
    parse_options: Vec<ParseOption>,
    encoding: Encoding,
    data_type: DataType,
    data: String,
}

impl DocumentBuilder {
    pub fn new() -> DocumentBuilder {
        DocumentBuilder {
            parse_options: vec![],
            encoding: Encoding::Auto,
            data_type: DataType::None,
            data: String::new(),
        }
    }

    pub fn from_file(mut self, path: &str) -> DocumentBuilder {
        self.data_type = DataType::File;
        self.data = path.to_string();
        self
    }

    pub fn from_string(mut self, string: &str) -> DocumentBuilder {
        self.data_type = DataType::String;
        self.data = string.to_string();
        self
    }

    pub fn encoded_in(mut self, encoding: Encoding) -> DocumentBuilder {
        self.encoding = encoding;
        self
    }

    pub fn with_parse_option(mut self, parse_option: ParseOption) -> DocumentBuilder {
        self.parse_options.push(parse_option);
        self
    }

    pub fn finish(&self) -> Result<Document, ParseResult> {
        let combined_parse_options = if self.parse_options.is_empty() {
            ParseOption::Default
        } else {
            self.parse_options
                .iter()
                .fold(ParseOption::RawValue(0), |acc, x| acc | *x)
        };
        let c_data = CString::new(&self.data as &str).unwrap();

        let document = try!(Document::new());

        match self.data_type {
            DataType::File => {
                match ParseResult::new(unsafe {
                    pugi_load_file(document.ptr,
                                   c_data.as_ptr(),
                                   combined_parse_options.value(),
                                   self.encoding)
                }) {
                    Ok(result) => {
                        match result.status {
                            ParseStatus::Ok => Ok(document),
                            _ => Err(result),
                        }
                    }
                    _ => Err(ParseResult::default()),
                }
            }
            DataType::String => {
                match ParseResult::new(unsafe {
                    pugi_load_buffer(document.ptr,
                                     c_data.as_ptr(),
                                     self.data.len(),
                                     combined_parse_options.value(),
                                     self.encoding)
                }) {
                    Ok(result) => {
                        match result.status {
                            ParseStatus::Ok => Ok(document),
                            _ => Err(result),
                        }
                    }
                    _ => Err(ParseResult::default()),
                }
            }
            DataType::None => Document::new(),
        }
    }
}

    pub fn save_file(self, path: &str, indent_string: &str, format_options: Vec<FormatOption>,
                     encoding: Encoding)
        -> Result<Self, ()> {
        let combined_format_options = format_options.iter()
            .fold(FormatOption::RawValue(0), |acc, x| acc | *x);
        let c_path = CString::new(path).unwrap();
        let c_indent_string = CString::new(indent_string).unwrap();

        unsafe {
            match pugi_save_file(self.doc_ptr,
                                 c_path.as_ptr(),
                                 c_indent_string.as_ptr(),
                                 combined_format_options.value(),
                                 encoding) {
                1 => Ok(self),
                _ => Err(()),
            }
        }
    }
}
<commit_msg>Adding reset_with function to Document<commit_after>use libc::c_void;

use std::ffi::CString;

use tree::{ParseOption, ParseResult, Encoding, ParseStatus, FormatOption};

use tree::NodeBase;

use wrapper::*;

pub enum CDocument {}

pub struct Document {
    ptr: *mut CDocument,
}

impl NodeBase for Document {
    fn get_ptr(&self) -> *mut c_void {
        self.ptr as *mut c_void
    }
}

impl Drop for Document {
    fn drop(&mut self) {
        unsafe {
            pugi_delete_document(self.ptr);
        }
    }
}

impl Document {
    fn new() -> Result<Self, ParseResult> {
        let document = unsafe { pugi_new_document() };
        if document.is_null() {
            Err(ParseResult::default())
        } else {
            Ok(Document { ptr: document })
        }
    }
}

#[derive(PartialEq)]
enum DataType {
    File,
    String,
    None,
}

pub struct DocumentBuilder {
    parse_options: Vec<ParseOption>,
    encoding: Encoding,
    data_type: DataType,
    data: String,
}

impl DocumentBuilder {
    pub fn new() -> DocumentBuilder {
        DocumentBuilder {
            parse_options: vec![],
            encoding: Encoding::Auto,
            data_type: DataType::None,
            data: String::new(),
        }
    }

    pub fn from_file(mut self, path: &str) -> DocumentBuilder {
        self.data_type = DataType::File;
        self.data = path.to_string();
        self
    }

    pub fn from_string(mut self, string: &str) -> DocumentBuilder {
        self.data_type = DataType::String;
        self.data = string.to_string();
        self
    }

    pub fn encoded_in(mut self, encoding: Encoding) -> DocumentBuilder {
        self.encoding = encoding;
        self
    }

    pub fn with_parse_option(mut self, parse_option: ParseOption) -> DocumentBuilder {
        self.parse_options.push(parse_option);
        self
    }

    pub fn finish(&self) -> Result<Document, ParseResult> {
        let combined_parse_options = if self.parse_options.is_empty() {
            ParseOption::Default
        } else {
            self.parse_options
                .iter()
                .fold(ParseOption::RawValue(0), |acc, x| acc | *x)
        };
        let c_data = CString::new(&self.data as &str).unwrap();

        let document = try!(Document::new());

        match self.data_type {
            DataType::File => {
                match ParseResult::new(unsafe {
                    pugi_load_file(document.ptr,
                                   c_data.as_ptr(),
                                   combined_parse_options.value(),
                                   self.encoding)
                }) {
                    Ok(result) => {
                        match result.status {
                            ParseStatus::Ok => Ok(document),
                            _ => Err(result),
                        }
                    }
                    _ => Err(ParseResult::default()),
                }
            }
            DataType::String => {
                match ParseResult::new(unsafe {
                    pugi_load_buffer(document.ptr,
                                     c_data.as_ptr(),
                                     self.data.len(),
                                     combined_parse_options.value(),
                                     self.encoding)
                }) {
                    Ok(result) => {
                        match result.status {
                            ParseStatus::Ok => Ok(document),
                            _ => Err(result),
                        }
                    }
                    _ => Err(ParseResult::default()),
                }
            }
            DataType::None => Document::new(),
        }
    }
}

    pub fn save_file(self, path: &str, indent_string: &str, format_options: Vec<FormatOption>,
                     encoding: Encoding)
        -> Result<Self, ()> {
        let combined_format_options = format_options.iter()
            .fold(FormatOption::RawValue(0), |acc, x| acc | *x);
        let c_path = CString::new(path).unwrap();
        let c_indent_string = CString::new(indent_string).unwrap();
pub fn reset_with(document: Document, other: &Document) -> Result<Document, ()> {
    unsafe {
        pugi_reset_document_with(document.ptr, other.ptr);
    }
    Ok(document)
}

        unsafe {
            match pugi_save_file(self.doc_ptr,
                                 c_path.as_ptr(),
                                 c_indent_string.as_ptr(),
                                 combined_format_options.value(),
                                 encoding) {
                1 => Ok(self),
                _ => Err(()),
            }
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "uu_unlink"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Colin Warren <me@zv.ms>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: unlink (GNU coreutils) 8.21 */

extern crate getopts;
extern crate libc;

#[macro_use]
extern crate uucore;

use getopts::Options;
use libc::{S_IFLNK, S_IFMT, S_IFREG};
use libc::{c_char, lstat, stat, unlink};
use std::io::{Error, ErrorKind};
use std::mem::uninitialized;

static NAME: &'static str = "unlink";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();

    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "invalid options\n{}", f),
    };

    if matches.opt_present("help") {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {} [FILE]... [OPTION]...", NAME);
        println!("");
        println!("{}", opts.usage("Unlink the file at [FILE]."));
        return 0;
    }

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if matches.free.is_empty() {
        crash!(
            1,
            "missing operand\nTry '{0} --help' for more information.",
            NAME
        );
    } else if matches.free.len() > 1 {
        crash!(
            1,
            "extra operand: '{1}'\nTry '{0} --help' for more information.",
            NAME,
            matches.free[1]
        );
    }

    let st_mode = {
        let mut buf: stat = unsafe { uninitialized() };
        let result = unsafe {
            lstat(
                matches.free[0].as_ptr() as *const c_char,
                &mut buf as *mut stat,
            )
        };

        if result < 0 {
            crash!(
                1,
                "Cannot stat '{}': {}",
                matches.free[0],
                Error::last_os_error()
            );
        }

        buf.st_mode & S_IFMT
    };

    let result = if st_mode != S_IFREG && st_mode != S_IFLNK {
        Err(Error::new(
            ErrorKind::Other,
            "Not a regular file or symlink",
        ))
    } else {
        let result = unsafe { unlink(matches.free[0].as_ptr() as *const c_char) };

        if result < 0 {
            Err(Error::last_os_error())
        } else {
            Ok(())
        }
    };

    match result {
        Ok(_) => (),
        Err(e) => {
            crash!(1, "cannot unlink '{0}': {1}", matches.free[0], e);
        }
    }

    0
}
<commit_msg>unlink: Add a nul-terminator after the file name before calling lstat.<commit_after>#![crate_name = "uu_unlink"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Colin Warren <me@zv.ms>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: unlink (GNU coreutils) 8.21 */

extern crate getopts;
extern crate libc;

#[macro_use]
extern crate uucore;

use getopts::Options;
use libc::{S_IFLNK, S_IFMT, S_IFREG};
use libc::{c_char, lstat, stat, unlink};
use std::io::{Error, ErrorKind};
use std::mem::uninitialized;
use std::ffi::CString;

static NAME: &'static str = "unlink";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();

    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "invalid options\n{}", f),
    };

    if matches.opt_present("help") {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {} [FILE]... [OPTION]...", NAME);
        println!("");
        println!("{}", opts.usage("Unlink the file at [FILE]."));
        return 0;
    }

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if matches.free.is_empty() {
        crash!(
            1,
            "missing operand\nTry '{0} --help' for more information.",
            NAME
        );
    } else if matches.free.len() > 1 {
        crash!(
            1,
            "extra operand: '{1}'\nTry '{0} --help' for more information.",
            NAME,
            matches.free[1]
        );
    }

    let st_mode = {
        let mut buf: stat = unsafe { uninitialized() };
        let c_string = CString::new(matches.free[0].clone()).unwrap(); // unwrap() cannot fail, the string comes from argv so it cannot contain a \0.
        let result = unsafe {
            lstat(
                c_string.as_ptr(),
                &mut buf as *mut stat,
            )
        };

        if result < 0 {
            crash!(
                1,
                "Cannot stat '{}': {}",
                matches.free[0],
                Error::last_os_error()
            );
        }

        buf.st_mode & S_IFMT
    };

    let result = if st_mode != S_IFREG && st_mode != S_IFLNK {
        Err(Error::new(
            ErrorKind::Other,
            "Not a regular file or symlink",
        ))
    } else {
        let result = unsafe { unlink(matches.free[0].as_ptr() as *const c_char) };

        if result < 0 {
            Err(Error::last_os_error())
        } else {
            Ok(())
        }
    };

    match result {
        Ok(_) => (),
        Err(e) => {
            crash!(1, "cannot unlink '{0}': {1}", matches.free[0], e);
        }
    }

    0
}
<|endoftext|>


<commit_before>use std::fmt;
use core::slice::Items;
use collections::hashmap::{HashMap, HashSet, Entries};

pub static NS_XMLNS_PREFIX: &'static str = "xmlns";
pub static NS_XMLNS_URI: &'static str    = "http://www.w3.org/2000/xmlns/";
pub static NS_XML_PREFIX: &'static str   = "xml";
pub static NS_XML_URI: &'static str      = "http://www.w3.org/XML/1998/namespace";
pub static NS_EMPTY_URI: &'static str    = "";

/// Denotes something which contains namespace URI mappings.
///
/// A URI mapping is a pair of type `(&str, &str)`, where the first item
/// is namespace prefix (`None` meaning default prefix) and the second item
/// is a URI mapped to the prefix.
pub trait NamespaceIterable<'a, I: Iterator<(Option<&'a str>, &'a str)>> {
    fn uri_mappings(&'a self) -> I;
}

/// Namespace is a map from prefixes to namespace URIs.
///
/// `None` prefix means no prefix (i.e. default namespace).
#[deriving(Eq, Clone)]
pub struct Namespace(pub HashMap<Option<String>, String>);

impl Namespace {
    /// Returns an empty namespace.
    pub fn empty() -> Namespace { Namespace(HashMap::with_capacity(2)) }

    /// Puts a mapping into this namespace.
    ///
    /// This method does not override already existing mapping.
    ///
    /// Returns a boolean flag indicating whether the map already contained
    /// the given prefix.
    ///
    /// # Parameters
    /// * `prefix` --- namespace prefix (`None` means default namespace);
    /// * `uri`    --- namespace URI.
    ///
    /// # Return value
    /// `true` if `prefix` has been inserted successfully; `false` if the `prefix`
    /// was already present in the namespace.
    pub fn put(&mut self, prefix: Option<String>, uri: String) -> bool {
        match *self {
            Namespace(ref mut hm) => hm.insert(prefix, uri)
        }
    }

    /// Queries the namespace for the given prefix.
    ///
    /// # Parameters
    /// * `prefix` --- namespace prefix (`None` means default namespace).
    ///
    /// # Return value
    /// Namespace URI corresponding to the given prefix, if it is present.
    pub fn get<'a>(&'a self, prefix: &Option<String>) -> Option<&'a str> {
        match *self {
            Namespace(ref hm) => hm.find(prefix).map(|s| s.as_slice())
        }
    }
}

pub struct NamespaceMappings<'a> {
    entries: Entries<'a, Option<String>, String>
}

impl<'a> Iterator<(Option<&'a str>, &'a str)> for NamespaceMappings<'a> {
    fn next(&mut self) -> Option<(Option<&'a str>, &'a str)> {
        self.entries.next().map(|(prefix, uri)| {
            (prefix.as_ref().map(|p| p.as_slice()), uri.as_slice())
        })
    }
}

impl<'a> NamespaceIterable<'a, NamespaceMappings<'a>> for Namespace {
    fn uri_mappings(&'a self) -> NamespaceMappings<'a> {
        let Namespace(ref hm) = *self;
        NamespaceMappings { entries: hm.iter() }
    }
}

/// Namespace stack is a sequence of namespaces.
///
/// Namespace stack is used to represent cumulative namespace consisting of
/// combined namespaces from nested elements.
#[deriving(Clone, Eq)]
pub struct NamespaceStack(pub Vec<Namespace>);

impl NamespaceStack {
    /// Returns an empty namespace stack.
    #[inline]
    pub fn empty() -> NamespaceStack { NamespaceStack(Vec::with_capacity(2)) }

    /// Returns a namespace stack with default items in it.
    ///
    /// Default items are the following:
    ///
    /// * `xml` → `http://www.w3.org/XML/1998/namespace`;
    /// * `xmlns` → `http://www.w3.org/2000/xmlns/`.
    #[inline]
    pub fn default() -> NamespaceStack {
        let mut nst = NamespaceStack::empty();
        nst.push_empty();
        // xml namespace
        nst.put(Some(NS_XML_PREFIX.to_string()), NS_XML_URI.to_string());
        // xmlns namespace
        nst.put(Some(NS_XMLNS_PREFIX.to_string()), NS_XMLNS_URI.to_string());
        // empty namespace
        nst.put(None, NS_EMPTY_URI.to_string());
        nst
    }

    /// Adds an empty namespace to the top of this stack.
    #[inline]
    pub fn push_empty(&mut self) {
        let NamespaceStack(ref mut nst) = *self;
        nst.push(Namespace::empty());
    }

    /// Removes a namespace at the top of the stack.
    ///
    /// Fails if the stack is empty.
    #[inline]
    pub fn pop(&mut self) -> Namespace {
        let NamespaceStack(ref mut nst) = *self;
        nst.pop().unwrap()
    }

    /// Returns a namespace at the top of the stack, leaving the stack intact.
    ///
    /// Fails if the stack is empty.
    #[inline]
    pub fn peek<'a>(&'a mut self) -> &'a mut Namespace {
        let NamespaceStack(ref mut nst) = *self;
        nst.mut_last().unwrap()
    }

    /// Puts a mapping into the topmost namespace in this stack.
    ///
    /// This method does not override a mapping in the topmost namespace if it is
    /// already present, however, it does not depend on other namespaces in the stack,
    /// so it is possible to put a mapping which is present in lower namespaces.
    ///
    /// Returns a boolean flag indicating whether the topmost namespace
    /// already contained the given prefix.
    ///
    /// # Parameters
    /// * `prefix` --- namespace prefix (`None` means default namespace);
    /// * `uri`    --- namespace URI.
    ///
    /// # Return value
    /// `true` if `prefix` has been inserted successfully; `false` if the `prefix`
    /// was already present in the namespace.
    #[inline]
    pub fn put(&mut self, prefix: Option<String>, uri: String) -> bool {
        let NamespaceStack(ref mut nst) = *self;
        nst.mut_last().unwrap().put(prefix, uri)
    }

    /// Performs a search for the given prefix in the whole stack.
    ///
    /// This method walks the stack from top to bottom, querying each namespace
    /// in order for the given prefix. If none of the namespaces contains the prefix,
    /// `None` is returned.
    ///
    /// # Parameters
    /// * `prefix` --- namespace prefix (`None` means default namespace)
    #[inline]
    pub fn get<'a>(&'a self, prefix: &Option<String>) -> Option<&'a str> {
        let NamespaceStack(ref nst) = *self;
        for ns in nst.as_slice().iter().rev() {
            match ns.get(prefix) {
                None => {},
                r => return r,
            }
        }
        None
    }

    /// Combines this stack of namespaces into a single namespace.
    ///
    /// Namespaces are combined in left-to-right order, that is, rightmost namespace
    /// elements take priority over leftmost ones.
    pub fn squash(&self) -> Namespace {
        let NamespaceStack(ref nstack) = *self;
        let mut result = HashMap::new();
        for &Namespace(ref ns) in nstack.iter() {
            result.extend(ns.iter().map(|(k, v)| (k.clone(), v.to_string())));
        }
        Namespace(result)
    }
}

pub struct NamespaceStackMappings<'a> {
    namespaces: Items<'a, Namespace>,
    current_namespace: Option<NamespaceMappings<'a>>,
    used_keys: HashSet<Option<&'a str>>
}

impl<'a> NamespaceStackMappings<'a> {
    fn to_next_namespace(&mut self) -> bool {
        self.current_namespace = self.namespaces.next().map(|ns| ns.uri_mappings());
        self.current_namespace.is_some()
    }
}

impl<'a> Iterator<(Option<&'a str>, &'a str)> for NamespaceStackMappings<'a> {
    fn next(&mut self) -> Option<(Option<&'a str>, &'a str)> {
        // If there is no current namespace and no next namespace, we're finished
        if self.current_namespace.is_none() && !self.to_next_namespace() {
            return None;
        }
        let next_item = self.current_namespace.as_mut().unwrap().next();

        match next_item {
            // There is an element in the current namespace
            Some(mapping @ (k, _)) => if self.used_keys.contains(&k) {
                // If the current key is used, go to the next one
                self.next()
            } else {
                // Otherwise insert the current key to the set of used keys and
                // return the mapping
                self.used_keys.insert(k);
                Some(mapping)
            },
            // Current namespace is exhausted
            None => if self.to_next_namespace() {
                // If there is next namespace, continue from it
                self.next()
            } else {
                // No next namespace, exiting
                None
            }
        }
    }
}

impl<'a> NamespaceIterable<'a, NamespaceStackMappings<'a>> for NamespaceStack {
    fn uri_mappings(&'a self) -> NamespaceStackMappings<'a> {
        let NamespaceStack(ref nst) = *self;
        NamespaceStackMappings {
            namespaces: nst.iter(),
            current_namespace: None,
            used_keys: HashSet::new()
        }
    }
}
<commit_msg>Fixed invalid order in namespace iteration<commit_after>use std::fmt;
use std::iter::Rev;
use core::slice::Items;
use collections::hashmap::{HashMap, HashSet, Entries};

pub static NS_XMLNS_PREFIX: &'static str = "xmlns";
pub static NS_XMLNS_URI: &'static str    = "http://www.w3.org/2000/xmlns/";
pub static NS_XML_PREFIX: &'static str   = "xml";
pub static NS_XML_URI: &'static str      = "http://www.w3.org/XML/1998/namespace";
pub static NS_EMPTY_URI: &'static str    = "";

/// Denotes something which contains namespace URI mappings.
///
/// A URI mapping is a pair of type `(&str, &str)`, where the first item
/// is namespace prefix (`None` meaning default prefix) and the second item
/// is a URI mapped to the prefix.
pub trait NamespaceIterable<'a, I: Iterator<(Option<&'a str>, &'a str)>> {
    fn uri_mappings(&'a self) -> I;
}

/// Namespace is a map from prefixes to namespace URIs.
///
/// `None` prefix means no prefix (i.e. default namespace).
#[deriving(Eq, Clone)]
pub struct Namespace(pub HashMap<Option<String>, String>);

impl Namespace {
    /// Returns an empty namespace.
    pub fn empty() -> Namespace { Namespace(HashMap::with_capacity(2)) }

    /// Puts a mapping into this namespace.
    ///
    /// This method does not override already existing mapping.
    ///
    /// Returns a boolean flag indicating whether the map already contained
    /// the given prefix.
    ///
    /// # Parameters
    /// * `prefix` --- namespace prefix (`None` means default namespace);
    /// * `uri`    --- namespace URI.
    ///
    /// # Return value
    /// `true` if `prefix` has been inserted successfully; `false` if the `prefix`
    /// was already present in the namespace.
    pub fn put(&mut self, prefix: Option<String>, uri: String) -> bool {
        match *self {
            Namespace(ref mut hm) => hm.insert(prefix, uri)
        }
    }

    /// Queries the namespace for the given prefix.
    ///
    /// # Parameters
    /// * `prefix` --- namespace prefix (`None` means default namespace).
    ///
    /// # Return value
    /// Namespace URI corresponding to the given prefix, if it is present.
    pub fn get<'a>(&'a self, prefix: &Option<String>) -> Option<&'a str> {
        match *self {
            Namespace(ref hm) => hm.find(prefix).map(|s| s.as_slice())
        }
    }
}

pub struct NamespaceMappings<'a> {
    entries: Entries<'a, Option<String>, String>
}

impl<'a> Iterator<(Option<&'a str>, &'a str)> for NamespaceMappings<'a> {
    fn next(&mut self) -> Option<(Option<&'a str>, &'a str)> {
        self.entries.next().map(|(prefix, uri)| {
            (prefix.as_ref().map(|p| p.as_slice()), uri.as_slice())
        })
    }
}

impl<'a> NamespaceIterable<'a, NamespaceMappings<'a>> for Namespace {
    fn uri_mappings(&'a self) -> NamespaceMappings<'a> {
        let Namespace(ref hm) = *self;
        NamespaceMappings { entries: hm.iter() }
    }
}

/// Namespace stack is a sequence of namespaces.
///
/// Namespace stack is used to represent cumulative namespace consisting of
/// combined namespaces from nested elements.
#[deriving(Clone, Eq)]
pub struct NamespaceStack(pub Vec<Namespace>);

impl NamespaceStack {
    /// Returns an empty namespace stack.
    #[inline]
    pub fn empty() -> NamespaceStack { NamespaceStack(Vec::with_capacity(2)) }

    /// Returns a namespace stack with default items in it.
    ///
    /// Default items are the following:
    ///
    /// * `xml` → `http://www.w3.org/XML/1998/namespace`;
    /// * `xmlns` → `http://www.w3.org/2000/xmlns/`.
    #[inline]
    pub fn default() -> NamespaceStack {
        let mut nst = NamespaceStack::empty();
        nst.push_empty();
        // xml namespace
        nst.put(Some(NS_XML_PREFIX.to_string()), NS_XML_URI.to_string());
        // xmlns namespace
        nst.put(Some(NS_XMLNS_PREFIX.to_string()), NS_XMLNS_URI.to_string());
        // empty namespace
        nst.put(None, NS_EMPTY_URI.to_string());
        nst
    }

    /// Adds an empty namespace to the top of this stack.
    #[inline]
    pub fn push_empty(&mut self) {
        let NamespaceStack(ref mut nst) = *self;
        nst.push(Namespace::empty());
    }

    /// Removes a namespace at the top of the stack.
    ///
    /// Fails if the stack is empty.
    #[inline]
    pub fn pop(&mut self) -> Namespace {
        let NamespaceStack(ref mut nst) = *self;
        nst.pop().unwrap()
    }

    /// Returns a namespace at the top of the stack, leaving the stack intact.
    ///
    /// Fails if the stack is empty.
    #[inline]
    pub fn peek<'a>(&'a mut self) -> &'a mut Namespace {
        let NamespaceStack(ref mut nst) = *self;
        nst.mut_last().unwrap()
    }

    /// Puts a mapping into the topmost namespace in this stack.
    ///
    /// This method does not override a mapping in the topmost namespace if it is
    /// already present, however, it does not depend on other namespaces in the stack,
    /// so it is possible to put a mapping which is present in lower namespaces.
    ///
    /// Returns a boolean flag indicating whether the topmost namespace
    /// already contained the given prefix.
    ///
    /// # Parameters
    /// * `prefix` --- namespace prefix (`None` means default namespace);
    /// * `uri`    --- namespace URI.
    ///
    /// # Return value
    /// `true` if `prefix` has been inserted successfully; `false` if the `prefix`
    /// was already present in the namespace.
    #[inline]
    pub fn put(&mut self, prefix: Option<String>, uri: String) -> bool {
        let NamespaceStack(ref mut nst) = *self;
        nst.mut_last().unwrap().put(prefix, uri)
    }

    /// Performs a search for the given prefix in the whole stack.
    ///
    /// This method walks the stack from top to bottom, querying each namespace
    /// in order for the given prefix. If none of the namespaces contains the prefix,
    /// `None` is returned.
    ///
    /// # Parameters
    /// * `prefix` --- namespace prefix (`None` means default namespace)
    #[inline]
    pub fn get<'a>(&'a self, prefix: &Option<String>) -> Option<&'a str> {
        let NamespaceStack(ref nst) = *self;
        for ns in nst.iter().rev() {
            match ns.get(prefix) {
                None => {},
                r => return r,
            }
        }
        None
    }

    /// Combines this stack of namespaces into a single namespace.
    ///
    /// Namespaces are combined in left-to-right order, that is, rightmost namespace
    /// elements take priority over leftmost ones.
    pub fn squash(&self) -> Namespace {
        let NamespaceStack(ref nstack) = *self;
        let mut result = HashMap::new();
        for &Namespace(ref ns) in nstack.iter() {
            result.extend(ns.iter().map(|(k, v)| (k.clone(), v.to_string())));
        }
        Namespace(result)
    }
}

pub struct NamespaceStackMappings<'a> {
    namespaces: Rev<Items<'a, Namespace>>,
    current_namespace: Option<NamespaceMappings<'a>>,
    used_keys: HashSet<Option<&'a str>>
}

impl<'a> NamespaceStackMappings<'a> {
    fn to_next_namespace(&mut self) -> bool {
        self.current_namespace = self.namespaces.next().map(|ns| ns.uri_mappings());
        self.current_namespace.is_some()
    }
}

impl<'a> Iterator<(Option<&'a str>, &'a str)> for NamespaceStackMappings<'a> {
    fn next(&mut self) -> Option<(Option<&'a str>, &'a str)> {
        // If there is no current namespace and no next namespace, we're finished
        if self.current_namespace.is_none() && !self.to_next_namespace() {
            return None;
        }
        let next_item = self.current_namespace.as_mut().unwrap().next();

        match next_item {
            // There is an element in the current namespace
            Some(mapping @ (k, _)) => if self.used_keys.contains(&k) {
                // If the current key is used, go to the next one
                self.next()
            } else {
                // Otherwise insert the current key to the set of used keys and
                // return the mapping
                self.used_keys.insert(k);
                Some(mapping)
            },
            // Current namespace is exhausted
            None => if self.to_next_namespace() {
                // If there is next namespace, continue from it
                self.next()
            } else {
                // No next namespace, exiting
                None
            }
        }
    }
}

impl<'a> NamespaceIterable<'a, NamespaceStackMappings<'a>> for NamespaceStack {
    fn uri_mappings(&'a self) -> NamespaceStackMappings<'a> {
        let NamespaceStack(ref nst) = *self;
        NamespaceStackMappings {
            namespaces: nst.iter().rev(),
            current_namespace: None,
            used_keys: HashSet::new()
        }
    }
}
<|endoftext|>