<commit_before>use std::cmp::{max, min};

use cssparser::Parser;
use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{ElementResult, SetAttributes};
use crate::error::*;
use crate::node::Node;
use crate::parsers::{NonNegative, NumberOptionalNumber, Parse, ParseValue};
use crate::properties::ColorInterpolationFilters;
use crate::rect::IRect;
use crate::session::Session;
use crate::surface_utils::{
    iterators::{PixelRectangle, Pixels},
    shared_surface::ExclusiveImageSurface,
    EdgeMode, ImageSurfaceDataExt, Pixel,
};
use crate::xml::Attributes;

use super::bounds::BoundsBuilder;
use super::context::{FilterContext, FilterOutput};
use super::{
    FilterEffect, FilterError, FilterResolveError, Input, Primitive, PrimitiveParams,
    ResolvedPrimitive,
};

/// Enumeration of the possible morphology operations.
#[derive(Clone)]
enum Operator {
    Erode,
    Dilate,
}

enum_default!(Operator, Operator::Erode);

/// The `feMorphology` filter primitive.
#[derive(Default)]
pub struct FeMorphology {
    base: Primitive,
    params: Morphology,
}

/// Resolved `feMorphology` primitive for rendering.
#[derive(Clone, Default)]
pub struct Morphology {
    in1: Input,
    operator: Operator,
    radius: (f64, f64),
}

impl SetAttributes for FeMorphology {
    fn set_attributes(&mut self, attrs: &Attributes, session: &Session) -> ElementResult {
        self.params.in1 = self.base.parse_one_input(attrs, session);

        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "operator") => self.params.operator = attr.parse(value)?,
                expanded_name!("", "radius") => {
                    let NumberOptionalNumber(NonNegative(x), NonNegative(y)) = attr.parse(value)?;
                    self.params.radius = (x, y);
                }
                _ => (),
            }
        }

        Ok(())
    }
}

impl Morphology {
    pub fn render(
        &self,
        bounds_builder: BoundsBuilder,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterOutput, FilterError> {
        // Although https://www.w3.org/TR/filter-effects/#propdef-color-interpolation-filters does not mention
        // feMorphology as being one of the primitives that does *not* use that property,
        // the SVG1.1 test for filters-morph-01-f.svg fails if we pass the value from the ComputedValues here (that
        // document does not specify the color-interpolation-filters property, so it defaults to linearRGB).
        // So, we pass Auto, which will get resolved to SRGB, and that makes that test pass.
        //
        // I suppose erosion/dilation doesn't care about the color space of the source image?

        let input_1 = ctx.get_input(
            acquired_nodes,
            draw_ctx,
            &self.in1,
            ColorInterpolationFilters::Auto,
        )?;
        let bounds: IRect = bounds_builder
            .add_input(&input_1)
            .compute(ctx)
            .clipped
            .into();

        let (rx, ry) = self.radius;

        if rx <= 0.0 && ry <= 0.0 {
            return Ok(FilterOutput {
                surface: input_1.surface().clone(),
                bounds,
            });
        }

        let (rx, ry) = ctx.paffine().transform_distance(rx, ry);

        // The radii can become negative here due to the transform.
        // Additionally The radii being excessively large causes cpu hangups
        let (rx, ry) = (rx.abs().min(10.0), ry.abs().min(10.0));

        let mut surface = ExclusiveImageSurface::new(
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
            input_1.surface().surface_type(),
        )?;

        surface.modify(&mut |data, stride| {
            for (x, y, _pixel) in Pixels::within(input_1.surface(), bounds) {
                // Compute the kernel rectangle bounds.
                let kernel_bounds = IRect::new(
                    (f64::from(x) - rx).floor() as i32,
                    (f64::from(y) - ry).floor() as i32,
                    (f64::from(x) + rx).ceil() as i32 + 1,
                    (f64::from(y) + ry).ceil() as i32 + 1,
                );

                // Compute the new pixel values.
                let initial = match self.operator {
                    Operator::Erode => u8::max_value(),
                    Operator::Dilate => u8::min_value(),
                };

                let mut output_pixel = Pixel {
                    r: initial,
                    g: initial,
                    b: initial,
                    a: initial,
                };

                for (_x, _y, pixel) in
                    PixelRectangle::within(input_1.surface(), bounds, kernel_bounds, EdgeMode::None)
                {
                    let op = match self.operator {
                        Operator::Erode => min,
                        Operator::Dilate => max,
                    };

                    output_pixel.r = op(output_pixel.r, pixel.r);
                    output_pixel.g = op(output_pixel.g, pixel.g);
                    output_pixel.b = op(output_pixel.b, pixel.b);
                    output_pixel.a = op(output_pixel.a, pixel.a);
                }

                data.set_pixel(stride, output_pixel, x, y);
            }
        });

        Ok(FilterOutput {
            surface: surface.share()?,
            bounds,
        })
    }
}

impl FilterEffect for FeMorphology {
    fn resolve(
        &self,
        _acquired_nodes: &mut AcquiredNodes<'_>,
        _node: &Node,
    ) -> Result<ResolvedPrimitive, FilterResolveError> {
        Ok(ResolvedPrimitive {
            primitive: self.base.clone(),
            params: PrimitiveParams::Morphology(self.params.clone()),
        })
    }
}

impl Parse for Operator {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        Ok(parse_identifiers!(
            parser,
            "erode" => Operator::Erode,
            "dilate" => Operator::Dilate,
        )?)
    }
}
<commit_msg>filters/morphology.rs: use set_attribute()<commit_after>use std::cmp::{max, min};

use cssparser::Parser;
use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{set_attribute, ElementResult, SetAttributes};
use crate::error::*;
use crate::node::Node;
use crate::parsers::{NumberOptionalNumber, Parse, ParseValue};
use crate::properties::ColorInterpolationFilters;
use crate::rect::IRect;
use crate::session::Session;
use crate::surface_utils::{
    iterators::{PixelRectangle, Pixels},
    shared_surface::ExclusiveImageSurface,
    EdgeMode, ImageSurfaceDataExt, Pixel,
};
use crate::xml::Attributes;

use super::bounds::BoundsBuilder;
use super::context::{FilterContext, FilterOutput};
use super::{
    FilterEffect, FilterError, FilterResolveError, Input, Primitive, PrimitiveParams,
    ResolvedPrimitive,
};

/// Enumeration of the possible morphology operations.
#[derive(Clone)]
enum Operator {
    Erode,
    Dilate,
}

enum_default!(Operator, Operator::Erode);

/// The `feMorphology` filter primitive.
#[derive(Default)]
pub struct FeMorphology {
    base: Primitive,
    params: Morphology,
}

/// Resolved `feMorphology` primitive for rendering.
#[derive(Clone)]
pub struct Morphology {
    in1: Input,
    operator: Operator,
    radius: NumberOptionalNumber<f64>,
}

// We need this because NumberOptionalNumber doesn't impl Default
impl Default for Morphology {
    fn default() -> Morphology {
        Morphology {
            in1: Default::default(),
            operator: Default::default(),
            radius: NumberOptionalNumber(0.0, 0.0),
        }
    }
}

impl SetAttributes for FeMorphology {
    fn set_attributes(&mut self, attrs: &Attributes, session: &Session) -> ElementResult {
        self.params.in1 = self.base.parse_one_input(attrs, session);

        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "operator") => {
                    set_attribute(&mut self.params.operator, attr.parse(value), session);
                }
                expanded_name!("", "radius") => {
                    set_attribute(&mut self.params.radius, attr.parse(value), session);
                }
                _ => (),
            }
        }

        Ok(())
    }
}

impl Morphology {
    pub fn render(
        &self,
        bounds_builder: BoundsBuilder,
        ctx: &FilterContext,
        acquired_nodes: &mut AcquiredNodes<'_>,
        draw_ctx: &mut DrawingCtx,
    ) -> Result<FilterOutput, FilterError> {
        // Although https://www.w3.org/TR/filter-effects/#propdef-color-interpolation-filters does not mention
        // feMorphology as being one of the primitives that does *not* use that property,
        // the SVG1.1 test for filters-morph-01-f.svg fails if we pass the value from the ComputedValues here (that
        // document does not specify the color-interpolation-filters property, so it defaults to linearRGB).
        // So, we pass Auto, which will get resolved to SRGB, and that makes that test pass.
        //
        // I suppose erosion/dilation doesn't care about the color space of the source image?

        let input_1 = ctx.get_input(
            acquired_nodes,
            draw_ctx,
            &self.in1,
            ColorInterpolationFilters::Auto,
        )?;
        let bounds: IRect = bounds_builder
            .add_input(&input_1)
            .compute(ctx)
            .clipped
            .into();

        let NumberOptionalNumber(rx, ry) = self.radius;

        if rx <= 0.0 && ry <= 0.0 {
            return Ok(FilterOutput {
                surface: input_1.surface().clone(),
                bounds,
            });
        }

        let (rx, ry) = ctx.paffine().transform_distance(rx, ry);

        // The radii can become negative here due to the transform.
        // Additionally The radii being excessively large causes cpu hangups
        let (rx, ry) = (rx.abs().min(10.0), ry.abs().min(10.0));

        let mut surface = ExclusiveImageSurface::new(
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
            input_1.surface().surface_type(),
        )?;

        surface.modify(&mut |data, stride| {
            for (x, y, _pixel) in Pixels::within(input_1.surface(), bounds) {
                // Compute the kernel rectangle bounds.
                let kernel_bounds = IRect::new(
                    (f64::from(x) - rx).floor() as i32,
                    (f64::from(y) - ry).floor() as i32,
                    (f64::from(x) + rx).ceil() as i32 + 1,
                    (f64::from(y) + ry).ceil() as i32 + 1,
                );

                // Compute the new pixel values.
                let initial = match self.operator {
                    Operator::Erode => u8::max_value(),
                    Operator::Dilate => u8::min_value(),
                };

                let mut output_pixel = Pixel {
                    r: initial,
                    g: initial,
                    b: initial,
                    a: initial,
                };

                for (_x, _y, pixel) in
                    PixelRectangle::within(input_1.surface(), bounds, kernel_bounds, EdgeMode::None)
                {
                    let op = match self.operator {
                        Operator::Erode => min,
                        Operator::Dilate => max,
                    };

                    output_pixel.r = op(output_pixel.r, pixel.r);
                    output_pixel.g = op(output_pixel.g, pixel.g);
                    output_pixel.b = op(output_pixel.b, pixel.b);
                    output_pixel.a = op(output_pixel.a, pixel.a);
                }

                data.set_pixel(stride, output_pixel, x, y);
            }
        });

        Ok(FilterOutput {
            surface: surface.share()?,
            bounds,
        })
    }
}

impl FilterEffect for FeMorphology {
    fn resolve(
        &self,
        _acquired_nodes: &mut AcquiredNodes<'_>,
        _node: &Node,
    ) -> Result<ResolvedPrimitive, FilterResolveError> {
        Ok(ResolvedPrimitive {
            primitive: self.base.clone(),
            params: PrimitiveParams::Morphology(self.params.clone()),
        })
    }
}

impl Parse for Operator {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        Ok(parse_identifiers!(
            parser,
            "erode" => Operator::Erode,
            "dilate" => Operator::Dilate,
        )?)
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::str;
use std::fmt::{Result};

static EMPTY : &'static str = "";
static NO_NAME : &'static str = "<none>";

// NOTE: Uncomment when https://github.com/mozilla/rust/issues/13703 is fixed.
// pub struct PreOrderNodes<'a, 'b> {
//   queue: Vec<&'a Node<'b>>
// }
//
// impl<'a, 'b> Iterator<&'a Node<'b>> for PreOrderNodes<'a, 'b> {
//   fn next( &mut self ) -> Option<&'a Node<'b>> {
//     match self.queue.pop() {
//       ex @ Some( node ) => {
//         match node.contents {
//           Children( ref x ) => {
//             for child in x.as_slice().rev_iter() {
//               self.queue.push( child )
//             }
//           }
//           _ => ()
//         };
//         ex
//       }
//       _ => None
//     }
//   }
// }

#[deriving(Show, Eq)]
pub enum NodeContents<'a> {
  /// A `&[u8]` byte slice this node matched in the parse input. Only leaf nodes
  /// have `Data` contents.
  Data( &'a [u8] ),

  /// Children of the node, if any. Only non-leaf nodes have `Children`
  /// contents.
  Children( Vec<Node<'a>> )
}

#[deriving(Eq)]
pub struct Node<'a> {
  /// The name of the node.
  pub name: &'static str,

  /// The (inclusive) start index of the range this node matches. It's the byte
  /// (NOT char) offset of the parse input.
  pub start: uint,

  /// The (exclusive) end index of the range this node matches. It's the byte
  /// (NOT char) offset of the parse input.
  pub end: uint,

  /// The contents of the node; this can be either children nodes or a matched
  /// `&[u8]` slice.
  pub contents: NodeContents<'a>
}

fn indent( formatter: &mut fmt::Formatter, indent_spaces: int )
    -> fmt::Result {
  for _ in range( 0, indent_spaces ) {
    try!( write!( formatter.buf, " " ) )
  }
  Ok(())
}

impl<'a> Node<'a> {
  fn format( &self, formatter: &mut fmt::Formatter, indent_spaces: int )
      -> fmt::Result {
    try!( indent( formatter, indent_spaces ) );
    try!( write!( formatter.buf,
                  "Node \\{name: {0}, start: {1}, end: {2}",
                  self.displayName(), self.start, self.end ) );

    match self.contents {
      Data( data ) => {
        match str::from_utf8( data ) {
          Some( string ) => {
            try!( writeln!( formatter.buf,
                            ", contents: \"{0}\" \\}",
                            string ) );
          }
          _ => {
            try!( writeln!( formatter.buf,
                            ", contents: \"{0}\" \\}",
                            data ) );
          }
        }
      }
      Children( ref children ) => {
        try!( writeln!( formatter.buf, " \\}" ) );
        for child in children.iter() {
          try!( child.format( formatter, indent_spaces + 1) )
        }
      }
    };

    Ok(())
  }

  /// The node name if set, or "<none>" if unset.
  pub fn displayName( &self ) -> &'static str {
    if !self.name.is_empty() {
      self.name
    } else {
      NO_NAME
    }
  }

  // TODO: rename this to withoutName?
  /// Creates a `Node` with an empty name.
  pub fn noName( start: uint, end: uint, contents: NodeContents<'a> )
      -> Node<'a> {
    Node { name: EMPTY, start: start, end: end, contents: contents }
  }

  // TODO: rename this to withChildren?
  /// Creates a `Node` with the provided `name` and makes it a parent of the
  /// provided `children`.
  pub fn newParent( name: &'static str, mut children: Vec<Node<'a>> )
      -> Node<'a> {
    // In case 'children' has only one node with an empty name, our new Node
    // will take the guts of the child with the new 'name'.
    if children.len() == 1 && children.get( 0 ).name.is_empty() {
      match children.pop() {
        Some( mut child ) => {
          child.name = name;
          return child;
        }
        _ => ()
      }
    }

    let start = if children.len() != 0 {
      children.get( 0 ).start
    } else {
      0
    };

    let end = match children.last() {
      Some( ref node ) => node.end,
      _ => 0
    };

    Node { name: name,
           start: start,
           end: end,
           contents: Children( children ) }
  }

  /// Traverses the tree rooted at the node with pre-order traversal. `visitor`
  /// is called on every node and traversal stops when `visitor` returns `false`.
  ///
  /// Normally this function would return an iterator instead of taking a
  /// visitor function, but a `rustc` bug is preventing that implementation.
  #[allow(dead_code)]
  pub fn preOrder( &self, visitor: |&Node| -> bool ) {
    fn inner( node: &Node, visitor: |&Node| -> bool ) -> bool {
      if !visitor( node ) {
        return false;
      }

      match node.contents {
        Children( ref x ) => {
          for node in x.iter() {
            if !inner( node, |x| visitor( x ) ) {
              return false;
            }
          }
        }
        _ => ()
      };

      return true;
    }
    inner( self, visitor );
  }

  // NOTE: Uncomment when https://github.com/mozilla/rust/issues/13703 is fixed.
  // pub fn preOrder<'b>( &'b self ) -> PreOrderNodes<'b, 'a> {
  //   PreOrderNodes { queue: vec!( self ) }
  // }

  #[allow(dead_code)]
  fn matchedData( &self ) -> Vec<u8> {
    match self.contents {
      Data( x ) => Vec::from_slice( x ),
      Children( _ ) => {
        // TODO: implement
        vec!()
      }
    }
  }

  // TODO: methods in_order/pre_order/post_order that yield
  // iterators for walking the node tree structure
}

impl<'a> fmt::Show for Node<'a> {
  fn fmt( &self, formatter: &mut fmt::Formatter ) -> fmt::Result {
    self.format( formatter, 0 )
  }
}

#[cfg(test)]
mod tests {
  use super::{Node, Data};

  fn nameOnly( name: &'static str ) -> Node {
    Node { name: name, start: 0, end: 0, contents: data!( "" ) }
  }

  fn testTree() -> Node {
    // Tree looks like the following:
    //        a
    //   b    c    d
    //  e f   g
    Node::newParent( "a", vec!(
        Node::newParent( "b", vec!( nameOnly( "e" ), nameOnly( "f" ) ) ),
        Node::newParent( "c", vec!( nameOnly( "g" ) ) ),
        nameOnly( "d" ) ) )
  }

  #[test]
  fn preOrder_FullIteration() {
    let root = testTree();
    let mut names : Vec<char> = vec!();
    root.preOrder( |ref x| {
      names.push( x.name.char_at( 0 ) );
      true
    });

    assert_eq!( names, vec!( 'a', 'b', 'e', 'f', 'c', 'g', 'd' ) )
  }

  #[test]
  fn preOrder_PartialIteration() {
    let root = testTree();
    let mut names : Vec<char> = vec!();
    root.preOrder( |ref x| {
      let ch =  x.name.char_at( 0 );
      names.push( ch );
      if ch == 'f' { false } else { true }
    });

    assert_eq!( names, vec!( 'a', 'b', 'e', 'f' ) )
  }
}
<commit_msg>Updated code to latest rustc<commit_after>use std::fmt;
use std::str;
use std::fmt::{Result};

static EMPTY : &'static str = "";
static NO_NAME : &'static str = "<none>";

// NOTE: Uncomment when https://github.com/mozilla/rust/issues/13703 is fixed.
// pub struct PreOrderNodes<'a, 'b> {
//   queue: Vec<&'a Node<'b>>
// }
//
// impl<'a, 'b> Iterator<&'a Node<'b>> for PreOrderNodes<'a, 'b> {
//   fn next( &mut self ) -> Option<&'a Node<'b>> {
//     match self.queue.pop() {
//       ex @ Some( node ) => {
//         match node.contents {
//           Children( ref x ) => {
//             for child in x.as_slice().rev_iter() {
//               self.queue.push( child )
//             }
//           }
//           _ => ()
//         };
//         ex
//       }
//       _ => None
//     }
//   }
// }

#[deriving(Show, Eq)]
pub enum NodeContents<'a> {
  /// A `&[u8]` byte slice this node matched in the parse input. Only leaf nodes
  /// have `Data` contents.
  Data( &'a [u8] ),

  /// Children of the node, if any. Only non-leaf nodes have `Children`
  /// contents.
  Children( Vec<Node<'a>> )
}

#[deriving(Eq)]
pub struct Node<'a> {
  /// The name of the node.
  pub name: &'static str,

  /// The (inclusive) start index of the range this node matches. It's the byte
  /// (NOT char) offset of the parse input.
  pub start: uint,

  /// The (exclusive) end index of the range this node matches. It's the byte
  /// (NOT char) offset of the parse input.
  pub end: uint,

  /// The contents of the node; this can be either children nodes or a matched
  /// `&[u8]` slice.
  pub contents: NodeContents<'a>
}

fn indent( formatter: &mut fmt::Formatter, indent_spaces: int )
    -> fmt::Result {
  for _ in range( 0, indent_spaces ) {
    try!( write!( formatter, " " ) )
  }
  Ok(())
}

impl<'a> Node<'a> {
  fn format( &self, formatter: &mut fmt::Formatter, indent_spaces: int )
      -> fmt::Result {
    try!( indent( formatter, indent_spaces ) );
    try!( write!( formatter,
                  "Node \\{name: {0}, start: {1}, end: {2}",
                  self.displayName(), self.start, self.end ) );

    match self.contents {
      Data( data ) => {
        match str::from_utf8( data ) {
          Some( string ) => {
            try!( writeln!( formatter,
                            ", contents: \"{0}\" \\}",
                            string ) );
          }
          _ => {
            try!( writeln!( formatter,
                            ", contents: \"{0}\" \\}",
                            data ) );
          }
        }
      }
      Children( ref children ) => {
        try!( writeln!( formatter, " \\}" ) );
        for child in children.iter() {
          try!( child.format( formatter, indent_spaces + 1) )
        }
      }
    };

    Ok(())
  }

  /// The node name if set, or "<none>" if unset.
  pub fn displayName( &self ) -> &'static str {
    if !self.name.is_empty() {
      self.name
    } else {
      NO_NAME
    }
  }

  // TODO: rename this to withoutName?
  /// Creates a `Node` with an empty name.
  pub fn noName( start: uint, end: uint, contents: NodeContents<'a> )
      -> Node<'a> {
    Node { name: EMPTY, start: start, end: end, contents: contents }
  }

  // TODO: rename this to withChildren?
  /// Creates a `Node` with the provided `name` and makes it a parent of the
  /// provided `children`.
  pub fn newParent( name: &'static str, mut children: Vec<Node<'a>> )
      -> Node<'a> {
    // In case 'children' has only one node with an empty name, our new Node
    // will take the guts of the child with the new 'name'.
    if children.len() == 1 && children.get( 0 ).name.is_empty() {
      match children.pop() {
        Some( mut child ) => {
          child.name = name;
          return child;
        }
        _ => ()
      }
    }

    let start = if children.len() != 0 {
      children.get( 0 ).start
    } else {
      0
    };

    let end = match children.last() {
      Some( ref node ) => node.end,
      _ => 0
    };

    Node { name: name,
           start: start,
           end: end,
           contents: Children( children ) }
  }

  /// Traverses the tree rooted at the node with pre-order traversal. `visitor`
  /// is called on every node and traversal stops when `visitor` returns `false`.
  ///
  /// Normally this function would return an iterator instead of taking a
  /// visitor function, but a `rustc` bug is preventing that implementation.
  #[allow(dead_code)]
  pub fn preOrder( &self, visitor: |&Node| -> bool ) {
    fn inner( node: &Node, visitor: |&Node| -> bool ) -> bool {
      if !visitor( node ) {
        return false;
      }

      match node.contents {
        Children( ref x ) => {
          for node in x.iter() {
            if !inner( node, |x| visitor( x ) ) {
              return false;
            }
          }
        }
        _ => ()
      };

      return true;
    }
    inner( self, visitor );
  }

  // NOTE: Uncomment when https://github.com/mozilla/rust/issues/13703 is fixed.
  // pub fn preOrder<'b>( &'b self ) -> PreOrderNodes<'b, 'a> {
  //   PreOrderNodes { queue: vec!( self ) }
  // }

  #[allow(dead_code)]
  fn matchedData( &self ) -> Vec<u8> {
    match self.contents {
      Data( x ) => Vec::from_slice( x ),
      Children( _ ) => {
        // TODO: implement
        vec!()
      }
    }
  }

  // TODO: methods in_order/pre_order/post_order that yield
  // iterators for walking the node tree structure
}

impl<'a> fmt::Show for Node<'a> {
  fn fmt( &self, formatter: &mut fmt::Formatter ) -> fmt::Result {
    self.format( formatter, 0 )
  }
}

#[cfg(test)]
mod tests {
  use super::{Node, Data};

  fn nameOnly( name: &'static str ) -> Node {
    Node { name: name, start: 0, end: 0, contents: data!( "" ) }
  }

  fn testTree() -> Node {
    // Tree looks like the following:
    //        a
    //   b    c    d
    //  e f   g
    Node::newParent( "a", vec!(
        Node::newParent( "b", vec!( nameOnly( "e" ), nameOnly( "f" ) ) ),
        Node::newParent( "c", vec!( nameOnly( "g" ) ) ),
        nameOnly( "d" ) ) )
  }

  #[test]
  fn preOrder_FullIteration() {
    let root = testTree();
    let mut names : Vec<char> = vec!();
    root.preOrder( |ref x| {
      names.push( x.name.char_at( 0 ) );
      true
    });

    assert_eq!( names, vec!( 'a', 'b', 'e', 'f', 'c', 'g', 'd' ) )
  }

  #[test]
  fn preOrder_PartialIteration() {
    let root = testTree();
    let mut names : Vec<char> = vec!();
    root.preOrder( |ref x| {
      let ch =  x.name.char_at( 0 );
      names.push( ch );
      if ch == 'f' { false } else { true }
    });

    assert_eq!( names, vec!( 'a', 'b', 'e', 'f' ) )
  }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::str;
use std::fmt::{Result};

static EMPTY : &'static str = "";
static NO_NAME : &'static str = "<none>";

// NOTE: Uncomment when https://github.com/mozilla/rust/issues/13703 is fixed.
// pub struct PreOrderNodes<'a, 'b> {
//   queue: Vec<&'a Node<'b>>
// }
//
// impl<'a, 'b> Iterator<&'a Node<'b>> for PreOrderNodes<'a, 'b> {
//   fn next( &mut self ) -> Option<&'a Node<'b>> {
//     match self.queue.pop() {
//       ex @ Some( node ) => {
//         match node.contents {
//           Children( ref x ) => {
//             for child in x.as_slice().rev_iter() {
//               self.queue.push( child )
//             }
//           }
//           _ => ()
//         };
//         ex
//       }
//       _ => None
//     }
//   }
// }

#[deriving(Show, PartialEq)]
pub enum NodeContents<'a> {
  /// A `&[u8]` byte slice this node matched in the parse input. Only leaf nodes
  /// have `Data` contents.
  Data( &'a [u8] ),

  /// Children of the node, if any. Only non-leaf nodes have `Children`
  /// contents.
  Children( Vec<Node<'a>> )
}

#[deriving(PartialEq)]
pub struct Node<'a> {
  /// The name of the node.
  pub name: &'static str,

  /// The (inclusive) start index of the range this node matches. It's the byte
  /// (NOT char) offset of the parse input.
  pub start: uint,

  /// The (exclusive) end index of the range this node matches. It's the byte
  /// (NOT char) offset of the parse input.
  pub end: uint,

  /// The contents of the node; this can be either children nodes or a matched
  /// `&[u8]` slice.
  pub contents: NodeContents<'a>
}

fn indent( formatter: &mut fmt::Formatter, indent_spaces: int )
    -> fmt::Result {
  for _ in range( 0, indent_spaces ) {
    try!( write!( formatter, " " ) )
  }
  Ok(())
}

impl<'a> Node<'a> {
  fn format( &self, formatter: &mut fmt::Formatter, indent_spaces: int )
      -> fmt::Result {
    try!( indent( formatter, indent_spaces ) );
    try!( write!( formatter,
                  "Node \\{name: {0}, start: {1}, end: {2}",
                  self.displayName(), self.start, self.end ) );

    match self.contents {
      Data( data ) => {
        match str::from_utf8( data ) {
          Some( string ) => {
            try!( writeln!( formatter,
                            ", contents: \"{0}\" \\}",
                            string ) );
          }
          _ => {
            try!( writeln!( formatter,
                            ", contents: \"{0}\" \\}",
                            data ) );
          }
        }
      }
      Children( ref children ) => {
        try!( writeln!( formatter, " \\}" ) );
        for child in children.iter() {
          try!( child.format( formatter, indent_spaces + 1) )
        }
      }
    };

    Ok(())
  }

  /// The node name if set, or "<none>" if unset.
  pub fn displayName( &self ) -> &'static str {
    if !self.name.is_empty() {
      self.name
    } else {
      NO_NAME
    }
  }

  // TODO: rename this to withoutName?
  /// Creates a `Node` with an empty name.
  pub fn noName( start: uint, end: uint, contents: NodeContents<'a> )
      -> Node<'a> {
    Node { name: EMPTY, start: start, end: end, contents: contents }
  }

  // TODO: rename this to withChildren?
  /// Creates a `Node` with the provided `name` and makes it a parent of the
  /// provided `children`.
  pub fn newParent( name: &'static str, mut children: Vec<Node<'a>> )
      -> Node<'a> {
    // In case 'children' has only one node with an empty name, our new Node
    // will take the guts of the child with the new 'name'.
    if children.len() == 1 && children.get( 0 ).name.is_empty() {
      match children.pop() {
        Some( mut child ) => {
          child.name = name;
          return child;
        }
        _ => ()
      }
    }

    let start = if children.len() != 0 {
      children.get( 0 ).start
    } else {
      0
    };

    let end = match children.last() {
      Some( ref node ) => node.end,
      _ => 0
    };

    Node { name: name,
           start: start,
           end: end,
           contents: Children( children ) }
  }

  /// Traverses the tree rooted at the node with pre-order traversal. `visitor`
  /// is called on every node and traversal stops when `visitor` returns `false`.
  ///
  /// Normally this function would return an iterator instead of taking a
  /// visitor function, but a `rustc` bug is preventing that implementation.
  #[allow(dead_code)]
  pub fn preOrder( &self, visitor: |&Node| -> bool ) {
    fn inner( node: &Node, visitor: |&Node| -> bool ) -> bool {
      if !visitor( node ) {
        return false;
      }

      match node.contents {
        Children( ref x ) => {
          for node in x.iter() {
            if !inner( node, |x| visitor( x ) ) {
              return false;
            }
          }
        }
        _ => ()
      };

      return true;
    }
    inner( self, visitor );
  }

  // NOTE: Uncomment when https://github.com/mozilla/rust/issues/13703 is fixed.
  // pub fn preOrder<'b>( &'b self ) -> PreOrderNodes<'b, 'a> {
  //   PreOrderNodes { queue: vec!( self ) }
  // }

  #[allow(dead_code)]
  fn matchedData( &self ) -> Vec<u8> {
    match self.contents {
      Data( x ) => Vec::from_slice( x ),
      Children( _ ) => {
        // TODO: implement
        vec!()
      }
    }
  }

  // TODO: methods in_order/pre_order/post_order that yield
  // iterators for walking the node tree structure
}

impl<'a> fmt::Show for Node<'a> {
  fn fmt( &self, formatter: &mut fmt::Formatter ) -> fmt::Result {
    self.format( formatter, 0 )
  }
}

#[cfg(test)]
mod tests {
  use super::{Node, Data};

  fn nameOnly( name: &'static str ) -> Node {
    Node { name: name, start: 0, end: 0, contents: data!( "" ) }
  }

  fn testTree() -> Node {
    // Tree looks like the following:
    //        a
    //   b    c    d
    //  e f   g
    Node::newParent( "a", vec!(
        Node::newParent( "b", vec!( nameOnly( "e" ), nameOnly( "f" ) ) ),
        Node::newParent( "c", vec!( nameOnly( "g" ) ) ),
        nameOnly( "d" ) ) )
  }

  #[test]
  fn preOrder_FullIteration() {
    let root = testTree();
    let mut names : Vec<char> = vec!();
    root.preOrder( |ref x| {
      names.push( x.name.char_at( 0 ) );
      true
    });

    assert_eq!( names, vec!( 'a', 'b', 'e', 'f', 'c', 'g', 'd' ) )
  }

  #[test]
  fn preOrder_PartialIteration() {
    let root = testTree();
    let mut names : Vec<char> = vec!();
    root.preOrder( |ref x| {
      let ch =  x.name.char_at( 0 );
      names.push( ch );
      if ch == 'f' { false } else { true }
    });

    assert_eq!( names, vec!( 'a', 'b', 'e', 'f' ) )
  }
}
<commit_msg>Updated code-in-standby<commit_after>use std::fmt;
use std::str;
use std::fmt::{Result};

static EMPTY : &'static str = "";
static NO_NAME : &'static str = "<none>";

// NOTE: Uncomment when https://github.com/mozilla/rust/issues/13703 is fixed.
// pub struct PreOrderNodes<'a, 'b> {
//   queue: Vec<&'a Node<'b>>
// }
//
// impl<'a, 'b> Iterator<&'a Node<'b>> for PreOrderNodes<'a, 'b> {
//   fn next( &mut self ) -> Option<&'a Node<'b>> {
//     match self.queue.pop() {
//       ex @ Some( node ) => {
//         match node.contents {
//           Children( ref x ) => {
//             for child in x.as_slice().iter().rev() {
//               self.queue.push( child )
//             }
//           }
//           _ => ()
//         };
//         ex
//       }
//       _ => None
//     }
//   }
// }

#[deriving(Show, PartialEq)]
pub enum NodeContents<'a> {
  /// A `&[u8]` byte slice this node matched in the parse input. Only leaf nodes
  /// have `Data` contents.
  Data( &'a [u8] ),

  /// Children of the node, if any. Only non-leaf nodes have `Children`
  /// contents.
  Children( Vec<Node<'a>> )
}

#[deriving(PartialEq)]
pub struct Node<'a> {
  /// The name of the node.
  pub name: &'static str,

  /// The (inclusive) start index of the range this node matches. It's the byte
  /// (NOT char) offset of the parse input.
  pub start: uint,

  /// The (exclusive) end index of the range this node matches. It's the byte
  /// (NOT char) offset of the parse input.
  pub end: uint,

  /// The contents of the node; this can be either children nodes or a matched
  /// `&[u8]` slice.
  pub contents: NodeContents<'a>
}

fn indent( formatter: &mut fmt::Formatter, indent_spaces: int )
    -> fmt::Result {
  for _ in range( 0, indent_spaces ) {
    try!( write!( formatter, " " ) )
  }
  Ok(())
}

impl<'a> Node<'a> {
  fn format( &self, formatter: &mut fmt::Formatter, indent_spaces: int )
      -> fmt::Result {
    try!( indent( formatter, indent_spaces ) );
    try!( write!( formatter,
                  "Node \\{name: {0}, start: {1}, end: {2}",
                  self.displayName(), self.start, self.end ) );

    match self.contents {
      Data( data ) => {
        match str::from_utf8( data ) {
          Some( string ) => {
            try!( writeln!( formatter,
                            ", contents: \"{0}\" \\}",
                            string ) );
          }
          _ => {
            try!( writeln!( formatter,
                            ", contents: \"{0}\" \\}",
                            data ) );
          }
        }
      }
      Children( ref children ) => {
        try!( writeln!( formatter, " \\}" ) );
        for child in children.iter() {
          try!( child.format( formatter, indent_spaces + 1) )
        }
      }
    };

    Ok(())
  }

  /// The node name if set, or "<none>" if unset.
  pub fn displayName( &self ) -> &'static str {
    if !self.name.is_empty() {
      self.name
    } else {
      NO_NAME
    }
  }

  // TODO: rename this to withoutName?
  /// Creates a `Node` with an empty name.
  pub fn noName( start: uint, end: uint, contents: NodeContents<'a> )
      -> Node<'a> {
    Node { name: EMPTY, start: start, end: end, contents: contents }
  }

  // TODO: rename this to withChildren?
  /// Creates a `Node` with the provided `name` and makes it a parent of the
  /// provided `children`.
  pub fn newParent( name: &'static str, mut children: Vec<Node<'a>> )
      -> Node<'a> {
    // In case 'children' has only one node with an empty name, our new Node
    // will take the guts of the child with the new 'name'.
    if children.len() == 1 && children.get( 0 ).name.is_empty() {
      match children.pop() {
        Some( mut child ) => {
          child.name = name;
          return child;
        }
        _ => ()
      }
    }

    let start = if children.len() != 0 {
      children.get( 0 ).start
    } else {
      0
    };

    let end = match children.last() {
      Some( ref node ) => node.end,
      _ => 0
    };

    Node { name: name,
           start: start,
           end: end,
           contents: Children( children ) }
  }

  /// Traverses the tree rooted at the node with pre-order traversal. `visitor`
  /// is called on every node and traversal stops when `visitor` returns `false`.
  ///
  /// Normally this function would return an iterator instead of taking a
  /// visitor function, but a `rustc` bug is preventing that implementation.
  #[allow(dead_code)]
  pub fn preOrder( &self, visitor: |&Node| -> bool ) {
    fn inner( node: &Node, visitor: |&Node| -> bool ) -> bool {
      if !visitor( node ) {
        return false;
      }

      match node.contents {
        Children( ref x ) => {
          for node in x.iter() {
            if !inner( node, |x| visitor( x ) ) {
              return false;
            }
          }
        }
        _ => ()
      };

      return true;
    }
    inner( self, visitor );
  }

  // NOTE: Uncomment when https://github.com/mozilla/rust/issues/13703 is fixed.
  // pub fn preOrder<'b>( &'b self ) -> PreOrderNodes<'b, 'a> {
  //   PreOrderNodes { queue: vec!( self ) }
  // }

  #[allow(dead_code)]
  fn matchedData( &self ) -> Vec<u8> {
    match self.contents {
      Data( x ) => Vec::from_slice( x ),
      Children( _ ) => {
        // TODO: implement
        vec!()
      }
    }
  }

  // TODO: methods in_order/pre_order/post_order that yield
  // iterators for walking the node tree structure
}

impl<'a> fmt::Show for Node<'a> {
  fn fmt( &self, formatter: &mut fmt::Formatter ) -> fmt::Result {
    self.format( formatter, 0 )
  }
}

#[cfg(test)]
mod tests {
  use super::{Node, Data};

  fn nameOnly( name: &'static str ) -> Node {
    Node { name: name, start: 0, end: 0, contents: data!( "" ) }
  }

  fn testTree() -> Node {
    // Tree looks like the following:
    //        a
    //   b    c    d
    //  e f   g
    Node::newParent( "a", vec!(
        Node::newParent( "b", vec!( nameOnly( "e" ), nameOnly( "f" ) ) ),
        Node::newParent( "c", vec!( nameOnly( "g" ) ) ),
        nameOnly( "d" ) ) )
  }

  #[test]
  fn preOrder_FullIteration() {
    let root = testTree();
    let mut names : Vec<char> = vec!();
    root.preOrder( |ref x| {
      names.push( x.name.char_at( 0 ) );
      true
    });

    assert_eq!( names, vec!( 'a', 'b', 'e', 'f', 'c', 'g', 'd' ) )
  }

  #[test]
  fn preOrder_PartialIteration() {
    let root = testTree();
    let mut names : Vec<char> = vec!();
    root.preOrder( |ref x| {
      let ch =  x.name.char_at( 0 );
      names.push( ch );
      if ch == 'f' { false } else { true }
    });

    assert_eq!( names, vec!( 'a', 'b', 'e', 'f' ) )
  }
}
<|endoftext|>


<commit_before>//! A "souped up" echo server example.
//!
//! Very similar to the example at https://tokio.rs

#![feature(proc_macro, conservative_impl_trait, generators)]

extern crate futures_await as futures;
extern crate tokio_core;
extern crate tokio_io;

use std::io::{self, BufReader};

use futures::prelude::*;
use tokio_core::net::{TcpListener, TcpStream};
use tokio_core::reactor::Core;
use tokio_io::{AsyncRead};

fn main() {
    // Create the event loop that will drive this server
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    // Bind the server's socket
    let addr = "127.0.0.1:12345".parse().unwrap();
    let tcp = TcpListener::bind(&addr, &handle).expect("failed to bind listener");

    let server = async_block! {
        #[async]
        for (client, _) in tcp.incoming() {
            handle.spawn(handle_client(client).then(|result| {
                match result {
                    Ok(n) => println!("wrote {} bytes", n),
                    Err(e) => println!("IO error {:?}", e),
                }
                Ok(())
            }));
        }

        Ok::<(), io::Error>(())
    };
    core.run(server).unwrap();
}

#[async]
fn handle_client(socket: TcpStream) -> io::Result<u64> {
    let (reader, mut writer) = socket.split();
    let input = BufReader::new(reader);

    let mut total = 0;

    #[async]
    for line in tokio_io::io::lines(input) {
        println!("got client line: {}", line);
        total += line.len() as u64;
		writer = await!(tokio_io::io::write_all(writer, line))?.0;
    }

    Ok(total)
}
<commit_msg>Fix tabs<commit_after>//! A "souped up" echo server example.
//!
//! Very similar to the example at https://tokio.rs

#![feature(proc_macro, conservative_impl_trait, generators)]

extern crate futures_await as futures;
extern crate tokio_core;
extern crate tokio_io;

use std::io::{self, BufReader};

use futures::prelude::*;
use tokio_core::net::{TcpListener, TcpStream};
use tokio_core::reactor::Core;
use tokio_io::{AsyncRead};

fn main() {
    // Create the event loop that will drive this server
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    // Bind the server's socket
    let addr = "127.0.0.1:12345".parse().unwrap();
    let tcp = TcpListener::bind(&addr, &handle).expect("failed to bind listener");

    let server = async_block! {
        #[async]
        for (client, _) in tcp.incoming() {
            handle.spawn(handle_client(client).then(|result| {
                match result {
                    Ok(n) => println!("wrote {} bytes", n),
                    Err(e) => println!("IO error {:?}", e),
                }
                Ok(())
            }));
        }

        Ok::<(), io::Error>(())
    };
    core.run(server).unwrap();
}

#[async]
fn handle_client(socket: TcpStream) -> io::Result<u64> {
    let (reader, mut writer) = socket.split();
    let input = BufReader::new(reader);

    let mut total = 0;

    #[async]
    for line in tokio_io::io::lines(input) {
        println!("got client line: {}", line);
        total += line.len() as u64;
        writer = await!(tokio_io::io::write_all(writer, line))?.0;
    }

    Ok(total)
}
<|endoftext|>


<commit_before>use std::thread;
use std::sync::mpsc::channel;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Write;

extern crate rustc_serialize;
use rustc_serialize::json::Json;

extern crate time;
use time::Duration;

extern crate telemetry;
use telemetry::plain::*;
use telemetry::Flatten;

// A stopwatch for microsecond precision.
struct StopwatchUS {
    pub value: time::Duration
}
impl StopwatchUS {
    fn span<F>(f: F) -> StopwatchUS where F: FnOnce() {
        StopwatchUS {
            value: time::Duration::span(f)
        }
    }
}
impl telemetry::Flatten for StopwatchUS {
    fn as_u32(&self) -> u32 {
        match self.value.num_microseconds() {
            Some(x) if x >= std::u32::MAX as i64 => std::u32::MAX,
            Some(x) if x <= 0 => 0,
            Some(x) => x as u32,
            None => std::u32::MAX
        }
    }
}

struct Histograms {
    /// The duration of execution of a recursive implementation of
    /// Fibonacci's function, in microseconds.
    fibonacci_us: telemetry::plain::Linear<StopwatchUS>
}

fn fibonacci(i: u32) -> u32 {
    if i == 0 || i == 1 {
        1
    } else {
        fibonacci(i - 1) + fibonacci(i - 2)
    }
}

fn main() {
    let telemetry = telemetry::Service::new(true /* activate immediately */);

    let histograms = Histograms {
        fibonacci_us: telemetry::plain::Linear::new(
            &telemetry,
            "FIBONACCI_DURATION_US".to_string(),
            0 /* min */,
            1_000_000 /* max */,
            20 /* buckets */)
    };

    // Measure a number of durations.
    let mut handles = Vec::new();
    for _ in 1..10 {
        let hist = histograms.fibonacci_us.clone();
        handles.push(thread::spawn(move || {
            hist.record(StopwatchUS::span(|| {fibonacci(30);}));
        }));
    }

    for handle in handles {
        handle.join().unwrap();
    }

    // Now look at the histogram.
    let (sender, receiver) = channel();
    telemetry.to_json(telemetry::Subset::AllPlain, telemetry::SerializationFormat::SimpleJson, sender.clone());
    let plain = receiver.recv().unwrap();

    print!("{}\n", plain);

    // Assemble the histograms payload into a whole.
    // For this example, we are not attempting to match a specific protocol.
    let mut storage = BTreeMap::new();
    storage.insert("plain".to_string(), plain);

    // If we had keyed histograms, we should put them here, too.
    // Now, add metadata.
    storage.insert("application".to_string(), Json::String("telemetry example app".to_string()));
    storage.insert("version".to_string(), Json::Array(vec![Json::I64(0), Json::I64(1), Json::I64(0)]));

    print!("{}\n", Json::Object(storage.clone()).pretty());

    // Write to disk.
    let data = format!("{}\n", Json::Object(storage));
    let mut file = File::create("telemetry.json").unwrap();
    file.write_all(&data.into_bytes()).unwrap();
}
<commit_msg>A bit more doc on examples/main.rs<commit_after>//! A simple example demonstrating how to use Telemetry to measure and
//! store performance data, then eventually dump it to console/disk.

use std::thread;
use std::sync::mpsc::channel;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Write;

extern crate rustc_serialize;
use rustc_serialize::json::Json;

extern crate time;
use time::Duration;

extern crate telemetry;
use telemetry::plain::*;
use telemetry::Flatten;

// A stopwatch for microsecond precision.
struct StopwatchUS {
    pub value: time::Duration
}
impl StopwatchUS {
    fn span<F>(f: F) -> StopwatchUS where F: FnOnce() {
        StopwatchUS {
            value: time::Duration::span(f)
        }
    }
}
impl telemetry::Flatten for StopwatchUS {
    fn as_u32(&self) -> u32 {
        match self.value.num_microseconds() {
            Some(x) if x >= std::u32::MAX as i64 => std::u32::MAX,
            Some(x) if x <= 0 => 0,
            Some(x) => x as u32,
            None => std::u32::MAX
        }
    }
}

struct Histograms {
    /// The duration of execution of a recursive implementation of
    /// Fibonacci's function, in microseconds.
    fibonacci_us: telemetry::plain::Linear<StopwatchUS>
}

fn fibonacci(i: u32) -> u32 {
    if i == 0 || i == 1 {
        1
    } else {
        fibonacci(i - 1) + fibonacci(i - 2)
    }
}

fn main() {
    let telemetry = telemetry::Service::new(true /* activate immediately */);

    let histograms = Histograms {
        fibonacci_us: telemetry::plain::Linear::new(
            &telemetry,
            "FIBONACCI_DURATION_US".to_string(),
            0 /* min */,
            1_000_000 /* max */,
            20 /* buckets */)
    };

    // Measure a number of durations.
    let mut handles = Vec::new();
    for _ in 1..10 {
        let hist = histograms.fibonacci_us.clone();
        handles.push(thread::spawn(move || {
            hist.record(StopwatchUS::span(|| {fibonacci(30);}));
        }));
    }

    for handle in handles {
        handle.join().unwrap();
    }

    // Now look at the histogram.
    let (sender, receiver) = channel();
    telemetry.to_json(telemetry::Subset::AllPlain, telemetry::SerializationFormat::SimpleJson, sender.clone());
    let plain = receiver.recv().unwrap();

    print!("{}\n", plain);

    // Assemble the histograms payload into a whole.
    // For this example, we are not attempting to match a specific protocol.
    let mut storage = BTreeMap::new();
    storage.insert("plain".to_string(), plain);

    // If we had keyed histograms, we should put them here, too.
    // Now, add metadata.
    storage.insert("application".to_string(), Json::String("telemetry example app".to_string()));
    storage.insert("version".to_string(), Json::Array(vec![Json::I64(0), Json::I64(1), Json::I64(0)]));

    print!("{}\n", Json::Object(storage.clone()).pretty());

    // Write to disk.
    let data = format!("{}\n", Json::Object(storage));
    let mut file = File::create("telemetry.json").unwrap();
    file.write_all(&data.into_bytes()).unwrap();
}
<|endoftext|>


<commit_before>extern crate fall_tree;
extern crate file;
extern crate tempdir;

use std::process;
use std::env;
use std::path::{PathBuf, Path};

use tempdir::TempDir;

const OVERWRITE: bool = false;

fn generator_path() -> PathBuf {
    let test_exe = env::current_exe().unwrap();
    test_exe.parent().unwrap().parent().unwrap().join("gen")
}

fn check_by_path<T: AsRef<Path>>(grammar_path: T) {
    let grammar_path = grammar_path.as_ref();
    let generated_path = &grammar_path.with_extension("rs");
    let grammar_text = file::get_text(grammar_path).unwrap();

    let expected = file::get_text(generated_path).unwrap();

    let generated = {
        let dir = TempDir::new("gen-tests").unwrap();
        let tmp_file = dir.path().join("grammar.fall");
        file::put_text(&tmp_file, grammar_text).unwrap();

        let output = process::Command::new(generator_path())
            .arg(&tmp_file)
            .output()
            .expect("Failed to execute process");

        if !output.status.success() {
            panic!("Generator exited with code {:?}\n----\n{}\n----\n",
                   output.status.code(), std::str::from_utf8(&output.stderr).unwrap())
        }
        file::get_text(tmp_file.with_extension("rs")).unwrap()
    };

    if expected != generated {
        if OVERWRITE {
            println!("UPDATING {}", grammar_path.display());
            file::put_text(generated_path, generated)
                .unwrap_or_else(|_| panic!("Failed to write result to {}", generated_path.display()));
            return
        }
        let difference = fall_tree::test_util::compare_trees(&expected, &generated);
        println!("MISMATCH {}\n{}", grammar_path.display(), difference);
        panic!("Mismatch!")
    }
}

#[test]
fn test_grammars_are_fresh() {
    check_by_path("../fall_test/src/sexp.fall");
    check_by_path("../fall_test/src/weird.fall");
    check_by_path("../lang/rust/src/syntax.fall");
    check_by_path("../lang/json/src/syntax.fall");

    check_by_path("../lang/fall/src/syntax.fall")
}
<commit_msg>Minor<commit_after>extern crate fall_tree;
extern crate file;
extern crate tempdir;

use std::process;
use std::env;
use std::path::{PathBuf, Path};

use tempdir::TempDir;

fn should_rewrite() -> bool {
    ::std::env::var("rewrite").is_ok()
}

fn generator_path() -> PathBuf {
    let test_exe = env::current_exe().unwrap();
    test_exe.parent().unwrap().parent().unwrap().join("gen")
}

fn check_by_path<T: AsRef<Path>>(grammar_path: T) {
    let grammar_path = grammar_path.as_ref();
    let generated_path = &grammar_path.with_extension("rs");
    let grammar_text = file::get_text(grammar_path).unwrap();

    let expected = file::get_text(generated_path).unwrap();

    let generated = {
        let dir = TempDir::new("gen-tests").unwrap();
        let tmp_file = dir.path().join("grammar.fall");
        file::put_text(&tmp_file, grammar_text).unwrap();

        let output = process::Command::new(generator_path())
            .arg(&tmp_file)
            .output()
            .expect("Failed to execute process");

        if !output.status.success() {
            panic!("Generator exited with code {:?}\n----\n{}\n----\n",
                   output.status.code(), std::str::from_utf8(&output.stderr).unwrap())
        }
        file::get_text(tmp_file.with_extension("rs")).unwrap()
    };

    if expected != generated {
        if should_rewrite() {
            println!("UPDATING {}", grammar_path.display());
            file::put_text(generated_path, generated)
                .unwrap_or_else(|_| panic!("Failed to write result to {}", generated_path.display()));
            return
        }
        let difference = fall_tree::test_util::compare_trees(&expected, &generated);
        println!("MISMATCH {}\n{}", grammar_path.display(), difference);
        panic!("Mismatch!")
    }
}

#[test]
fn test_grammars_are_fresh() {
    check_by_path("../fall_test/src/sexp.fall");
    check_by_path("../fall_test/src/weird.fall");
    check_by_path("../lang/rust/src/syntax.fall");
    check_by_path("../lang/json/src/syntax.fall");

    check_by_path("../lang/fall/src/syntax.fall")
}
<|endoftext|>


<commit_before><commit_msg>Trait update<commit_after><|endoftext|>


<commit_before>#![allow(non_camel_case_types)]

use std::os::raw::*;
use std::ptr::null_mut;
use std::ops::Deref;

use pyffi;
use pyffi::{PyObject, PyTypeObject};
use cpython::{Python, PythonObject, ObjectProtocol, PyResult, PyModule};

use super::types::*;
use super::objects::*;

pub struct PyUFuncModule {
    numpy: PyModule,
    api: *const *const c_void,
}

impl Deref for PyUFuncModule {
    type Target = PyModule;
    fn deref(&self) -> &Self::Target {
        &self.numpy
    }
}

impl PyUFuncModule {
    pub fn import(py: Python) -> PyResult<Self> {
        let numpy = py.import("numpy.core.umath")?;
        let c_api = numpy.as_object().getattr(py, "_UFUNC_API")?;
        let api = unsafe {
            pyffi::PyCapsule_GetPointer(c_api.as_object().as_ptr(), null_mut()) as
            *const *const c_void
        };
        Ok(Self {
            numpy: numpy,
            api: api,
        })
    }

    pub unsafe fn get_pyufunc_type(&self) -> *mut PyTypeObject {
        *self.api as *mut PyTypeObject
    }
}

macro_rules! pyufunc_api {
    [ $offset:expr; $fname:ident ( $($arg:ident : $t:ty),* ) $( -> $ret:ty )* ] => {
impl PyUFuncModule {
#[allow(non_snake_case)]
pub unsafe fn $fname(&self, $($arg : $t), *) $( -> $ret )* {
    let fptr = self.api.offset($offset) as (*const extern fn ($($arg : $t), *) $( -> $ret )* );
    (*fptr)($($arg), *)
}
} // impl PyUFuncModule
}} // pyufunc_api!

pyufunc_api![1; PyUFunc_FromFuncAndData(func: *mut PyUFuncGenericFunction, data: *mut *mut c_void, types: *mut c_char, ntypes: c_int, nin: c_int, nout: c_int, identity: c_int, name: *const c_char, doc: *const c_char, unused: c_int) -> *mut PyObject];
pyufunc_api![2; PyUFunc_RegisterLoopForType(ufunc: *mut PyUFuncObject, usertype: c_int, function: PyUFuncGenericFunction, arg_types: *mut c_int, data: *mut c_void) -> c_int];
pyufunc_api![3; PyUFunc_GenericFunction(ufunc: *mut PyUFuncObject, args: *mut PyObject, kwds: *mut PyObject, op: *mut *mut PyArrayObject) -> c_int];
pyufunc_api![4; PyUFunc_f_f_As_d_d(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![5; PyUFunc_d_d(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![6; PyUFunc_f_f(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![7; PyUFunc_g_g(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![8; PyUFunc_F_F_As_D_D(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![9; PyUFunc_F_F(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![10; PyUFunc_D_D(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![11; PyUFunc_G_G(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![12; PyUFunc_O_O(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![13; PyUFunc_ff_f_As_dd_d(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![14; PyUFunc_ff_f(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![15; PyUFunc_dd_d(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![16; PyUFunc_gg_g(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![17; PyUFunc_FF_F_As_DD_D(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![18; PyUFunc_DD_D(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![19; PyUFunc_FF_F(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![20; PyUFunc_GG_G(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![21; PyUFunc_OO_O(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![22; PyUFunc_O_O_method(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![23; PyUFunc_OO_O_method(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![24; PyUFunc_On_Om(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![25; PyUFunc_GetPyValues(name: *mut c_char, bufsize: *mut c_int, errmask: *mut c_int, errobj: *mut *mut PyObject) -> c_int];
pyufunc_api![26; PyUFunc_checkfperr(errmask: c_int, errobj: *mut PyObject, first: *mut c_int) -> c_int];
pyufunc_api![27; PyUFunc_clearfperr()];
pyufunc_api![28; PyUFunc_getfperr() -> c_int];
pyufunc_api![29; PyUFunc_handlefperr(errmask: c_int, errobj: *mut PyObject, retstatus: c_int, first: *mut c_int) -> c_int];
pyufunc_api![30; PyUFunc_ReplaceLoopBySignature(func: *mut PyUFuncObject, newfunc: PyUFuncGenericFunction, signature: *mut c_int, oldfunc: *mut PyUFuncGenericFunction) -> c_int];
pyufunc_api![31; PyUFunc_FromFuncAndDataAndSignature(func: *mut PyUFuncGenericFunction, data: *mut *mut c_void, types: *mut c_char, ntypes: c_int, nin: c_int, nout: c_int, identity: c_int, name: *const c_char, doc: *const c_char, unused: c_int, signature: *const c_char) -> *mut PyObject];
pyufunc_api![32; PyUFunc_SetUsesArraysAsData(data: *mut *mut c_void, i: usize) -> c_int];
pyufunc_api![33; PyUFunc_e_e(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![34; PyUFunc_e_e_As_f_f(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![35; PyUFunc_e_e_As_d_d(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![36; PyUFunc_ee_e(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![37; PyUFunc_ee_e_As_ff_f(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![38; PyUFunc_ee_e_As_dd_d(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
pyufunc_api![39; PyUFunc_DefaultTypeResolver(ufunc: *mut PyUFuncObject, casting: NPY_CASTING, operands: *mut *mut PyArrayObject, type_tup: *mut PyObject, out_dtypes: *mut *mut PyArray_Descr) -> c_int];
pyufunc_api![40; PyUFunc_ValidateCasting(ufunc: *mut PyUFuncObject, casting: NPY_CASTING, operands: *mut *mut PyArrayObject, dtypes: *mut *mut PyArray_Descr) -> c_int];
pyufunc_api![41; PyUFunc_RegisterLoopForDescr(ufunc: *mut PyUFuncObject, user_dtype: *mut PyArray_Descr, function: PyUFuncGenericFunction, arg_dtypes: *mut *mut PyArray_Descr, data: *mut c_void) -> c_int];
<commit_msg>Add documents on UFunc API<commit_after>#![allow(non_camel_case_types)]

use std::os::raw::*;
use std::ptr::null_mut;
use std::ops::Deref;

use pyffi;
use pyffi::{PyObject, PyTypeObject};
use cpython::{Python, PythonObject, ObjectProtocol, PyResult, PyModule};

use super::types::*;
use super::objects::*;

/// UFunc API
/// https://docs.scipy.org/doc/numpy/reference/c-api.ufunc.html
///
/// Most of UFunc API is exposed as the related function of this module object.
pub struct PyUFuncModule {
    numpy: PyModule,
    api: *const *const c_void,
}

impl Deref for PyUFuncModule {
    type Target = PyModule;
    fn deref(&self) -> &Self::Target {
        &self.numpy
    }
}

/// Define UFunc API in PyUFuncModule
macro_rules! pyufunc_api {
    [ $offset:expr; $fname:ident ( $($arg:ident : $t:ty),* ) $( -> $ret:ty )* ] => {
#[allow(non_snake_case)]
pub unsafe fn $fname(&self, $($arg : $t), *) $( -> $ret )* {
    let fptr = self.api.offset($offset) as (*const extern fn ($($arg : $t), *) $( -> $ret )* );
    (*fptr)($($arg), *)
}
}} // pyufunc_api!

impl PyUFuncModule {
    /// Import `numpy.core.umath` to use UFunc API.
    pub fn import(py: Python) -> PyResult<Self> {
        let numpy = py.import("numpy.core.umath")?;
        let c_api = numpy.as_object().getattr(py, "_UFUNC_API")?;
        let api = unsafe {
            pyffi::PyCapsule_GetPointer(c_api.as_object().as_ptr(), null_mut()) as
            *const *const c_void
        };
        Ok(Self {
            numpy: numpy,
            api: api,
        })
    }

    pub unsafe fn get_pyufunc_type(&self) -> *mut PyTypeObject {
        *self.api as *mut PyTypeObject
    }

    pyufunc_api![1; PyUFunc_FromFuncAndData(func: *mut PyUFuncGenericFunction, data: *mut *mut c_void, types: *mut c_char, ntypes: c_int, nin: c_int, nout: c_int, identity: c_int, name: *const c_char, doc: *const c_char, unused: c_int) -> *mut PyObject];
    pyufunc_api![2; PyUFunc_RegisterLoopForType(ufunc: *mut PyUFuncObject, usertype: c_int, function: PyUFuncGenericFunction, arg_types: *mut c_int, data: *mut c_void) -> c_int];
    pyufunc_api![3; PyUFunc_GenericFunction(ufunc: *mut PyUFuncObject, args: *mut PyObject, kwds: *mut PyObject, op: *mut *mut PyArrayObject) -> c_int];
    pyufunc_api![4; PyUFunc_f_f_As_d_d(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![5; PyUFunc_d_d(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![6; PyUFunc_f_f(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![7; PyUFunc_g_g(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![8; PyUFunc_F_F_As_D_D(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![9; PyUFunc_F_F(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![10; PyUFunc_D_D(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![11; PyUFunc_G_G(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![12; PyUFunc_O_O(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![13; PyUFunc_ff_f_As_dd_d(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![14; PyUFunc_ff_f(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![15; PyUFunc_dd_d(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![16; PyUFunc_gg_g(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![17; PyUFunc_FF_F_As_DD_D(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![18; PyUFunc_DD_D(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![19; PyUFunc_FF_F(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![20; PyUFunc_GG_G(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![21; PyUFunc_OO_O(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![22; PyUFunc_O_O_method(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![23; PyUFunc_OO_O_method(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![24; PyUFunc_On_Om(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![25; PyUFunc_GetPyValues(name: *mut c_char, bufsize: *mut c_int, errmask: *mut c_int, errobj: *mut *mut PyObject) -> c_int];
    pyufunc_api![26; PyUFunc_checkfperr(errmask: c_int, errobj: *mut PyObject, first: *mut c_int) -> c_int];
    pyufunc_api![27; PyUFunc_clearfperr()];
    pyufunc_api![28; PyUFunc_getfperr() -> c_int];
    pyufunc_api![29; PyUFunc_handlefperr(errmask: c_int, errobj: *mut PyObject, retstatus: c_int, first: *mut c_int) -> c_int];
    pyufunc_api![30; PyUFunc_ReplaceLoopBySignature(func: *mut PyUFuncObject, newfunc: PyUFuncGenericFunction, signature: *mut c_int, oldfunc: *mut PyUFuncGenericFunction) -> c_int];
    pyufunc_api![31; PyUFunc_FromFuncAndDataAndSignature(func: *mut PyUFuncGenericFunction, data: *mut *mut c_void, types: *mut c_char, ntypes: c_int, nin: c_int, nout: c_int, identity: c_int, name: *const c_char, doc: *const c_char, unused: c_int, signature: *const c_char) -> *mut PyObject];
    pyufunc_api![32; PyUFunc_SetUsesArraysAsData(data: *mut *mut c_void, i: usize) -> c_int];
    pyufunc_api![33; PyUFunc_e_e(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![34; PyUFunc_e_e_As_f_f(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![35; PyUFunc_e_e_As_d_d(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![36; PyUFunc_ee_e(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![37; PyUFunc_ee_e_As_ff_f(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![38; PyUFunc_ee_e_As_dd_d(args: *mut *mut c_char, dimensions: *mut npy_intp, steps: *mut npy_intp, func: *mut c_void)];
    pyufunc_api![39; PyUFunc_DefaultTypeResolver(ufunc: *mut PyUFuncObject, casting: NPY_CASTING, operands: *mut *mut PyArrayObject, type_tup: *mut PyObject, out_dtypes: *mut *mut PyArray_Descr) -> c_int];
    pyufunc_api![40; PyUFunc_ValidateCasting(ufunc: *mut PyUFuncObject, casting: NPY_CASTING, operands: *mut *mut PyArrayObject, dtypes: *mut *mut PyArray_Descr) -> c_int];
    pyufunc_api![41; PyUFunc_RegisterLoopForDescr(ufunc: *mut PyUFuncObject, user_dtype: *mut PyArray_Descr, function: PyUFuncGenericFunction, arg_dtypes: *mut *mut PyArray_Descr, data: *mut c_void) -> c_int];
}
<|endoftext|>


<commit_before>//! SVG paint servers.

use cssparser::Parser;

use crate::bbox::BoundingBox;
use crate::document::{AcquiredNodes, NodeId};
use crate::drawing_ctx::DrawingCtx;
use crate::element::Element;
use crate::error::{
    AcquireError, ImplementationLimit, NodeIdError, ParseError, RenderingError, ValueErrorKind,
};
use crate::gradient::{ResolvedGradient, UserSpaceGradient};
use crate::node::NodeBorrow;
use crate::parsers::Parse;
use crate::pattern::{ResolvedPattern, UserSpacePattern};
use crate::properties::ComputedValues;
use crate::unit_interval::UnitInterval;
use crate::util;

#[derive(Debug, Clone, PartialEq)]
pub enum PaintServer {
    None,
    Iri {
        iri: Box<NodeId>,
        alternate: Option<cssparser::Color>,
    },
    SolidColor(cssparser::Color),
}

pub enum PaintSource {
    None,
    Gradient(ResolvedGradient, Option<cssparser::RGBA>),
    Pattern(ResolvedPattern, Option<cssparser::RGBA>),
    SolidColor(cssparser::RGBA),
}

pub enum UserSpacePaintSource {
    None,
    Gradient(UserSpaceGradient, Option<cssparser::RGBA>),
    Pattern(UserSpacePattern, Option<cssparser::RGBA>),
    SolidColor(cssparser::RGBA),
}

impl Parse for PaintServer {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<PaintServer, ParseError<'i>> {
        if parser
            .try_parse(|i| i.expect_ident_matching("none"))
            .is_ok()
        {
            Ok(PaintServer::None)
        } else if let Ok(url) = parser.try_parse(|i| i.expect_url()) {
            let loc = parser.current_source_location();

            let alternate = if !parser.is_exhausted() {
                if parser
                    .try_parse(|i| i.expect_ident_matching("none"))
                    .is_ok()
                {
                    None
                } else {
                    Some(parser.try_parse(|i| cssparser::Color::parse(i))?)
                }
            } else {
                None
            };

            Ok(PaintServer::Iri {
                iri: Box::new(
                    NodeId::parse(&url)
                        .map_err(|e: NodeIdError| -> ValueErrorKind { e.into() })
                        .map_err(|e| loc.new_custom_error(e))?,
                ),
                alternate,
            })
        } else {
            Ok(cssparser::Color::parse(parser).map(PaintServer::SolidColor)?)
        }
    }
}

impl PaintServer {
    pub fn resolve(
        &self,
        acquired_nodes: &mut AcquiredNodes<'_>,
        opacity: UnitInterval,
        current_color: cssparser::RGBA,
    ) -> Result<PaintSource, RenderingError> {
        match self {
            PaintServer::Iri {
                ref iri,
                ref alternate,
            } => acquired_nodes
                .acquire(iri)
                .and_then(|acquired| {
                    let node = acquired.get();
                    assert!(node.is_element());

                    match *node.borrow_element() {
                        Element::LinearGradient(ref g) => {
                            g.resolve(&node, acquired_nodes).map(|g| {
                                PaintSource::Gradient(
                                    g,
                                    alternate.map(|c| resolve_color(&c, opacity, current_color)),
                                )
                            })
                        }
                        Element::Pattern(ref p) => p.resolve(&node, acquired_nodes).map(|p| {
                            PaintSource::Pattern(
                                p,
                                alternate.map(|c| resolve_color(&c, opacity, current_color)),
                            )
                        }),
                        Element::RadialGradient(ref g) => {
                            g.resolve(&node, acquired_nodes).map(|g| {
                                PaintSource::Gradient(
                                    g,
                                    alternate.map(|c| resolve_color(&c, opacity, current_color)),
                                )
                            })
                        }
                        _ => Err(AcquireError::InvalidLinkType(iri.as_ref().clone())),
                    }
                })
                .or_else(|err| match (err, alternate) {
                    (AcquireError::MaxReferencesExceeded, _) => {
                        rsvg_log!("exceeded maximum number of referenced objects");
                        Err(RenderingError::LimitExceeded(
                            ImplementationLimit::TooManyReferencedElements,
                        ))
                    }

                    // The following two cases catch AcquireError::CircularReference, which for
                    // paint servers may mean that there is a pattern or gradient with a reference
                    // cycle in its "href" attribute.  This is an invalid paint server, and per
                    // https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint we should try to
                    // fall back to the alternate color.
                    (_, Some(color)) => {
                        rsvg_log!(
                            "could not resolve paint server \"{}\", using alternate color",
                            iri
                        );

                        Ok(PaintSource::SolidColor(resolve_color(
                            color,
                            opacity,
                            current_color,
                        )))
                    }

                    (_, _) => {
                        rsvg_log!(
                            "could not resolve paint server \"{}\", no alternate color specified",
                            iri
                        );

                        Ok(PaintSource::None)
                    }
                }),

            PaintServer::SolidColor(color) => Ok(PaintSource::SolidColor(resolve_color(
                color,
                opacity,
                current_color,
            ))),

            PaintServer::None => Ok(PaintSource::None),
        }
    }
}

impl PaintSource {
    pub fn to_user_space(
        &self,
        bbox: &BoundingBox,
        draw_ctx: &DrawingCtx,
        values: &ComputedValues,
    ) -> UserSpacePaintSource {
        match *self {
            PaintSource::None => UserSpacePaintSource::None,
            PaintSource::SolidColor(c) => UserSpacePaintSource::SolidColor(c),

            PaintSource::Gradient(ref g, c) => match (g.to_user_space(bbox, draw_ctx, values), c) {
                (Some(gradient), c) => UserSpacePaintSource::Gradient(gradient, c),
                (None, Some(c)) => UserSpacePaintSource::SolidColor(c),
                (None, None) => UserSpacePaintSource::None,
            },

            PaintSource::Pattern(ref p, c) => match (p.to_user_space(bbox, draw_ctx, values), c) {
                (Some(pattern), c) => UserSpacePaintSource::Pattern(pattern, c),
                (None, Some(c)) => UserSpacePaintSource::SolidColor(c),
                (None, None) => UserSpacePaintSource::None,
            },
        }
    }
}

pub fn resolve_color(
    color: &cssparser::Color,
    opacity: UnitInterval,
    current_color: cssparser::RGBA,
) -> cssparser::RGBA {
    let rgba = match *color {
        cssparser::Color::RGBA(rgba) => rgba,
        cssparser::Color::CurrentColor => current_color,
    };

    let UnitInterval(o) = opacity;

    let alpha = (f64::from(rgba.alpha) * o).round();
    let alpha = util::clamp(alpha, 0.0, 255.0);

    // For the following I'd prefer to use `cast::u8(alpha).unwrap()`
    // but the cast crate is erroneously returning Overflow for `u8(255.0)`:
    // https://github.com/japaric/cast.rs/issues/23

    let alpha = alpha as u8;

    cssparser::RGBA { alpha, ..rgba }
}

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

    #[test]
    fn catches_invalid_syntax() {
        assert!(PaintServer::parse_str("").is_err());
        assert!(PaintServer::parse_str("42").is_err());
        assert!(PaintServer::parse_str("invalid").is_err());
    }

    #[test]
    fn parses_none() {
        assert_eq!(PaintServer::parse_str("none").unwrap(), PaintServer::None);
    }

    #[test]
    fn parses_solid_color() {
        assert_eq!(
            PaintServer::parse_str("rgb(255, 128, 64, 0.5)").unwrap(),
            PaintServer::SolidColor(cssparser::Color::RGBA(cssparser::RGBA::new(
                255, 128, 64, 128
            )))
        );

        assert_eq!(
            PaintServer::parse_str("currentColor").unwrap(),
            PaintServer::SolidColor(cssparser::Color::CurrentColor)
        );
    }

    #[test]
    fn parses_iri() {
        assert_eq!(
            PaintServer::parse_str("url(#link)").unwrap(),
            PaintServer::Iri {
                iri: Box::new(NodeId::Internal("link".to_string())),
                alternate: None,
            }
        );

        assert_eq!(
            PaintServer::parse_str("url(foo#link) none").unwrap(),
            PaintServer::Iri {
                iri: Box::new(NodeId::External("foo".to_string(), "link".to_string())),
                alternate: None,
            }
        );

        assert_eq!(
            PaintServer::parse_str("url(#link) #ff8040").unwrap(),
            PaintServer::Iri {
                iri: Box::new(NodeId::Internal("link".to_string())),
                alternate: Some(cssparser::Color::RGBA(cssparser::RGBA::new(
                    255, 128, 64, 255
                ))),
            }
        );

        assert_eq!(
            PaintServer::parse_str("url(#link) rgb(255, 128, 64, 0.5)").unwrap(),
            PaintServer::Iri {
                iri: Box::new(NodeId::Internal("link".to_string())),
                alternate: Some(cssparser::Color::RGBA(cssparser::RGBA::new(
                    255, 128, 64, 128
                ))),
            }
        );

        assert_eq!(
            PaintServer::parse_str("url(#link) currentColor").unwrap(),
            PaintServer::Iri {
                iri: Box::new(NodeId::Internal("link".to_string())),
                alternate: Some(cssparser::Color::CurrentColor),
            }
        );

        assert!(PaintServer::parse_str("url(#link) invalid").is_err());
    }
}
<commit_msg>Make resolve_color private<commit_after>//! SVG paint servers.

use cssparser::Parser;

use crate::bbox::BoundingBox;
use crate::document::{AcquiredNodes, NodeId};
use crate::drawing_ctx::DrawingCtx;
use crate::element::Element;
use crate::error::{
    AcquireError, ImplementationLimit, NodeIdError, ParseError, RenderingError, ValueErrorKind,
};
use crate::gradient::{ResolvedGradient, UserSpaceGradient};
use crate::node::NodeBorrow;
use crate::parsers::Parse;
use crate::pattern::{ResolvedPattern, UserSpacePattern};
use crate::properties::ComputedValues;
use crate::unit_interval::UnitInterval;
use crate::util;

#[derive(Debug, Clone, PartialEq)]
pub enum PaintServer {
    None,
    Iri {
        iri: Box<NodeId>,
        alternate: Option<cssparser::Color>,
    },
    SolidColor(cssparser::Color),
}

pub enum PaintSource {
    None,
    Gradient(ResolvedGradient, Option<cssparser::RGBA>),
    Pattern(ResolvedPattern, Option<cssparser::RGBA>),
    SolidColor(cssparser::RGBA),
}

pub enum UserSpacePaintSource {
    None,
    Gradient(UserSpaceGradient, Option<cssparser::RGBA>),
    Pattern(UserSpacePattern, Option<cssparser::RGBA>),
    SolidColor(cssparser::RGBA),
}

impl Parse for PaintServer {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<PaintServer, ParseError<'i>> {
        if parser
            .try_parse(|i| i.expect_ident_matching("none"))
            .is_ok()
        {
            Ok(PaintServer::None)
        } else if let Ok(url) = parser.try_parse(|i| i.expect_url()) {
            let loc = parser.current_source_location();

            let alternate = if !parser.is_exhausted() {
                if parser
                    .try_parse(|i| i.expect_ident_matching("none"))
                    .is_ok()
                {
                    None
                } else {
                    Some(parser.try_parse(|i| cssparser::Color::parse(i))?)
                }
            } else {
                None
            };

            Ok(PaintServer::Iri {
                iri: Box::new(
                    NodeId::parse(&url)
                        .map_err(|e: NodeIdError| -> ValueErrorKind { e.into() })
                        .map_err(|e| loc.new_custom_error(e))?,
                ),
                alternate,
            })
        } else {
            Ok(cssparser::Color::parse(parser).map(PaintServer::SolidColor)?)
        }
    }
}

impl PaintServer {
    pub fn resolve(
        &self,
        acquired_nodes: &mut AcquiredNodes<'_>,
        opacity: UnitInterval,
        current_color: cssparser::RGBA,
    ) -> Result<PaintSource, RenderingError> {
        match self {
            PaintServer::Iri {
                ref iri,
                ref alternate,
            } => acquired_nodes
                .acquire(iri)
                .and_then(|acquired| {
                    let node = acquired.get();
                    assert!(node.is_element());

                    match *node.borrow_element() {
                        Element::LinearGradient(ref g) => {
                            g.resolve(&node, acquired_nodes).map(|g| {
                                PaintSource::Gradient(
                                    g,
                                    alternate.map(|c| resolve_color(&c, opacity, current_color)),
                                )
                            })
                        }
                        Element::Pattern(ref p) => p.resolve(&node, acquired_nodes).map(|p| {
                            PaintSource::Pattern(
                                p,
                                alternate.map(|c| resolve_color(&c, opacity, current_color)),
                            )
                        }),
                        Element::RadialGradient(ref g) => {
                            g.resolve(&node, acquired_nodes).map(|g| {
                                PaintSource::Gradient(
                                    g,
                                    alternate.map(|c| resolve_color(&c, opacity, current_color)),
                                )
                            })
                        }
                        _ => Err(AcquireError::InvalidLinkType(iri.as_ref().clone())),
                    }
                })
                .or_else(|err| match (err, alternate) {
                    (AcquireError::MaxReferencesExceeded, _) => {
                        rsvg_log!("exceeded maximum number of referenced objects");
                        Err(RenderingError::LimitExceeded(
                            ImplementationLimit::TooManyReferencedElements,
                        ))
                    }

                    // The following two cases catch AcquireError::CircularReference, which for
                    // paint servers may mean that there is a pattern or gradient with a reference
                    // cycle in its "href" attribute.  This is an invalid paint server, and per
                    // https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint we should try to
                    // fall back to the alternate color.
                    (_, Some(color)) => {
                        rsvg_log!(
                            "could not resolve paint server \"{}\", using alternate color",
                            iri
                        );

                        Ok(PaintSource::SolidColor(resolve_color(
                            color,
                            opacity,
                            current_color,
                        )))
                    }

                    (_, _) => {
                        rsvg_log!(
                            "could not resolve paint server \"{}\", no alternate color specified",
                            iri
                        );

                        Ok(PaintSource::None)
                    }
                }),

            PaintServer::SolidColor(color) => Ok(PaintSource::SolidColor(resolve_color(
                color,
                opacity,
                current_color,
            ))),

            PaintServer::None => Ok(PaintSource::None),
        }
    }
}

impl PaintSource {
    pub fn to_user_space(
        &self,
        bbox: &BoundingBox,
        draw_ctx: &DrawingCtx,
        values: &ComputedValues,
    ) -> UserSpacePaintSource {
        match *self {
            PaintSource::None => UserSpacePaintSource::None,
            PaintSource::SolidColor(c) => UserSpacePaintSource::SolidColor(c),

            PaintSource::Gradient(ref g, c) => match (g.to_user_space(bbox, draw_ctx, values), c) {
                (Some(gradient), c) => UserSpacePaintSource::Gradient(gradient, c),
                (None, Some(c)) => UserSpacePaintSource::SolidColor(c),
                (None, None) => UserSpacePaintSource::None,
            },

            PaintSource::Pattern(ref p, c) => match (p.to_user_space(bbox, draw_ctx, values), c) {
                (Some(pattern), c) => UserSpacePaintSource::Pattern(pattern, c),
                (None, Some(c)) => UserSpacePaintSource::SolidColor(c),
                (None, None) => UserSpacePaintSource::None,
            },
        }
    }
}

fn resolve_color(
    color: &cssparser::Color,
    opacity: UnitInterval,
    current_color: cssparser::RGBA,
) -> cssparser::RGBA {
    let rgba = match *color {
        cssparser::Color::RGBA(rgba) => rgba,
        cssparser::Color::CurrentColor => current_color,
    };

    let UnitInterval(o) = opacity;

    let alpha = (f64::from(rgba.alpha) * o).round();
    let alpha = util::clamp(alpha, 0.0, 255.0);

    // For the following I'd prefer to use `cast::u8(alpha).unwrap()`
    // but the cast crate is erroneously returning Overflow for `u8(255.0)`:
    // https://github.com/japaric/cast.rs/issues/23

    let alpha = alpha as u8;

    cssparser::RGBA { alpha, ..rgba }
}

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

    #[test]
    fn catches_invalid_syntax() {
        assert!(PaintServer::parse_str("").is_err());
        assert!(PaintServer::parse_str("42").is_err());
        assert!(PaintServer::parse_str("invalid").is_err());
    }

    #[test]
    fn parses_none() {
        assert_eq!(PaintServer::parse_str("none").unwrap(), PaintServer::None);
    }

    #[test]
    fn parses_solid_color() {
        assert_eq!(
            PaintServer::parse_str("rgb(255, 128, 64, 0.5)").unwrap(),
            PaintServer::SolidColor(cssparser::Color::RGBA(cssparser::RGBA::new(
                255, 128, 64, 128
            )))
        );

        assert_eq!(
            PaintServer::parse_str("currentColor").unwrap(),
            PaintServer::SolidColor(cssparser::Color::CurrentColor)
        );
    }

    #[test]
    fn parses_iri() {
        assert_eq!(
            PaintServer::parse_str("url(#link)").unwrap(),
            PaintServer::Iri {
                iri: Box::new(NodeId::Internal("link".to_string())),
                alternate: None,
            }
        );

        assert_eq!(
            PaintServer::parse_str("url(foo#link) none").unwrap(),
            PaintServer::Iri {
                iri: Box::new(NodeId::External("foo".to_string(), "link".to_string())),
                alternate: None,
            }
        );

        assert_eq!(
            PaintServer::parse_str("url(#link) #ff8040").unwrap(),
            PaintServer::Iri {
                iri: Box::new(NodeId::Internal("link".to_string())),
                alternate: Some(cssparser::Color::RGBA(cssparser::RGBA::new(
                    255, 128, 64, 255
                ))),
            }
        );

        assert_eq!(
            PaintServer::parse_str("url(#link) rgb(255, 128, 64, 0.5)").unwrap(),
            PaintServer::Iri {
                iri: Box::new(NodeId::Internal("link".to_string())),
                alternate: Some(cssparser::Color::RGBA(cssparser::RGBA::new(
                    255, 128, 64, 128
                ))),
            }
        );

        assert_eq!(
            PaintServer::parse_str("url(#link) currentColor").unwrap(),
            PaintServer::Iri {
                iri: Box::new(NodeId::Internal("link".to_string())),
                alternate: Some(cssparser::Color::CurrentColor),
            }
        );

        assert!(PaintServer::parse_str("url(#link) invalid").is_err());
    }
}
<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Penney's_game
// H = true, T = false

extern crate rand;

use std::io::{stdout, stdin, Write};
use rand::{Rng, thread_rng};

fn toss_coin(print:bool) -> char {
    let c : char;
    if thread_rng().gen::<bool>() {c = 'H'} else {c = 'T'}
    if print {
        print!("{}",c);
        stdout().flush().ok().expect("Could not flush stdout");
        }
    c
}

fn gen_sequence(seed : Option<&str>) -> String {
    let mut seq = String::new();
    match seed {
        Some(s) => {
            let c0 = s.chars().next().unwrap();
            if c0 == 'H' {seq.push('T')
                } else {seq.push('H')}
            seq.push(c0);
            seq.push(s.chars().nth(1).unwrap());
        },
        None => {
            for _ in (0..3) {
                seq.push(toss_coin(false))
            }
        }
    }
    seq
}

fn read_sequence() -> String {
    let mut seq = String::new();
    'reading: loop {
        seq.clear();
        println!("Please, enter sequence of 3 coins: H (heads) or T (tails): ");
        stdin().read_line(&mut seq)
                   .ok().expect("failed to read line");
        seq = seq.trim().to_uppercase();
        if seq.len() != 3 { continue
        } else {
            for c in seq.chars() {
                match c {
                    'H' | 'T' => continue,
                    _ => {
                        println!("Please enter correct sequence!");
                        continue 'reading;
                    }
                };
            }
            return seq;
        }
    }
}

fn main() {
    let useq : String;
    let aiseq : String;
    if thread_rng().gen::<bool>() {
        println!("You choose first!");
        useq = read_sequence();
        println!("Your sequence: {}", useq);
        aiseq = gen_sequence( Some(&useq) );
        println!("My sequence: {}", aiseq);
    } else {
        println!("I choose first!");
        aiseq = gen_sequence(None);
        println!("My sequence: {}", aiseq);
        useq = read_sequence();
        println!("Your sequence: {}", useq);
    }
    println!("Tossing coins...");
    let mut coins = String::new();
        for _ in (0..2) { //toss first 2 coins
            coins.push(toss_coin(true));
            std::thread::sleep_ms(500);
        }
    loop {
        coins.push(toss_coin(true));
        std::thread::sleep_ms(500);
        if coins.contains(&useq) {
            println!("\nYou win!");
            break;
        }
        if coins.contains(&aiseq) {
            println!("\nI win!");
            break;
        }
    }
}<commit_msg>fix indentation<commit_after>// http://rosettacode.org/wiki/Penney's_game
// H = true, T = false

extern crate rand;

use std::io::{stdout, stdin, Write};
use rand::{Rng, thread_rng};

fn toss_coin(print:bool) -> char {
    let c : char;
    if thread_rng().gen::<bool>() {c = 'H'} else {c = 'T'}
    if print {
        print!("{}",c);
        stdout().flush().ok().expect("Could not flush stdout");
        }
    c
}

fn gen_sequence(seed : Option<&str>) -> String {
    let mut seq = String::new();
    match seed {
        Some(s) => {
            let c0 = s.chars().next().unwrap();
            if c0 == 'H' {seq.push('T')
                } else {seq.push('H')}
            seq.push(c0);
            seq.push(s.chars().nth(1).unwrap());
        },
        None => {
            for _ in (0..3) {
                seq.push(toss_coin(false))
            }
        }
    }
    seq
}

fn read_sequence() -> String {
    let mut seq = String::new();
    'reading: loop {
        seq.clear();
        println!("Please, enter sequence of 3 coins: H (heads) or T (tails): ");
        stdin().read_line(&mut seq)
                   .ok().expect("failed to read line");
        seq = seq.trim().to_uppercase();
        if seq.len() != 3 { continue
        } else {
            for c in seq.chars() {
                match c {
                    'H' | 'T' => continue,
                    _ => {
                        println!("Please enter correct sequence!");
                        continue 'reading;
                    }
                };
            }
            return seq;
        }
    }
}

fn main() {
    let useq : String;
    let aiseq : String;
    if thread_rng().gen::<bool>() {
        println!("You choose first!");
        useq = read_sequence();
        println!("Your sequence: {}", useq);
        aiseq = gen_sequence( Some(&useq) );
        println!("My sequence: {}", aiseq);
    } else {
        println!("I choose first!");
        aiseq = gen_sequence(None);
        println!("My sequence: {}", aiseq);
        useq = read_sequence();
        println!("Your sequence: {}", useq);
    }
    println!("Tossing coins...");
    let mut coins = String::new();
    for _ in (0..2) { //toss first 2 coins
        coins.push(toss_coin(true));
        std::thread::sleep_ms(500);
    }
    loop {
        coins.push(toss_coin(true));
        std::thread::sleep_ms(500);
        if coins.contains(&useq) {
            println!("\nYou win!");
            break;
        }
        if coins.contains(&aiseq) {
            println!("\nI win!");
            break;
        }
    }
}
<|endoftext|>