<commit_before>//! The `pattern` element.

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

use crate::aspect_ratio::*;
use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::document::{AcquiredNode, AcquiredNodes, NodeId, NodeStack};
use crate::drawing_ctx::ViewParams;
use crate::element::{Draw, Element, ElementResult, SetAttributes};
use crate::error::*;
use crate::href::{is_href, set_href};
use crate::length::*;
use crate::node::{Node, NodeBorrow, WeakNode};
use crate::parsers::ParseValue;
use crate::properties::ComputedValues;
use crate::rect::Rect;
use crate::transform::{Transform, TransformAttribute};
use crate::unit_interval::UnitInterval;
use crate::viewbox::*;
use crate::xml::Attributes;

coord_units!(PatternUnits, CoordUnits::ObjectBoundingBox);
coord_units!(PatternContentUnits, CoordUnits::UserSpaceOnUse);

#[derive(Clone, Default)]
struct Common {
    units: Option<PatternUnits>,
    content_units: Option<PatternContentUnits>,
    // This Option<Option<ViewBox>> is a bit strange.  We want a field
    // with value None to mean, "this field isn't resolved yet".  However,
    // the vbox can very well be *not* specified in the SVG file.
    // In that case, the fully resolved pattern will have a .vbox=Some(None) value.
    vbox: Option<Option<ViewBox>>,
    preserve_aspect_ratio: Option<AspectRatio>,
    transform: Option<Transform>,
    x: Option<Length<Horizontal>>,
    y: Option<Length<Vertical>>,
    width: Option<ULength<Horizontal>>,
    height: Option<ULength<Vertical>>,
}

/// State used during the pattern resolution process
///
/// This is the current node's pattern information, plus the fallback
/// that should be used in case that information is not complete for a
/// resolved pattern yet.
struct Unresolved {
    pattern: UnresolvedPattern,
    fallback: Option<NodeId>,
}

/// Keeps track of which Pattern provided a non-empty set of children during pattern resolution
#[derive(Clone)]
enum UnresolvedChildren {
    /// Points back to the original Pattern if it had no usable children
    Unresolved,

    /// Points back to the original Pattern, as no pattern in the
    /// chain of fallbacks had usable children.  This only gets returned
    /// by resolve_from_defaults().
    ResolvedEmpty,

    /// Points back to the Pattern that had usable children.
    WithChildren(WeakNode),
}

/// Keeps track of which Pattern provided a non-empty set of children during pattern resolution
#[derive(Clone)]
enum Children {
    Empty,

    /// Points back to the Pattern that had usable children
    WithChildren(WeakNode),
}

/// Main structure used during pattern resolution.  For unresolved
/// patterns, we store all fields as Option<T> - if None, it means
/// that the field is not specified; if Some(T), it means that the
/// field was specified.
struct UnresolvedPattern {
    common: Common,

    // Point back to our corresponding node, or to the fallback node which has children.
    // If the value is None, it means we are fully resolved and didn't find any children
    // among the fallbacks.
    children: UnresolvedChildren,
}

#[derive(Clone)]
pub struct ResolvedPattern {
    units: PatternUnits,
    content_units: PatternContentUnits,
    vbox: Option<ViewBox>,
    preserve_aspect_ratio: AspectRatio,
    transform: Transform,
    x: Length<Horizontal>,
    y: Length<Vertical>,
    width: ULength<Horizontal>,
    height: ULength<Vertical>,
    opacity: UnitInterval,

    // Link to the node whose children are the pattern's resolved children.
    children: Children,
}

/// Pattern normalized to user-space units.
pub struct UserSpacePattern {
    pub width: f64,
    pub height: f64,
    pub transform: Transform,
    pub coord_transform: Transform,
    pub content_transform: Transform,
    pub opacity: UnitInterval,

    // This one is private so the caller has to go through fn acquire_pattern_node()
    node_with_children: Node,
}

#[derive(Default)]
pub struct Pattern {
    common: Common,
    fallback: Option<NodeId>,
}

impl SetAttributes for Pattern {
    fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "patternUnits") => self.common.units = attr.parse(value)?,
                expanded_name!("", "patternContentUnits") => {
                    self.common.content_units = attr.parse(value)?
                }
                expanded_name!("", "viewBox") => self.common.vbox = attr.parse(value)?,
                expanded_name!("", "preserveAspectRatio") => {
                    self.common.preserve_aspect_ratio = attr.parse(value)?
                }
                expanded_name!("", "patternTransform") => {
                    let transform_attr: TransformAttribute = attr.parse(value)?;
                    self.common.transform = Some(transform_attr.to_transform());
                }
                ref a if is_href(a) => {
                    set_href(
                        a,
                        &mut self.fallback,
                        NodeId::parse(value).attribute(attr.clone())?,
                    );
                }
                expanded_name!("", "x") => self.common.x = attr.parse(value)?,
                expanded_name!("", "y") => self.common.y = attr.parse(value)?,
                expanded_name!("", "width") => self.common.width = attr.parse(value)?,
                expanded_name!("", "height") => self.common.height = attr.parse(value)?,
                _ => (),
            }
        }

        Ok(())
    }
}

impl Draw for Pattern {}

impl UnresolvedPattern {
    fn into_resolved(self, opacity: UnitInterval) -> ResolvedPattern {
        assert!(self.is_resolved());

        ResolvedPattern {
            units: self.common.units.unwrap(),
            content_units: self.common.content_units.unwrap(),
            vbox: self.common.vbox.unwrap(),
            preserve_aspect_ratio: self.common.preserve_aspect_ratio.unwrap(),
            transform: self.common.transform.unwrap(),
            x: self.common.x.unwrap(),
            y: self.common.y.unwrap(),
            width: self.common.width.unwrap(),
            height: self.common.height.unwrap(),
            opacity,

            children: self.children.to_resolved(),
        }
    }

    fn is_resolved(&self) -> bool {
        self.common.units.is_some()
            && self.common.content_units.is_some()
            && self.common.vbox.is_some()
            && self.common.preserve_aspect_ratio.is_some()
            && self.common.transform.is_some()
            && self.common.x.is_some()
            && self.common.y.is_some()
            && self.common.width.is_some()
            && self.common.height.is_some()
            && self.children.is_resolved()
    }

    fn resolve_from_fallback(&self, fallback: &UnresolvedPattern) -> UnresolvedPattern {
        let units = self.common.units.or(fallback.common.units);
        let content_units = self.common.content_units.or(fallback.common.content_units);
        let vbox = self.common.vbox.or(fallback.common.vbox);
        let preserve_aspect_ratio = self
            .common
            .preserve_aspect_ratio
            .or(fallback.common.preserve_aspect_ratio);
        let transform = self.common.transform.or(fallback.common.transform);
        let x = self.common.x.or(fallback.common.x);
        let y = self.common.y.or(fallback.common.y);
        let width = self.common.width.or(fallback.common.width);
        let height = self.common.height.or(fallback.common.height);
        let children = self.children.resolve_from_fallback(&fallback.children);

        UnresolvedPattern {
            common: Common {
                units,
                content_units,
                vbox,
                preserve_aspect_ratio,
                transform,
                x,
                y,
                width,
                height,
            },
            children,
        }
    }

    fn resolve_from_defaults(&self) -> UnresolvedPattern {
        let units = self.common.units.or_else(|| Some(PatternUnits::default()));
        let content_units = self
            .common
            .content_units
            .or_else(|| Some(PatternContentUnits::default()));
        let vbox = self.common.vbox.or(Some(None));
        let preserve_aspect_ratio = self
            .common
            .preserve_aspect_ratio
            .or_else(|| Some(AspectRatio::default()));
        let transform = self.common.transform.or_else(|| Some(Transform::default()));
        let x = self.common.x.or_else(|| Some(Default::default()));
        let y = self.common.y.or_else(|| Some(Default::default()));
        let width = self.common.width.or_else(|| Some(Default::default()));
        let height = self.common.height.or_else(|| Some(Default::default()));
        let children = self.children.resolve_from_defaults();

        UnresolvedPattern {
            common: Common {
                units,
                content_units,
                vbox,
                preserve_aspect_ratio,
                transform,
                x,
                y,
                width,
                height,
            },
            children,
        }
    }
}

impl UnresolvedChildren {
    fn from_node(node: &Node) -> UnresolvedChildren {
        let weak = node.downgrade();

        if node.children().any(|child| child.is_element()) {
            UnresolvedChildren::WithChildren(weak)
        } else {
            UnresolvedChildren::Unresolved
        }
    }

    fn is_resolved(&self) -> bool {
        !matches!(*self, UnresolvedChildren::Unresolved)
    }

    fn resolve_from_fallback(&self, fallback: &UnresolvedChildren) -> UnresolvedChildren {
        use UnresolvedChildren::*;

        match (self, fallback) {
            (&Unresolved, &Unresolved) => Unresolved,
            (&WithChildren(ref wc), _) => WithChildren(wc.clone()),
            (_, &WithChildren(ref wc)) => WithChildren(wc.clone()),
            (_, _) => unreachable!(),
        }
    }

    fn resolve_from_defaults(&self) -> UnresolvedChildren {
        use UnresolvedChildren::*;

        match *self {
            Unresolved => ResolvedEmpty,
            _ => (*self).clone(),
        }
    }

    fn to_resolved(&self) -> Children {
        use UnresolvedChildren::*;

        assert!(self.is_resolved());

        match *self {
            ResolvedEmpty => Children::Empty,
            WithChildren(ref wc) => Children::WithChildren(wc.clone()),
            _ => unreachable!(),
        }
    }
}

impl ResolvedPattern {
    fn node_with_children(&self) -> Option<Node> {
        match self.children {
            // This means we didn't find any children among the fallbacks,
            // so there is nothing to render.
            Children::Empty => None,

            Children::WithChildren(ref wc) => Some(wc.upgrade().unwrap()),
        }
    }

    fn get_rect(&self, params: &NormalizeParams) -> Rect {
        let x = self.x.to_user(params);
        let y = self.y.to_user(params);
        let w = self.width.to_user(params);
        let h = self.height.to_user(params);

        Rect::new(x, y, x + w, y + h)
    }

    pub fn to_user_space(
        &self,
        bbox: &BoundingBox,
        current_params: &ViewParams,
        values: &ComputedValues,
    ) -> Option<UserSpacePattern> {
        let node_with_children = self.node_with_children()?;

        let view_params = current_params.with_units(self.units.0);
        let params = NormalizeParams::new(values, &view_params);

        let rect = self.get_rect(&params);

        let bbrect = match bbox.rect {
            None => return None,
            Some(r) if r.is_empty() => return None,
            Some(r) => r,
        };

        // Create the pattern coordinate system
        let (width, height, coord_transform) = match self.units {
            PatternUnits(CoordUnits::ObjectBoundingBox) => (
                rect.width() * bbrect.width(),
                rect.height() * bbrect.height(),
                Transform::new_translate(
                    bbrect.x0 + rect.x0 * bbrect.width(),
                    bbrect.y0 + rect.y0 * bbrect.height(),
                ),
            ),
            PatternUnits(CoordUnits::UserSpaceOnUse) => (
                rect.width(),
                rect.height(),
                Transform::new_translate(rect.x0, rect.y0),
            ),
        };

        let coord_transform = coord_transform.post_transform(&self.transform);

        // Create the pattern contents coordinate system
        let content_transform = if let Some(vbox) = self.vbox {
            // If there is a vbox, use that
            let r = self
                .preserve_aspect_ratio
                .compute(&vbox, &Rect::from_size(width, height));

            let sw = r.width() / vbox.width();
            let sh = r.height() / vbox.height();
            let x = r.x0 - vbox.x0 * sw;
            let y = r.y0 - vbox.y0 * sh;

            Transform::new_scale(sw, sh).pre_translate(x, y)
        } else {
            let PatternContentUnits(content_units) = self.content_units;

            match content_units {
                CoordUnits::ObjectBoundingBox => {
                    Transform::new_scale(bbrect.width(), bbrect.height())
                }
                CoordUnits::UserSpaceOnUse => Transform::identity(),
            }
        };

        Some(UserSpacePattern {
            width,
            height,
            transform: self.transform,
            coord_transform,
            content_transform,
            opacity: self.opacity,
            node_with_children,
        })
    }
}

impl UserSpacePattern {
    /// Gets the `<pattern>` node that contains the children to be drawn for the pattern's contents.
    ///
    /// This has to go through [AcquiredNodes] to catch circular references among
    /// patterns and their children.
    pub fn acquire_pattern_node(
        &self,
        acquired_nodes: &mut AcquiredNodes<'_>,
    ) -> Result<AcquiredNode, AcquireError> {
        acquired_nodes.acquire_ref(&self.node_with_children)
    }
}

impl Pattern {
    fn get_unresolved(&self, node: &Node) -> Unresolved {
        let pattern = UnresolvedPattern {
            common: self.common.clone(),
            children: UnresolvedChildren::from_node(node),
        };

        Unresolved {
            pattern,
            fallback: self.fallback.clone(),
        }
    }

    pub fn resolve(
        &self,
        node: &Node,
        acquired_nodes: &mut AcquiredNodes<'_>,
        opacity: UnitInterval,
    ) -> Result<ResolvedPattern, AcquireError> {
        let Unresolved {
            mut pattern,
            mut fallback,
        } = self.get_unresolved(node);

        let mut stack = NodeStack::new();

        while !pattern.is_resolved() {
            if let Some(ref node_id) = fallback {
                match acquired_nodes.acquire(node_id) {
                    Ok(acquired) => {
                        let acquired_node = acquired.get();

                        if stack.contains(acquired_node) {
                            return Err(AcquireError::CircularReference(acquired_node.clone()));
                        }

                        match *acquired_node.borrow_element() {
                            Element::Pattern(ref p) => {
                                let unresolved = p.get_unresolved(acquired_node);
                                pattern = pattern.resolve_from_fallback(&unresolved.pattern);
                                fallback = unresolved.fallback;

                                stack.push(acquired_node);
                            }
                            _ => return Err(AcquireError::InvalidLinkType(node_id.clone())),
                        }
                    }

                    Err(AcquireError::MaxReferencesExceeded) => {
                        return Err(AcquireError::MaxReferencesExceeded)
                    }

                    Err(e) => {
                        rsvg_log!("Stopping pattern resolution: {}", e);
                        pattern = pattern.resolve_from_defaults();
                        break;
                    }
                }
            } else {
                pattern = pattern.resolve_from_defaults();
                break;
            }
        }

        Ok(pattern.into_resolved(opacity))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::node::NodeData;
    use markup5ever::{namespace_url, ns, QualName};

    #[test]
    fn pattern_resolved_from_defaults_is_really_resolved() {
        let node = Node::new(NodeData::new_element(
            &QualName::new(None, ns!(svg), local_name!("pattern")),
            Attributes::new(),
        ));

        let unresolved = borrow_element_as!(node, Pattern).get_unresolved(&node);
        let pattern = unresolved.pattern.resolve_from_defaults();
        assert!(pattern.is_resolved());
    }
}
<commit_msg>pattern.rs: Remove temporary variable<commit_after>//! The `pattern` element.

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

use crate::aspect_ratio::*;
use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::document::{AcquiredNode, AcquiredNodes, NodeId, NodeStack};
use crate::drawing_ctx::ViewParams;
use crate::element::{Draw, Element, ElementResult, SetAttributes};
use crate::error::*;
use crate::href::{is_href, set_href};
use crate::length::*;
use crate::node::{Node, NodeBorrow, WeakNode};
use crate::parsers::ParseValue;
use crate::properties::ComputedValues;
use crate::rect::Rect;
use crate::transform::{Transform, TransformAttribute};
use crate::unit_interval::UnitInterval;
use crate::viewbox::*;
use crate::xml::Attributes;

coord_units!(PatternUnits, CoordUnits::ObjectBoundingBox);
coord_units!(PatternContentUnits, CoordUnits::UserSpaceOnUse);

#[derive(Clone, Default)]
struct Common {
    units: Option<PatternUnits>,
    content_units: Option<PatternContentUnits>,
    // This Option<Option<ViewBox>> is a bit strange.  We want a field
    // with value None to mean, "this field isn't resolved yet".  However,
    // the vbox can very well be *not* specified in the SVG file.
    // In that case, the fully resolved pattern will have a .vbox=Some(None) value.
    vbox: Option<Option<ViewBox>>,
    preserve_aspect_ratio: Option<AspectRatio>,
    transform: Option<Transform>,
    x: Option<Length<Horizontal>>,
    y: Option<Length<Vertical>>,
    width: Option<ULength<Horizontal>>,
    height: Option<ULength<Vertical>>,
}

/// State used during the pattern resolution process
///
/// This is the current node's pattern information, plus the fallback
/// that should be used in case that information is not complete for a
/// resolved pattern yet.
struct Unresolved {
    pattern: UnresolvedPattern,
    fallback: Option<NodeId>,
}

/// Keeps track of which Pattern provided a non-empty set of children during pattern resolution
#[derive(Clone)]
enum UnresolvedChildren {
    /// Points back to the original Pattern if it had no usable children
    Unresolved,

    /// Points back to the original Pattern, as no pattern in the
    /// chain of fallbacks had usable children.  This only gets returned
    /// by resolve_from_defaults().
    ResolvedEmpty,

    /// Points back to the Pattern that had usable children.
    WithChildren(WeakNode),
}

/// Keeps track of which Pattern provided a non-empty set of children during pattern resolution
#[derive(Clone)]
enum Children {
    Empty,

    /// Points back to the Pattern that had usable children
    WithChildren(WeakNode),
}

/// Main structure used during pattern resolution.  For unresolved
/// patterns, we store all fields as Option<T> - if None, it means
/// that the field is not specified; if Some(T), it means that the
/// field was specified.
struct UnresolvedPattern {
    common: Common,

    // Point back to our corresponding node, or to the fallback node which has children.
    // If the value is None, it means we are fully resolved and didn't find any children
    // among the fallbacks.
    children: UnresolvedChildren,
}

#[derive(Clone)]
pub struct ResolvedPattern {
    units: PatternUnits,
    content_units: PatternContentUnits,
    vbox: Option<ViewBox>,
    preserve_aspect_ratio: AspectRatio,
    transform: Transform,
    x: Length<Horizontal>,
    y: Length<Vertical>,
    width: ULength<Horizontal>,
    height: ULength<Vertical>,
    opacity: UnitInterval,

    // Link to the node whose children are the pattern's resolved children.
    children: Children,
}

/// Pattern normalized to user-space units.
pub struct UserSpacePattern {
    pub width: f64,
    pub height: f64,
    pub transform: Transform,
    pub coord_transform: Transform,
    pub content_transform: Transform,
    pub opacity: UnitInterval,

    // This one is private so the caller has to go through fn acquire_pattern_node()
    node_with_children: Node,
}

#[derive(Default)]
pub struct Pattern {
    common: Common,
    fallback: Option<NodeId>,
}

impl SetAttributes for Pattern {
    fn set_attributes(&mut self, attrs: &Attributes) -> ElementResult {
        for (attr, value) in attrs.iter() {
            match attr.expanded() {
                expanded_name!("", "patternUnits") => self.common.units = attr.parse(value)?,
                expanded_name!("", "patternContentUnits") => {
                    self.common.content_units = attr.parse(value)?
                }
                expanded_name!("", "viewBox") => self.common.vbox = attr.parse(value)?,
                expanded_name!("", "preserveAspectRatio") => {
                    self.common.preserve_aspect_ratio = attr.parse(value)?
                }
                expanded_name!("", "patternTransform") => {
                    let transform_attr: TransformAttribute = attr.parse(value)?;
                    self.common.transform = Some(transform_attr.to_transform());
                }
                ref a if is_href(a) => {
                    set_href(
                        a,
                        &mut self.fallback,
                        NodeId::parse(value).attribute(attr.clone())?,
                    );
                }
                expanded_name!("", "x") => self.common.x = attr.parse(value)?,
                expanded_name!("", "y") => self.common.y = attr.parse(value)?,
                expanded_name!("", "width") => self.common.width = attr.parse(value)?,
                expanded_name!("", "height") => self.common.height = attr.parse(value)?,
                _ => (),
            }
        }

        Ok(())
    }
}

impl Draw for Pattern {}

impl UnresolvedPattern {
    fn into_resolved(self, opacity: UnitInterval) -> ResolvedPattern {
        assert!(self.is_resolved());

        ResolvedPattern {
            units: self.common.units.unwrap(),
            content_units: self.common.content_units.unwrap(),
            vbox: self.common.vbox.unwrap(),
            preserve_aspect_ratio: self.common.preserve_aspect_ratio.unwrap(),
            transform: self.common.transform.unwrap(),
            x: self.common.x.unwrap(),
            y: self.common.y.unwrap(),
            width: self.common.width.unwrap(),
            height: self.common.height.unwrap(),
            opacity,

            children: self.children.to_resolved(),
        }
    }

    fn is_resolved(&self) -> bool {
        self.common.units.is_some()
            && self.common.content_units.is_some()
            && self.common.vbox.is_some()
            && self.common.preserve_aspect_ratio.is_some()
            && self.common.transform.is_some()
            && self.common.x.is_some()
            && self.common.y.is_some()
            && self.common.width.is_some()
            && self.common.height.is_some()
            && self.children.is_resolved()
    }

    fn resolve_from_fallback(&self, fallback: &UnresolvedPattern) -> UnresolvedPattern {
        let units = self.common.units.or(fallback.common.units);
        let content_units = self.common.content_units.or(fallback.common.content_units);
        let vbox = self.common.vbox.or(fallback.common.vbox);
        let preserve_aspect_ratio = self
            .common
            .preserve_aspect_ratio
            .or(fallback.common.preserve_aspect_ratio);
        let transform = self.common.transform.or(fallback.common.transform);
        let x = self.common.x.or(fallback.common.x);
        let y = self.common.y.or(fallback.common.y);
        let width = self.common.width.or(fallback.common.width);
        let height = self.common.height.or(fallback.common.height);
        let children = self.children.resolve_from_fallback(&fallback.children);

        UnresolvedPattern {
            common: Common {
                units,
                content_units,
                vbox,
                preserve_aspect_ratio,
                transform,
                x,
                y,
                width,
                height,
            },
            children,
        }
    }

    fn resolve_from_defaults(&self) -> UnresolvedPattern {
        let units = self.common.units.or_else(|| Some(PatternUnits::default()));
        let content_units = self
            .common
            .content_units
            .or_else(|| Some(PatternContentUnits::default()));
        let vbox = self.common.vbox.or(Some(None));
        let preserve_aspect_ratio = self
            .common
            .preserve_aspect_ratio
            .or_else(|| Some(AspectRatio::default()));
        let transform = self.common.transform.or_else(|| Some(Transform::default()));
        let x = self.common.x.or_else(|| Some(Default::default()));
        let y = self.common.y.or_else(|| Some(Default::default()));
        let width = self.common.width.or_else(|| Some(Default::default()));
        let height = self.common.height.or_else(|| Some(Default::default()));
        let children = self.children.resolve_from_defaults();

        UnresolvedPattern {
            common: Common {
                units,
                content_units,
                vbox,
                preserve_aspect_ratio,
                transform,
                x,
                y,
                width,
                height,
            },
            children,
        }
    }
}

impl UnresolvedChildren {
    fn from_node(node: &Node) -> UnresolvedChildren {
        let weak = node.downgrade();

        if node.children().any(|child| child.is_element()) {
            UnresolvedChildren::WithChildren(weak)
        } else {
            UnresolvedChildren::Unresolved
        }
    }

    fn is_resolved(&self) -> bool {
        !matches!(*self, UnresolvedChildren::Unresolved)
    }

    fn resolve_from_fallback(&self, fallback: &UnresolvedChildren) -> UnresolvedChildren {
        use UnresolvedChildren::*;

        match (self, fallback) {
            (&Unresolved, &Unresolved) => Unresolved,
            (&WithChildren(ref wc), _) => WithChildren(wc.clone()),
            (_, &WithChildren(ref wc)) => WithChildren(wc.clone()),
            (_, _) => unreachable!(),
        }
    }

    fn resolve_from_defaults(&self) -> UnresolvedChildren {
        use UnresolvedChildren::*;

        match *self {
            Unresolved => ResolvedEmpty,
            _ => (*self).clone(),
        }
    }

    fn to_resolved(&self) -> Children {
        use UnresolvedChildren::*;

        assert!(self.is_resolved());

        match *self {
            ResolvedEmpty => Children::Empty,
            WithChildren(ref wc) => Children::WithChildren(wc.clone()),
            _ => unreachable!(),
        }
    }
}

impl ResolvedPattern {
    fn node_with_children(&self) -> Option<Node> {
        match self.children {
            // This means we didn't find any children among the fallbacks,
            // so there is nothing to render.
            Children::Empty => None,

            Children::WithChildren(ref wc) => Some(wc.upgrade().unwrap()),
        }
    }

    fn get_rect(&self, params: &NormalizeParams) -> Rect {
        let x = self.x.to_user(params);
        let y = self.y.to_user(params);
        let w = self.width.to_user(params);
        let h = self.height.to_user(params);

        Rect::new(x, y, x + w, y + h)
    }

    pub fn to_user_space(
        &self,
        bbox: &BoundingBox,
        current_params: &ViewParams,
        values: &ComputedValues,
    ) -> Option<UserSpacePattern> {
        let node_with_children = self.node_with_children()?;

        let view_params = current_params.with_units(self.units.0);
        let params = NormalizeParams::new(values, &view_params);

        let rect = self.get_rect(&params);

        let bbrect = match bbox.rect {
            None => return None,
            Some(r) if r.is_empty() => return None,
            Some(r) => r,
        };

        // Create the pattern coordinate system
        let (width, height, coord_transform) = match self.units {
            PatternUnits(CoordUnits::ObjectBoundingBox) => (
                rect.width() * bbrect.width(),
                rect.height() * bbrect.height(),
                Transform::new_translate(
                    bbrect.x0 + rect.x0 * bbrect.width(),
                    bbrect.y0 + rect.y0 * bbrect.height(),
                ),
            ),
            PatternUnits(CoordUnits::UserSpaceOnUse) => (
                rect.width(),
                rect.height(),
                Transform::new_translate(rect.x0, rect.y0),
            ),
        };

        let coord_transform = coord_transform.post_transform(&self.transform);

        // Create the pattern contents coordinate system
        let content_transform = if let Some(vbox) = self.vbox {
            // If there is a vbox, use that
            let r = self
                .preserve_aspect_ratio
                .compute(&vbox, &Rect::from_size(width, height));

            let sw = r.width() / vbox.width();
            let sh = r.height() / vbox.height();
            let x = r.x0 - vbox.x0 * sw;
            let y = r.y0 - vbox.y0 * sh;

            Transform::new_scale(sw, sh).pre_translate(x, y)
        } else {
            match self.content_units {
                PatternContentUnits(CoordUnits::ObjectBoundingBox) => {
                    Transform::new_scale(bbrect.width(), bbrect.height())
                }
                PatternContentUnits(CoordUnits::UserSpaceOnUse) => Transform::identity(),
            }
        };

        Some(UserSpacePattern {
            width,
            height,
            transform: self.transform,
            coord_transform,
            content_transform,
            opacity: self.opacity,
            node_with_children,
        })
    }
}

impl UserSpacePattern {
    /// Gets the `<pattern>` node that contains the children to be drawn for the pattern's contents.
    ///
    /// This has to go through [AcquiredNodes] to catch circular references among
    /// patterns and their children.
    pub fn acquire_pattern_node(
        &self,
        acquired_nodes: &mut AcquiredNodes<'_>,
    ) -> Result<AcquiredNode, AcquireError> {
        acquired_nodes.acquire_ref(&self.node_with_children)
    }
}

impl Pattern {
    fn get_unresolved(&self, node: &Node) -> Unresolved {
        let pattern = UnresolvedPattern {
            common: self.common.clone(),
            children: UnresolvedChildren::from_node(node),
        };

        Unresolved {
            pattern,
            fallback: self.fallback.clone(),
        }
    }

    pub fn resolve(
        &self,
        node: &Node,
        acquired_nodes: &mut AcquiredNodes<'_>,
        opacity: UnitInterval,
    ) -> Result<ResolvedPattern, AcquireError> {
        let Unresolved {
            mut pattern,
            mut fallback,
        } = self.get_unresolved(node);

        let mut stack = NodeStack::new();

        while !pattern.is_resolved() {
            if let Some(ref node_id) = fallback {
                match acquired_nodes.acquire(node_id) {
                    Ok(acquired) => {
                        let acquired_node = acquired.get();

                        if stack.contains(acquired_node) {
                            return Err(AcquireError::CircularReference(acquired_node.clone()));
                        }

                        match *acquired_node.borrow_element() {
                            Element::Pattern(ref p) => {
                                let unresolved = p.get_unresolved(acquired_node);
                                pattern = pattern.resolve_from_fallback(&unresolved.pattern);
                                fallback = unresolved.fallback;

                                stack.push(acquired_node);
                            }
                            _ => return Err(AcquireError::InvalidLinkType(node_id.clone())),
                        }
                    }

                    Err(AcquireError::MaxReferencesExceeded) => {
                        return Err(AcquireError::MaxReferencesExceeded)
                    }

                    Err(e) => {
                        rsvg_log!("Stopping pattern resolution: {}", e);
                        pattern = pattern.resolve_from_defaults();
                        break;
                    }
                }
            } else {
                pattern = pattern.resolve_from_defaults();
                break;
            }
        }

        Ok(pattern.into_resolved(opacity))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::node::NodeData;
    use markup5ever::{namespace_url, ns, QualName};

    #[test]
    fn pattern_resolved_from_defaults_is_really_resolved() {
        let node = Node::new(NodeData::new_element(
            &QualName::new(None, ns!(svg), local_name!("pattern")),
            Attributes::new(),
        ));

        let unresolved = borrow_element_as!(node, Pattern).get_unresolved(&node);
        let pattern = unresolved.pattern.resolve_from_defaults();
        assert!(pattern.is_resolved());
    }
}
<|endoftext|>


<commit_before>trait Persister {
    fn add_item(&self, &Item) -> i32;
    fn change_item_desc(&self, i32, &str);
    fn update_item(&self, &Item);
    fn remove_item(&self, i32);
    fn get_items(&self) -> Vec<Item>;
}
<commit_msg>Rework params of Persister trait methods<commit_after>trait Persister {
    fn add_item(&self, desc: &str) -> i32;
    fn change_item_desc(&self, id: i32, desc: &str) -> Result<(), ()>;
    fn update_item(&self, id: i32, last_reviewed: i32, ff: f64, int_step: i32, iri: f64) -> Result<(), ()>;
    fn remove_item(&self, id: i32) -> Result<(), ()>;
    fn get_items(&self) -> Vec<Item>;
}
<|endoftext|>


<commit_before>//! Compiler plugin for Rust-PHF
//!
//! See the documentation for the `phf` crate for more details.
#[crate_id="github.com/sfackler/rust-phf/phf_mac"];
#[crate_type="dylib"];
#[doc(html_root_url="http://www.rust-ci.org/sfackler/rust-phf/doc")];
#[feature(managed_boxes, macro_registrar, quote)];

extern crate collections;
extern crate extra;
extern crate syntax;
extern crate time;
extern crate phf;

use collections::HashMap;
use std::rand;
use std::os;
use std::vec;
use syntax::ast;
use syntax::ast::{Name, TokenTree, LitStr, MutImmutable, Expr, ExprVec, ExprLit};
use syntax::codemap::Span;
use syntax::ext::base::{SyntaxExtension,
                        ExtCtxt,
                        MacResult,
                        MRExpr,
                        NormalTT,
                        BasicMacroExpander};
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{InternedString, COMMA, EOF, FAT_ARROW};

static DEFAULT_LAMBDA: uint = 5;

#[macro_registrar]
#[doc(hidden)]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("phf_map"),
             NormalTT(~BasicMacroExpander {
                expander: expand_mphf_map,
                span: None
             },
             None));
}

struct Entry {
    key_str: InternedString,
    key: @Expr,
    value: @Expr
}

fn expand_mphf_map(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> MacResult {
    let mut entries = match parse_entries(cx, tts) {
        Some(entries) => entries,
        None => return MacResult::dummy_expr(sp)
    };

    entries.sort_by(|a, b| a.key_str.cmp(&b.key_str));
    if has_duplicates(cx, sp, entries) {
        return MacResult::dummy_expr(sp);
    }

    let start = time::precise_time_s();
    let state;
    loop {
        match generate_hash(entries) {
            Some(s) => {
                state = s;
                break;
            }
            None => {}
        }
    }
    let time = time::precise_time_s() - start;
    if os::getenv("PHF_STATS").is_some() {
        cx.span_note(sp, format!("PHF generation took {} seconds", time));
    }

    create_map(cx, sp, entries, state)
}

fn parse_entries(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<~[Entry]> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.to_owned());
    let mut entries = ~[];

    let mut bad = false;
    while parser.token != EOF {
        let key = cx.expand_expr(parser.parse_expr());

        let key_str = match key.node {
            ExprLit(lit) => {
                match lit.node {
                    LitStr(ref s, _) => s.clone(),
                    _ => {
                        cx.span_err(key.span, "expected string literal");
                        bad = true;
                        InternedString::new("")
                    }
                }
            }
            _ => {
                cx.span_err(key.span, "expected string literal");
                bad = true;
                InternedString::new("")
            }
        };

        if !parser.eat(&FAT_ARROW) {
            cx.span_err(parser.span, "expected `=>`");
            return None;
        }

        let value = parser.parse_expr();

        entries.push(Entry {
            key_str: key_str,
            key: key,
            value: value
        });

        if !parser.eat(&COMMA) && parser.token != EOF {
            cx.span_err(parser.span, "expected `,`");
            return None;
        }
    }

    if entries.len() > phf::MAX_SIZE {
        cx.span_err(parser.span,
                    format!("maps with more than {} entries are not supported",
                            phf::MAX_SIZE));
        return None;
    }

    if bad {
        return None;
    }

    Some(entries)
}

fn has_duplicates(cx: &mut ExtCtxt, sp: Span, entries: &[Entry]) -> bool {
    let mut dups = false;
    let mut in_dup = false;
    for window in entries.windows(2) {
        let ref a = window[0];
        let ref b = window[1];
        if a.key_str == b.key_str {
            dups = true;
            if !in_dup {
                cx.span_err(sp, format!("duplicate key \"{}\"", a.key_str));
                cx.span_note(a.key.span, "one occurrence here");
                in_dup = true;
            }
            cx.span_note(b.key.span, "one occurrence here");
        } else {
            in_dup = false;
        }
    }

    dups
}

struct HashState {
    k1: u64,
    k2: u64,
    disps: ~[(uint, uint)],
    map: ~[Option<uint>],
}

fn generate_hash(entries: &[Entry]) -> Option<HashState> {
    struct Bucket {
        idx: uint,
        keys: ~[uint],
    }

    struct Hashes {
        g: uint,
        f1: uint,
        f2: uint,
    }

    let k1 = rand::random();
    let k2 = rand::random();

    let hashes = entries.iter().map(|entry| {
            let (g, f1, f2) = phf::hash(entry.key_str.get(), k1, k2);
            Hashes {
                g: g,
                f1: f1,
                f2: f2
            }
        }).to_owned_vec();

    let buckets_len = (entries.len() + DEFAULT_LAMBDA - 1) / DEFAULT_LAMBDA;
    let mut buckets = vec::from_fn(buckets_len,
                                   |i| Bucket { idx: i, keys: ~[] });

    for (i, hash) in hashes.iter().enumerate() {
        buckets[hash.g % buckets_len].keys.push(i);
    }

    // Sort descending
    buckets.sort_by(|a, b| b.keys.len().cmp(&a.keys.len()));

    let table_len = entries.len();
    let mut map = vec::from_elem(table_len, None);
    let mut disps = vec::from_elem(buckets_len, None);
    let mut try_map = HashMap::new();
    'buckets: for bucket in buckets.iter() {
        for d1 in range(0, table_len) {
            'disps_l: for d2 in range(0, table_len) {
                try_map.clear();
                for &key in bucket.keys.iter() {
                    let idx = phf::displace(hashes[key].f1, hashes[key].f2,
                                            d1, d2) % table_len;
                    if try_map.find(&idx).is_some() || map[idx].is_some() {
                        continue 'disps_l;
                    }
                    try_map.insert(idx, key);
                }

                // We've picked a good set of disps
                disps[bucket.idx] = Some((d1, d2));
                for (&idx, &key) in try_map.iter() {
                    map[idx] = Some(key);
                }
                continue 'buckets;
            }
        }

        // Unable to find displacements for a bucket
        return None;
    }

    let disps = disps.move_iter().map(|i| i.expect("should have a bucket"))
            .collect();

    Some(HashState {
        k1: k1,
        k2: k2,
        disps: disps,
        map: map,
    })
}

fn create_map(cx: &mut ExtCtxt, sp: Span, entries: ~[Entry], state: HashState)
              -> MacResult {
    let len = entries.len();
    let k1 = state.k1;
    let k2 = state.k2;
    let disps = state.disps.iter().map(|&(d1, d2)| {
            quote_expr!(&*cx, ($d1, $d2))
        }).collect();
    let disps = @Expr {
        id: ast::DUMMY_NODE_ID,
        node: ExprVec(disps, MutImmutable),
        span: sp,
    };
    let entries = state.map.iter().map(|&idx| {
            match idx {
                Some(idx) => {
                    let Entry { key, value, .. } = entries[idx];
                    quote_expr!(&*cx, Some(($key, $value)))
                }
                None => quote_expr!(&*cx, None),
            }
        }).collect();
    let entries = @Expr {
        id: ast::DUMMY_NODE_ID,
        node: ExprVec(entries, MutImmutable),
        span: sp,
    };

    MRExpr(quote_expr!(cx, PhfMap {
        len: $len,
        k1: $k1,
        k2: $k2,
        disps: &'static $disps,
        entries: &'static $entries,
    }))
}
<commit_msg>Update for upstream changes<commit_after>//! Compiler plugin for Rust-PHF
//!
//! See the documentation for the `phf` crate for more details.
#[crate_id="github.com/sfackler/rust-phf/phf_mac"];
#[crate_type="dylib"];
#[doc(html_root_url="http://www.rust-ci.org/sfackler/rust-phf/doc")];
#[feature(managed_boxes, macro_registrar, quote)];

extern crate collections;
extern crate extra;
extern crate syntax;
extern crate time;
extern crate phf;

use collections::HashMap;
use std::rand;
use std::os;
use std::vec;
use syntax::ast;
use syntax::ast::{Name, TokenTree, LitStr, MutImmutable, Expr, ExprVec, ExprLit};
use syntax::codemap::Span;
use syntax::ext::base::{SyntaxExtension,
                        ExtCtxt,
                        MacResult,
                        MRExpr,
                        NormalTT,
                        BasicMacroExpander};
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{InternedString, COMMA, EOF, FAT_ARROW};

static DEFAULT_LAMBDA: uint = 5;

#[macro_registrar]
#[doc(hidden)]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("phf_map"),
             NormalTT(~BasicMacroExpander {
                expander: expand_mphf_map,
                span: None
             },
             None));
}

struct Entry {
    key_str: InternedString,
    key: @Expr,
    value: @Expr
}

fn expand_mphf_map(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> MacResult {
    let mut entries = match parse_entries(cx, tts) {
        Some(entries) => entries,
        None => return MacResult::dummy_expr(sp)
    };

    entries.sort_by(|a, b| a.key_str.cmp(&b.key_str));
    if has_duplicates(cx, sp, entries) {
        return MacResult::dummy_expr(sp);
    }

    let start = time::precise_time_s();
    let state;
    loop {
        match generate_hash(entries) {
            Some(s) => {
                state = s;
                break;
            }
            None => {}
        }
    }
    let time = time::precise_time_s() - start;
    if os::getenv("PHF_STATS").is_some() {
        cx.span_note(sp, format!("PHF generation took {} seconds", time));
    }

    create_map(cx, sp, entries, state)
}

fn parse_entries(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<~[Entry]> {
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
                                                tts.iter().map(|x| x.clone())
                                                    .collect());
    let mut entries = ~[];

    let mut bad = false;
    while parser.token != EOF {
        let key = cx.expand_expr(parser.parse_expr());

        let key_str = match key.node {
            ExprLit(lit) => {
                match lit.node {
                    LitStr(ref s, _) => s.clone(),
                    _ => {
                        cx.span_err(key.span, "expected string literal");
                        bad = true;
                        InternedString::new("")
                    }
                }
            }
            _ => {
                cx.span_err(key.span, "expected string literal");
                bad = true;
                InternedString::new("")
            }
        };

        if !parser.eat(&FAT_ARROW) {
            cx.span_err(parser.span, "expected `=>`");
            return None;
        }

        let value = parser.parse_expr();

        entries.push(Entry {
            key_str: key_str,
            key: key,
            value: value
        });

        if !parser.eat(&COMMA) && parser.token != EOF {
            cx.span_err(parser.span, "expected `,`");
            return None;
        }
    }

    if entries.len() > phf::MAX_SIZE {
        cx.span_err(parser.span,
                    format!("maps with more than {} entries are not supported",
                            phf::MAX_SIZE));
        return None;
    }

    if bad {
        return None;
    }

    Some(entries)
}

fn has_duplicates(cx: &mut ExtCtxt, sp: Span, entries: &[Entry]) -> bool {
    let mut dups = false;
    let mut in_dup = false;
    for window in entries.windows(2) {
        let ref a = window[0];
        let ref b = window[1];
        if a.key_str == b.key_str {
            dups = true;
            if !in_dup {
                cx.span_err(sp, format!("duplicate key \"{}\"", a.key_str));
                cx.span_note(a.key.span, "one occurrence here");
                in_dup = true;
            }
            cx.span_note(b.key.span, "one occurrence here");
        } else {
            in_dup = false;
        }
    }

    dups
}

struct HashState {
    k1: u64,
    k2: u64,
    disps: ~[(uint, uint)],
    map: ~[Option<uint>],
}

fn generate_hash(entries: &[Entry]) -> Option<HashState> {
    struct Bucket {
        idx: uint,
        keys: ~[uint],
    }

    struct Hashes {
        g: uint,
        f1: uint,
        f2: uint,
    }

    let k1 = rand::random();
    let k2 = rand::random();

    let hashes = entries.iter().map(|entry| {
            let (g, f1, f2) = phf::hash(entry.key_str.get(), k1, k2);
            Hashes {
                g: g,
                f1: f1,
                f2: f2
            }
        }).to_owned_vec();

    let buckets_len = (entries.len() + DEFAULT_LAMBDA - 1) / DEFAULT_LAMBDA;
    let mut buckets = vec::from_fn(buckets_len,
                                   |i| Bucket { idx: i, keys: ~[] });

    for (i, hash) in hashes.iter().enumerate() {
        buckets[hash.g % buckets_len].keys.push(i);
    }

    // Sort descending
    buckets.sort_by(|a, b| b.keys.len().cmp(&a.keys.len()));

    let table_len = entries.len();
    let mut map = vec::from_elem(table_len, None);
    let mut disps = vec::from_elem(buckets_len, None);
    let mut try_map = HashMap::new();
    'buckets: for bucket in buckets.iter() {
        for d1 in range(0, table_len) {
            'disps_l: for d2 in range(0, table_len) {
                try_map.clear();
                for &key in bucket.keys.iter() {
                    let idx = phf::displace(hashes[key].f1, hashes[key].f2,
                                            d1, d2) % table_len;
                    if try_map.find(&idx).is_some() || map[idx].is_some() {
                        continue 'disps_l;
                    }
                    try_map.insert(idx, key);
                }

                // We've picked a good set of disps
                disps[bucket.idx] = Some((d1, d2));
                for (&idx, &key) in try_map.iter() {
                    map[idx] = Some(key);
                }
                continue 'buckets;
            }
        }

        // Unable to find displacements for a bucket
        return None;
    }

    let disps = disps.move_iter().map(|i| i.expect("should have a bucket"))
            .collect();

    Some(HashState {
        k1: k1,
        k2: k2,
        disps: disps,
        map: map,
    })
}

fn create_map(cx: &mut ExtCtxt, sp: Span, entries: ~[Entry], state: HashState)
              -> MacResult {
    let len = entries.len();
    let k1 = state.k1;
    let k2 = state.k2;
    let disps = state.disps.iter().map(|&(d1, d2)| {
            quote_expr!(&*cx, ($d1, $d2))
        }).collect();
    let disps = @Expr {
        id: ast::DUMMY_NODE_ID,
        node: ExprVec(disps, MutImmutable),
        span: sp,
    };
    let entries = state.map.iter().map(|&idx| {
            match idx {
                Some(idx) => {
                    let Entry { key, value, .. } = entries[idx];
                    quote_expr!(&*cx, Some(($key, $value)))
                }
                None => quote_expr!(&*cx, None),
            }
        }).collect();
    let entries = @Expr {
        id: ast::DUMMY_NODE_ID,
        node: ExprVec(entries, MutImmutable),
        span: sp,
    };

    MRExpr(quote_expr!(cx, PhfMap {
        len: $len,
        k1: $k1,
        k2: $k2,
        disps: &'static $disps,
        entries: &'static $entries,
    }))
}
<|endoftext|>


<commit_before>//! The [`uuid`] prelude.
//!
//! This module contains the most important items of the [`uuid`] crate.
//!
//! To use the prelude, include the following in your crate root:
//!
//! ```rust
//! extern crate uuid;
//! ```
//!
//! and the following in every module:
//!
//! ```rust
//! use uuid::prelude::*;
//! ```
//!
//! # Prelude Contents
//!
//! Currently the prelude reexports the following:
//!
//! ## The core types
//!
//! [`uuid`]`::{`[`ParseError`], [`Uuid`], [`UuidVariant`]`}`: The fundamental
//! types used in [`uuid`] crate.
//!
//! [`uuid`]: ../index.html
//! [`ParseError`]: ../enum.ParseError.html
//! [`Uuid`]: ../struct.Uuid.html
//! [`UuidVariant`]: enum.UuidVariant.html

#[doc(inline)]
pub use super::{ParseError, Uuid, UuidVariant};
<commit_msg>add UuidVersion to the prelude<commit_after>//! The [`uuid`] prelude.
//!
//! This module contains the most important items of the [`uuid`] crate.
//!
//! To use the prelude, include the following in your crate root:
//!
//! ```rust
//! extern crate uuid;
//! ```
//!
//! and the following in every module:
//!
//! ```rust
//! use uuid::prelude::*;
//! ```
//!
//! # Prelude Contents
//!
//! Currently the prelude reexports the following:
//!
//! ## The core types
//!
//! [`uuid`]`::{`[`ParseError`], [`Uuid`], [`UuidVariant`], [`UuidVersion`]`}`: The fundamental
//! types used in [`uuid`] crate.
//!
//! [`uuid`]: ../index.html
//! [`ParseError`]: ../enum.ParseError.html
//! [`Uuid`]: ../struct.Uuid.html
//! [`UuidVariant`]: ../enum.UuidVariant.html
//! [`UuidVersion`]: ../enum.UuidVersion.html

#[doc(inline)]
pub use super::{ParseError, Uuid, UuidVariant, UuidVersion};
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Prepare
//!
//! If a pattern needs to be matched against many different things, it can be prepared in order to generate an object that can
//! be used many times without the delay of generating a DFA.
//!
//! ```
//! # use ndfa::*;
//! let match_abcs      = "abc".prepare_to_match();
//! let match_many_abcs = "abc".repeat_forever(1).prepare_to_match();
//! ```
//!

use super::countable::*;
use super::symbol_range::*;
use super::state_machine::*;
use super::regular_pattern::*;
use super::symbol_range_dfa::*;
use super::dfa_compiler::*;

///
/// Can be applied to patterns and other objects in order to match them
///
pub trait PrepareToMatch<As> where As: Sized {
    fn prepare_to_match(self) -> As;
}

impl<InputSymbol: Clone+PartialOrd+Countable, OutputSymbol: Ord+Clone> PrepareToMatch<SymbolRangeDfa<InputSymbol, OutputSymbol>>
for Box<StateMachine<SymbolRange<InputSymbol>, OutputSymbol>> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        let builder       = SymbolRangeDfaBuilder::new();
        let state_machine = DfaCompiler::build(self, builder);

        state_machine
    }
}

impl<InputSymbol: Clone+PartialOrd+Countable+'static> PrepareToMatch<SymbolRangeDfa<InputSymbol, bool>>
for Pattern<InputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, bool> {
        let ndfa = self.to_ndfa(true);

        ndfa.prepare_to_match()
    }
}

impl<'a, InputSymbol: Clone+PartialOrd+Countable+'static> PrepareToMatch<SymbolRangeDfa<InputSymbol, bool>>
for &'a ToPattern<InputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, bool> {
        let pattern = self.to_pattern();

        pattern.prepare_to_match()
    }
}

impl<InputSymbol: Clone+PartialOrd+Countable, OutputSymbol> PrepareToMatch<SymbolRangeDfa<InputSymbol, OutputSymbol>> for SymbolRangeDfa<InputSymbol, OutputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        self
    }
}

impl<'a> PrepareToMatch<SymbolRangeDfa<char, bool>>
for &'a str {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<char, bool> {
        let pattern = self.to_pattern();

        pattern.prepare_to_match()
    }
}
<commit_msg>Add demo for how to use a prepared expression<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Prepare
//!
//! If a pattern needs to be matched against many different things, it can be prepared in order to generate an object that can
//! be used many times without the delay of generating a DFA.
//!
//! ```
//! # use ndfa::*;
//! let match_abcs      = "abc".prepare_to_match();
//! let match_many_abcs = "abc".repeat_forever(1).prepare_to_match();
//!
//! if match("abcabc", match_many_abcs).is_some() { /* ... */ }
//! # assert!(match("abc", match_many_abcs).is_some());
//! ```
//!

use super::countable::*;
use super::symbol_range::*;
use super::state_machine::*;
use super::regular_pattern::*;
use super::symbol_range_dfa::*;
use super::dfa_compiler::*;

///
/// Can be applied to patterns and other objects in order to match them
///
pub trait PrepareToMatch<As> where As: Sized {
    fn prepare_to_match(self) -> As;
}

impl<InputSymbol: Clone+PartialOrd+Countable, OutputSymbol: Ord+Clone> PrepareToMatch<SymbolRangeDfa<InputSymbol, OutputSymbol>>
for Box<StateMachine<SymbolRange<InputSymbol>, OutputSymbol>> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        let builder       = SymbolRangeDfaBuilder::new();
        let state_machine = DfaCompiler::build(self, builder);

        state_machine
    }
}

impl<InputSymbol: Clone+PartialOrd+Countable+'static> PrepareToMatch<SymbolRangeDfa<InputSymbol, bool>>
for Pattern<InputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, bool> {
        let ndfa = self.to_ndfa(true);

        ndfa.prepare_to_match()
    }
}

impl<'a, InputSymbol: Clone+PartialOrd+Countable+'static> PrepareToMatch<SymbolRangeDfa<InputSymbol, bool>>
for &'a ToPattern<InputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, bool> {
        let pattern = self.to_pattern();

        pattern.prepare_to_match()
    }
}

impl<InputSymbol: Clone+PartialOrd+Countable, OutputSymbol> PrepareToMatch<SymbolRangeDfa<InputSymbol, OutputSymbol>> for SymbolRangeDfa<InputSymbol, OutputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        self
    }
}

impl<'a> PrepareToMatch<SymbolRangeDfa<char, bool>>
for &'a str {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<char, bool> {
        let pattern = self.to_pattern();

        pattern.prepare_to_match()
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

type Bit = bool;

#[derive(Debug)]
pub struct Request {
    header: Header,
    payload: Payload,
}

impl Request {
    pub fn new(header: Header, payload: Payload) -> Request {
        Request {
            header,
            payload,
        }
    }
}

#[derive(Debug)]
pub struct Payload(pub Vec<u8>);

// RequestBin newtype
pub struct RequestBin(pub Vec<u8>);

#[derive(Debug)]
pub struct Header {
    frame: Frame,
    frame_address: FrameAddress,
    protocol_header: ProtocolHeader,
}

impl Header {
    pub fn new(frame: Frame,
               frame_address: FrameAddress,
               protocol_header: ProtocolHeader)
               -> Header {
        Header {
            frame,
            frame_address,
            protocol_header,
        }
    }
}

#[derive(Debug)]
pub struct Frame {
    // First 2 bytes
    size: u16,

    // Second two bytes
    origin: u8,
    // For discovery using Device::GetService use true and target all zeroes.
    // For all other requests set to false and target to device MAC address.
    tagged: bool,
    addressable: bool, // Must be true
    protocol: u16, // Must be 1024

    // Final 4 bytes
    source: u32,
}

impl Frame {
    pub fn new(origin: u8, tagged: bool, addressable: bool, protocol: u16, source: u32) -> Frame {
        Frame {
            size: 0,
            origin,
            tagged,
            addressable,
            protocol,
            source,
        }
    }
}

#[derive(Debug)]
pub struct FrameAddress {
    // MAC address (6 bytes) left-justified with two 0 bytes, or all 0s for all devices
    target: [u8; 8],
    reserved: [u8; 6],
    reserved_2: u8,
    ack_required: bool,
    res_required: bool,
    sequence: u8,
}

impl FrameAddress {
    pub fn new(target: [u8; 8],
               reserved: [u8; 6],
               reserved_2: u8,
               ack_required: bool,
               res_required: bool,
               sequence: u8)
               -> FrameAddress {
        FrameAddress {
            target,
            reserved,
            reserved_2,
            ack_required,
            res_required,
            sequence,
        }
    }
}

#[derive(Debug)]
pub struct ProtocolHeader {
    reserved: u64,
    message_type: u16,
    reserved_2: u16,
}

impl ProtocolHeader {
    pub fn new(reserved: u64, message_type: u16, reserved_2: u16) -> ProtocolHeader {
        ProtocolHeader {
            reserved,
            message_type,
            reserved_2,
        }
    }
}

// BitFrame is an intermediate representation.
struct BitFrame {
    // First 2 bytes
    size: u16,

    // Second two bytes
    origin: BitOrigin,

    // For discovery using Device::GetService use true and target all zeroes.
    // For all other requests set to false and target to device MAC address.
    tagged: Bit,
    addressable: Bit, // Must be true
    protocol: BitProtocol, // Must be 1024

    // Final 4 bytes
    source: u32,
}

impl<'a> From<&'a Frame> for BitFrame {
    fn from(f: &Frame) -> BitFrame {
        BitFrame {
            // First two bytes
            size: f.size,

            // Second two bytes
            origin: BitOrigin::from(f.origin),
            tagged: f.tagged,
            addressable: f.addressable,
            protocol: BitProtocol::from(f.protocol),

            // Final four bytes
            source: f.source,
        }
    }
}

// BitOrigin newtype
struct BitOrigin([Bit; 2]);

impl From<u8> for BitOrigin {
    // Format as zero padded boolean string.
    // Convert boolean string to vec of bools
    fn from(o: u8) -> BitOrigin {
        let s = format!("{:02b}", o);
        let v: Vec<Bit> = s.as_bytes()
            .iter()
            .map(|&n| n == 49)
            .collect();
        BitOrigin([v[0], v[1]])
    }
}

// BitProtocol newtype
struct BitProtocol([Bit; 12]);

impl From<u16> for BitProtocol {
    fn from(p: u16) -> BitProtocol {
        let s = format!("{:012b}", p);
        let v: Vec<Bit> = s.as_bytes()
            .iter()
            .map(|&n| n == 49)
            .collect();
        BitProtocol([v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11]])
    }
}

struct BitFrameAddress {
    // MAC address (6 bytes) left-justified with two 0 bytes, or all 0s for all devices
    target: [u8; 8],
    reserved: [u8; 6],
    reserved_2: [Bit; 6],
    ack_required: Bit,
    res_required: Bit,
    sequence: u8,
}

impl<'a> From<&'a FrameAddress> for BitFrameAddress {
    fn from(f: &FrameAddress) -> BitFrameAddress {
        BitFrameAddress {
            target: f.target,
            reserved: f.reserved,
            reserved_2: {
                let s = format!("{:06b}", f.reserved_2);
                let v: Vec<bool> = s.as_bytes()
                    .iter()
                    .map(|&n| n == 49)
                    .collect();
                let a: [Bit; 6] = [v[0], v[1], v[2], v[3], v[4], v[5]];
                a
            },
            ack_required: f.ack_required,
            res_required: f.res_required,
            sequence: f.sequence,
        }
    }
}

impl From<Request> for RequestBin {
    fn from(msg: Request) -> RequestBin {
        let mut msg_bin = RequestBin(vec![]);

        // First 2 bytes of Frame
        msg_bin.extend_with_u16(msg.header.frame.size);

        // Second 2 bytes of Frame
        let bitframe = BitFrame::from(&msg.header.frame);

        let mut fr_pt2: [Bit; 16] = [false; 16];
        fr_pt2[0] = bitframe.origin.0[0];
        fr_pt2[1] = bitframe.origin.0[1];
        fr_pt2[2] = bitframe.tagged;
        fr_pt2[3] = bitframe.addressable;
        for i in 0..bitframe.protocol.0.len() {
            fr_pt2[i + 4] = bitframe.protocol.0[i];
        }

        let (fr_pt2_a_bits, fr_pt2_b_bits) = fr_pt2.split_at(8);
        let fr_pt2_a = RequestBin::bits_to_byte(fr_pt2_a_bits);
        let fr_pt2_b = RequestBin::bits_to_byte(fr_pt2_b_bits);

        // Add these two bytes in little endian order.
        msg_bin.extend_with_u8(fr_pt2_b);
        msg_bin.extend_with_u8(fr_pt2_a);

        // Final 4 bytes of Frame
        msg_bin.extend_with_u32(msg.header.frame.source);

        // First, 8 bytes of FrameAddress
        msg_bin.extend_with_u8_array_8(msg.header.frame_address.target);

        // Second, 6 bytes of FrameAddress
        msg_bin.extend_with_u8_array_6(msg.header.frame_address.reserved);

        // Third, 1 byte of FrameAddress
        let bitframeaddress = BitFrameAddress::from(&msg.header.frame_address);

        let mut fa_pt2: [Bit; 8] = [false; 8];
        let rlen = bitframeaddress.reserved_2.len();
        for i in 0..rlen {
            fa_pt2[i] = bitframeaddress.reserved_2[i];
        }
        fa_pt2[rlen + 0] = bitframeaddress.ack_required;
        fa_pt2[rlen + 1] = bitframeaddress.res_required;

        let fa_pt2_byte = RequestBin::bits_to_byte(&fa_pt2);
        msg_bin.extend_with_u8(fa_pt2_byte);

        // Final byte of FrameAddress
        msg_bin.extend_with_u8(msg.header.frame_address.sequence);

        // First 8 bytes of ProtocolHeader
        msg_bin.extend_with_u64(msg.header.protocol_header.reserved);
        // Second, 2 bytes of ProtocolHeader
        msg_bin.extend_with_u16(msg.header.protocol_header.message_type);
        // Final 2 bytes of ProtocolHeader
        msg_bin.extend_with_u16(msg.header.protocol_header.reserved_2);

        // Append payload if required.
        // Payload for 102.
        if msg.header.protocol_header.message_type == 102 {
            msg_bin.extend_with_u8(msg.payload.0[..1][0]);
            let mut p_arr_h = [0u8; 2];
            let mut p_arr_s = [0u8; 2];
            let mut p_arr_b = [0u8; 2];
            let mut p_arr_k = [0u8; 2];
            let mut p_arr_d = [0u8; 4];
            p_arr_h.clone_from_slice(&msg.payload.0[1..3]);
            p_arr_s.clone_from_slice(&msg.payload.0[3..5]);
            p_arr_b.clone_from_slice(&msg.payload.0[5..7]);
            p_arr_k.clone_from_slice(&msg.payload.0[7..9]);
            p_arr_d.clone_from_slice(&msg.payload.0[9..13]);
            msg_bin.extend_with_u8_array_2(p_arr_h);
            msg_bin.extend_with_u8_array_2(p_arr_s);
            msg_bin.extend_with_u8_array_2(p_arr_b);
            msg_bin.extend_with_u8_array_2(p_arr_k);
            msg_bin.extend_with_u8_array_4(p_arr_d);
        }

        // Payload for 21.
        if msg.header.protocol_header.message_type == 21 {
            msg_bin.extend_with_u8(msg.payload.0[..1][0]);
            let mut p_arr_p = [0u8; 2];
            p_arr_p.clone_from_slice(&msg.payload.0[1..3]);
            msg_bin.extend_with_u8_array_2(p_arr_p);
        }

        // Set message size in first 2 bytes of request, Frame.
        let mut p = RequestBin::u16_to_u8_array(msg_bin.0.len() as u16);
        p.reverse();
        msg_bin.0[0] = p[0];
        msg_bin.0[1] = p[1];
        msg_bin
    }
}

impl RequestBin {
    fn bits_to_byte(bits: &[Bit]) -> u8 {
        bits.iter().fold(0, |acc, b| (acc << 1) + if *b { 1 } else { 0 })
    }

    fn extend_with_bool(&mut self, field: bool) {
        // No need to reverse endianness, single byte.
        self.0.extend_from_slice(&RequestBin::bool_to_u8_array(field));
    }

    fn extend_with_u8(&mut self, field: u8) {
        // No need to reverse endianness, single byte.
        self.0.extend_from_slice(&[field]);
    }

    fn extend_with_u8_array_8(&mut self, mut field: [u8; 8]) {
        field.reverse();
        for b in field.iter() {
            self.0.extend_from_slice(&[*b]);
        }
    }

    fn extend_with_u8_array_6(&mut self, mut field: [u8; 6]) {
        field.reverse();
        for b in field.iter() {
            self.0.extend_from_slice(&[*b]);
        }
    }

    fn extend_with_u8_array_4(&mut self, mut field: [u8; 4]) {
        field.reverse();
        for b in field.iter() {
            self.0.extend_from_slice(&[*b]);
        }
    }

    fn extend_with_u8_array_2(&mut self, mut field: [u8; 2]) {
        field.reverse();
        for b in field.iter() {
            self.0.extend_from_slice(&[*b]);
        }
    }

    fn extend_with_u16(&mut self, field: u16) {
        let mut p = RequestBin::u16_to_u8_array(field);
        p.reverse();
        self.0.extend_from_slice(&p);
    }

    fn extend_with_u32(&mut self, field: u32) {
        let mut p = RequestBin::u32_to_u8_array(field);
        p.reverse();
        self.0.extend_from_slice(&p);
    }

    fn extend_with_u64(&mut self, field: u64) {
        let mut p = RequestBin::u64_to_u8_array(field);
        p.reverse();
        self.0.extend_from_slice(&p);
    }

    fn bool_to_u8_array(b: bool) -> [u8; 1] {
        match b {
            true => [1],
            false => [0],
        }
    }

    pub fn u16_to_u8_array(x: u16) -> [u8; 2] {
        let b1: u8 = ((x >> 8) & 0xff) as u8;
        let b2: u8 = (x & 0xff) as u8;
        [b1, b2]
    }

    pub fn u32_to_u8_array(x: u32) -> [u8; 4] {
        let b1: u8 = ((x >> 24) & 0xff) as u8;
        let b2: u8 = ((x >> 16) & 0xff) as u8;
        let b3: u8 = ((x >> 8) & 0xff) as u8;
        let b4: u8 = (x & 0xff) as u8;
        [b1, b2, b3, b4]
    }

    fn u64_to_u8_array(x: u64) -> [u8; 8] {
        let b1: u8 = ((x >> 56) & 0xff) as u8;
        let b2: u8 = ((x >> 48) & 0xff) as u8;
        let b3: u8 = ((x >> 40) & 0xff) as u8;
        let b4: u8 = ((x >> 32) & 0xff) as u8;
        let b5: u8 = ((x >> 24) & 0xff) as u8;
        let b6: u8 = ((x >> 16) & 0xff) as u8;
        let b7: u8 = ((x >> 8) & 0xff) as u8;
        let b8: u8 = (x & 0xff) as u8;
        [b1, b2, b3, b4, b5, b6, b7, b8]
    }
}

<commit_msg>Tidy.<commit_after>#![allow(dead_code)]

type Bit = bool;

#[derive(Debug)]
pub struct Request {
    header: Header,
    payload: Payload,
}

impl Request {
    pub fn new(header: Header, payload: Payload) -> Request {
        Request {
            header,
            payload,
        }
    }
}

#[derive(Debug)]
pub struct Payload(pub Vec<u8>);

// RequestBin newtype
pub struct RequestBin(pub Vec<u8>);

#[derive(Debug)]
pub struct Header {
    frame: Frame,
    frame_address: FrameAddress,
    protocol_header: ProtocolHeader,
}

impl Header {
    pub fn new(frame: Frame,
               frame_address: FrameAddress,
               protocol_header: ProtocolHeader)
               -> Header {
        Header {
            frame,
            frame_address,
            protocol_header,
        }
    }
}

#[derive(Debug)]
pub struct Frame {
    // First 2 bytes
    size: u16,

    // Second two bytes
    origin: u8,
    // For discovery using Device::GetService use true and target all zeroes.
    // For all other requests set to false and target to device MAC address.
    tagged: bool,
    addressable: bool, // Must be true
    protocol: u16, // Must be 1024

    // Final 4 bytes
    source: u32,
}

impl Frame {
    pub fn new(origin: u8, tagged: bool, addressable: bool, protocol: u16, source: u32) -> Frame {
        Frame {
            size: 0,
            origin,
            tagged,
            addressable,
            protocol,
            source,
        }
    }
}

#[derive(Debug)]
pub struct FrameAddress {
    // MAC address (6 bytes) left-justified with two 0 bytes, or all 0s for all devices
    target: [u8; 8],
    reserved: [u8; 6],
    reserved_2: u8,
    ack_required: bool,
    res_required: bool,
    sequence: u8,
}

impl FrameAddress {
    pub fn new(target: [u8; 8],
               reserved: [u8; 6],
               reserved_2: u8,
               ack_required: bool,
               res_required: bool,
               sequence: u8)
               -> FrameAddress {
        FrameAddress {
            target,
            reserved,
            reserved_2,
            ack_required,
            res_required,
            sequence,
        }
    }
}

#[derive(Debug)]
pub struct ProtocolHeader {
    reserved: u64,
    message_type: u16,
    reserved_2: u16,
}

impl ProtocolHeader {
    pub fn new(reserved: u64, message_type: u16, reserved_2: u16) -> ProtocolHeader {
        ProtocolHeader {
            reserved,
            message_type,
            reserved_2,
        }
    }
}

// BitFrame is an intermediate representation.
struct BitFrame {
    // First 2 bytes
    size: u16,

    // Second two bytes
    origin: BitOrigin,

    // For discovery using Device::GetService use true and target all zeroes.
    // For all other requests set to false and target to device MAC address.
    tagged: Bit,
    addressable: Bit, // Must be true
    protocol: BitProtocol, // Must be 1024

    // Final 4 bytes
    source: u32,
}

impl<'a> From<&'a Frame> for BitFrame {
    fn from(f: &Frame) -> BitFrame {
        BitFrame {
            // First two bytes
            size: f.size,

            // Second two bytes
            origin: BitOrigin::from(f.origin),
            tagged: f.tagged,
            addressable: f.addressable,
            protocol: BitProtocol::from(f.protocol),

            // Final four bytes
            source: f.source,
        }
    }
}

// BitOrigin newtype
struct BitOrigin([Bit; 2]);

impl From<u8> for BitOrigin {
    // Format as zero padded boolean string.
    // Convert boolean string to vec of bools
    fn from(o: u8) -> BitOrigin {
        let s = format!("{:02b}", o);
        let v: Vec<Bit> = s.as_bytes()
            .iter()
            .map(|&n| n == 49)
            .collect();
        BitOrigin([v[0], v[1]])
    }
}

// BitProtocol newtype
struct BitProtocol([Bit; 12]);

impl From<u16> for BitProtocol {
    fn from(p: u16) -> BitProtocol {
        let s = format!("{:012b}", p);
        let v: Vec<Bit> = s.as_bytes()
            .iter()
            .map(|&n| n == 49)
            .collect();
        BitProtocol([v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11]])
    }
}

struct BitFrameAddress {
    // MAC address (6 bytes) left-justified with two 0 bytes, or all 0s for all devices
    target: [u8; 8],
    reserved: [u8; 6],
    reserved_2: [Bit; 6],
    ack_required: Bit,
    res_required: Bit,
    sequence: u8,
}

impl<'a> From<&'a FrameAddress> for BitFrameAddress {
    fn from(f: &FrameAddress) -> BitFrameAddress {
        BitFrameAddress {
            target: f.target,
            reserved: f.reserved,
            reserved_2: {
                let s = format!("{:06b}", f.reserved_2);
                let v: Vec<bool> = s.as_bytes()
                    .iter()
                    .map(|&n| n == 49)
                    .collect();
                let a: [Bit; 6] = [v[0], v[1], v[2], v[3], v[4], v[5]];
                a
            },
            ack_required: f.ack_required,
            res_required: f.res_required,
            sequence: f.sequence,
        }
    }
}

impl From<Request> for RequestBin {
    fn from(msg: Request) -> RequestBin {
        let mut msg_bin = RequestBin(vec![]);

        // First 2 bytes of Frame
        msg_bin.extend_with_u16(msg.header.frame.size);

        // Second 2 bytes of Frame
        let bitframe = BitFrame::from(&msg.header.frame);

        let mut fr_pt2: [Bit; 16] = [false; 16];
        fr_pt2[0] = bitframe.origin.0[0];
        fr_pt2[1] = bitframe.origin.0[1];
        fr_pt2[2] = bitframe.tagged;
        fr_pt2[3] = bitframe.addressable;
        fr_pt2[4..(bitframe.protocol.0.len() + 4)].clone_from_slice(&bitframe.protocol.0[..]);

        let (fr_pt2_a_bits, fr_pt2_b_bits) = fr_pt2.split_at(8);
        let fr_pt2_a = RequestBin::bits_to_byte(fr_pt2_a_bits);
        let fr_pt2_b = RequestBin::bits_to_byte(fr_pt2_b_bits);

        // Add these two bytes in little endian order.
        msg_bin.extend_with_u8(fr_pt2_b);
        msg_bin.extend_with_u8(fr_pt2_a);

        // Final 4 bytes of Frame
        msg_bin.extend_with_u32(msg.header.frame.source);

        // First, 8 bytes of FrameAddress
        msg_bin.extend_with_u8_array_8(msg.header.frame_address.target);

        // Second, 6 bytes of FrameAddress
        msg_bin.extend_with_u8_array_6(msg.header.frame_address.reserved);

        // Third, 1 byte of FrameAddress
        let bitframeaddress = BitFrameAddress::from(&msg.header.frame_address);

        let mut fa_pt2: [Bit; 8] = [false; 8];
        let rlen = bitframeaddress.reserved_2.len();

        fa_pt2[..rlen].clone_from_slice(&bitframeaddress.reserved_2[..rlen]);

        fa_pt2[rlen + 0] = bitframeaddress.ack_required;
        fa_pt2[rlen + 1] = bitframeaddress.res_required;

        let fa_pt2_byte = RequestBin::bits_to_byte(&fa_pt2);
        msg_bin.extend_with_u8(fa_pt2_byte);

        // Final byte of FrameAddress
        msg_bin.extend_with_u8(msg.header.frame_address.sequence);

        // First 8 bytes of ProtocolHeader
        msg_bin.extend_with_u64(msg.header.protocol_header.reserved);
        // Second, 2 bytes of ProtocolHeader
        msg_bin.extend_with_u16(msg.header.protocol_header.message_type);
        // Final 2 bytes of ProtocolHeader
        msg_bin.extend_with_u16(msg.header.protocol_header.reserved_2);

        // Append payload if required.
        // Payload for 102.
        if msg.header.protocol_header.message_type == 102 {
            msg_bin.extend_with_u8(msg.payload.0[..1][0]);
            let mut p_arr_h = [0u8; 2];
            let mut p_arr_s = [0u8; 2];
            let mut p_arr_b = [0u8; 2];
            let mut p_arr_k = [0u8; 2];
            let mut p_arr_d = [0u8; 4];
            p_arr_h.clone_from_slice(&msg.payload.0[1..3]);
            p_arr_s.clone_from_slice(&msg.payload.0[3..5]);
            p_arr_b.clone_from_slice(&msg.payload.0[5..7]);
            p_arr_k.clone_from_slice(&msg.payload.0[7..9]);
            p_arr_d.clone_from_slice(&msg.payload.0[9..13]);
            msg_bin.extend_with_u8_array_2(p_arr_h);
            msg_bin.extend_with_u8_array_2(p_arr_s);
            msg_bin.extend_with_u8_array_2(p_arr_b);
            msg_bin.extend_with_u8_array_2(p_arr_k);
            msg_bin.extend_with_u8_array_4(p_arr_d);
        }

        // Payload for 21.
        if msg.header.protocol_header.message_type == 21 {
            msg_bin.extend_with_u8(msg.payload.0[..1][0]);
            let mut p_arr_p = [0u8; 2];
            p_arr_p.clone_from_slice(&msg.payload.0[1..3]);
            msg_bin.extend_with_u8_array_2(p_arr_p);
        }

        // Set message size in first 2 bytes of request, Frame.
        let mut p = RequestBin::u16_to_u8_array(msg_bin.0.len() as u16);
        p.reverse();
        msg_bin.0[0] = p[0];
        msg_bin.0[1] = p[1];
        msg_bin
    }
}

impl RequestBin {
    fn bits_to_byte(bits: &[Bit]) -> u8 {
        bits.iter().fold(0, |acc, b| (acc << 1) + if *b { 1 } else { 0 })
    }

    fn extend_with_bool(&mut self, field: bool) {
        // No need to reverse endianness, single byte.
        self.0.extend_from_slice(&RequestBin::bool_to_u8_array(field));
    }

    fn extend_with_u8(&mut self, field: u8) {
        // No need to reverse endianness, single byte.
        self.0.extend_from_slice(&[field]);
    }

    fn extend_with_u8_array_8(&mut self, mut field: [u8; 8]) {
        field.reverse();
        for b in field.iter() {
            self.0.extend_from_slice(&[*b]);
        }
    }

    fn extend_with_u8_array_6(&mut self, mut field: [u8; 6]) {
        field.reverse();
        for b in field.iter() {
            self.0.extend_from_slice(&[*b]);
        }
    }

    fn extend_with_u8_array_4(&mut self, mut field: [u8; 4]) {
        field.reverse();
        for b in field.iter() {
            self.0.extend_from_slice(&[*b]);
        }
    }

    fn extend_with_u8_array_2(&mut self, mut field: [u8; 2]) {
        field.reverse();
        for b in field.iter() {
            self.0.extend_from_slice(&[*b]);
        }
    }

    fn extend_with_u16(&mut self, field: u16) {
        let mut p = RequestBin::u16_to_u8_array(field);
        p.reverse();
        self.0.extend_from_slice(&p);
    }

    fn extend_with_u32(&mut self, field: u32) {
        let mut p = RequestBin::u32_to_u8_array(field);
        p.reverse();
        self.0.extend_from_slice(&p);
    }

    fn extend_with_u64(&mut self, field: u64) {
        let mut p = RequestBin::u64_to_u8_array(field);
        p.reverse();
        self.0.extend_from_slice(&p);
    }

    fn bool_to_u8_array(b: bool) -> [u8; 1] {
        if b { [1] } else { [0] }
    }

    pub fn u16_to_u8_array(x: u16) -> [u8; 2] {
        let b1: u8 = ((x >> 8) & 0xff) as u8;
        let b2: u8 = (x & 0xff) as u8;
        [b1, b2]
    }

    pub fn u32_to_u8_array(x: u32) -> [u8; 4] {
        let b1: u8 = ((x >> 24) & 0xff) as u8;
        let b2: u8 = ((x >> 16) & 0xff) as u8;
        let b3: u8 = ((x >> 8) & 0xff) as u8;
        let b4: u8 = (x & 0xff) as u8;
        [b1, b2, b3, b4]
    }

    fn u64_to_u8_array(x: u64) -> [u8; 8] {
        let b1: u8 = ((x >> 56) & 0xff) as u8;
        let b2: u8 = ((x >> 48) & 0xff) as u8;
        let b3: u8 = ((x >> 40) & 0xff) as u8;
        let b4: u8 = ((x >> 32) & 0xff) as u8;
        let b5: u8 = ((x >> 24) & 0xff) as u8;
        let b6: u8 = ((x >> 16) & 0xff) as u8;
        let b7: u8 = ((x >> 8) & 0xff) as u8;
        let b8: u8 = (x & 0xff) as u8;
        [b1, b2, b3, b4, b5, b6, b7, b8]
    }
}

<|endoftext|>


<commit_before>use std::fmt;
use lexer::reader::{CodeReader,StrReader,FileReader};
use lexer::token::{Token,TokenType};
use lexer::position::Position;
use error::{ParseError,ErrorCode};

pub mod reader;
pub mod token;
pub mod position;

struct CharPos {
    value: char,
    position: Position
}

impl fmt::Show for CharPos {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "char {} at line {:?}", self.value, self.position)
    }
}

impl Copy for CharPos {}

pub struct Lexer<T : CodeReader> {
    reader: T,
    position: Position,

    buffer: Vec<CharPos>,
    eof_reached: bool
}

impl Lexer<StrReader> {
    pub fn from_str(code: &'static str) -> Lexer<StrReader> {
        Lexer::new(StrReader::new(code))
    }
}

impl Lexer<StrReader> {
    pub fn from_file(filename: &'static str) -> Lexer<FileReader> {
        Lexer::new(FileReader::new(filename))
    }
}

impl<T : CodeReader> Lexer<T> {
    pub fn new(reader : T) -> Lexer<T> {
        let mut lexer = Lexer::<T> {
            reader: reader,
            position: Position::new(1, 1),
            buffer: Vec::with_capacity(10),
            eof_reached: false
        };
        lexer.fill_buffer();

        lexer
    }

    pub fn read_token(&mut self) -> Result<Token,ParseError> {
        loop {
            self.skip_white();

            if self.top().is_none() {
                return Ok(Token::new(TokenType::End, self.position));
            }

            if self.is_digit() {
                return self.read_number();

            } else if self.is_comment_start() {
                match self.read_comment() {
                    Some(err) => return Err(err),
                    _ => {}
                }

            } else if self.is_multi_comment_start() {
                match self.read_multi_comment() {
                    Some(err) => return Err(err),
                    _ => {}
                }

            } else {
                return Err( ParseError {
                  filename: self.reader.filename().to_string(),
                  position: self.position,
                  code: ErrorCode::UnknownChar,
                  message: "not implemented".to_string()
                } )
            }
        }
    }

    fn skip_white(&mut self) {
        while self.is_whitespace() {
            self.read_char();
        }
    }

    fn read_comment(&mut self) -> Option<ParseError> {
        while self.top().is_some() && !self.is_newline() {
            self.read_char();
        }

        None
    }

    fn read_multi_comment(&mut self) -> Option<ParseError> {
        let pos = self.top().unwrap().position;

        self.read_char();
        self.read_char();

        while self.top().is_some() && !self.is_multi_comment_end() {
          self.read_char();
        }

        if self.top().is_none() {
          return Some(ParseError {
              filename: self.reader.filename().to_string(),
              position: pos,
              code: ErrorCode::UnclosedComment,
              message: "unclosed comment".to_string()
          } );
        }

        self.read_char();
        self.read_char();

        None
    }

    fn read_number(&mut self) -> Result<Token,ParseError> {
        let mut tok = self.build_token(TokenType::Number);

        while self.is_digit() {
            let ch = self.read_char().unwrap().value;
            tok.value.push(ch);
        }

        Ok(tok)
    }

    fn read_char(&mut self) -> Option<CharPos> {
        if self.buffer.len() > 0 {
            let ch = self.buffer.remove(0);
            self.fill_buffer();

            Some(ch)
        } else {
            None
        }
    }

    fn top(&self) -> Option<CharPos> {
        self.at(0)
    }

    fn at(&self, index: usize) -> Option<CharPos> {
        if self.buffer.len() > index {
            Some(self.buffer[index])
        } else {
            None
        }
    }

    fn build_token(&self, ttype: TokenType) -> Token {
        Token::new(ttype, self.top().unwrap().position)
    }

    fn fill_buffer(&mut self) {
        while !self.eof_reached && self.buffer.len() < 10 {
            let ch = self.reader.read_char();

            if ch.is_some() {
                let ch = ch.unwrap();
                self.buffer.push(CharPos { value: ch, position: self.position });

                if ch == '\n' {
                    self.position.line += 1;
                    self.position.column = 1;
                } else {
                    self.position.column += 1;
                }
            } else {
                self.eof_reached = true;
            }
        }
    }

    fn is_comment_start(&self) -> bool {
        let top = self.top();
        let ntop = self.at(1);

        top.is_some() && top.unwrap().value == '/' &&
            ntop.is_some() && ntop.unwrap().value == '/'
    }

    fn is_multi_comment_start(&self) -> bool {
        let top = self.top();
        let ntop = self.at(1);

        top.is_some() && top.unwrap().value == '/' &&
            ntop.is_some() && ntop.unwrap().value == '*'
    }

    fn is_multi_comment_end(&self) -> bool {
        let top = self.top();
        let ntop = self.at(1);

        top.is_some() && top.unwrap().value == '*' &&
            ntop.is_some() && ntop.unwrap().value == '/'
    }

    fn is_digit(&self) -> bool {
        let top = self.top();

        top.is_some() && top.unwrap().value.is_digit(10)
    }

    fn is_whitespace(&self) -> bool {
        let top = self.top();

        top.is_some() && top.unwrap().value.is_whitespace()
    }

    fn is_newline(&self) -> bool {
        let top = self.top();

        top.is_some() && top.unwrap().value == '\n'
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use lexer::reader::StrReader;
    use lexer::token::TokenType;
    use error::ErrorCode;

    fn assert_end(reader: &mut Lexer<StrReader>, l: u32, c: u32) {
        assert_tok(reader, TokenType::End, "", l, c);
    }

    fn assert_tok(reader: &mut Lexer<StrReader>, ttype: TokenType, val: &'static str, l: u32, c: u32) {
        let tok = reader.read_token().unwrap();
        assert_eq!(ttype, tok.ttype);
        assert_eq!(val, tok.value);
        assert_eq!(l, tok.position.line);
        assert_eq!(c, tok.position.column);
    }

    fn assert_err(reader: &mut Lexer<StrReader>, code: ErrorCode, l: u32, c: u32) {
        let err = reader.read_token().unwrap_err();
        assert_eq!(code, err.code);
        assert_eq!(l, err.position.line);
        assert_eq!(c, err.position.column);
    }

    #[test]
    fn test_read_empty_file() {
        let mut reader = Lexer::from_str("");
        assert_end(&mut reader, 1, 1);
        assert_end(&mut reader, 1, 1);
    }

    #[test]
    fn test_read_numbers() {
        let mut reader = Lexer::from_str("1 2\n0123 10");
        assert_tok(&mut reader, TokenType::Number, "1", 1, 1);
        assert_tok(&mut reader, TokenType::Number, "2", 1, 3);
        assert_tok(&mut reader, TokenType::Number, "0123", 2, 1);
        assert_tok(&mut reader, TokenType::Number, "10", 2, 6);
        assert_end(&mut reader, 2, 8);
    }

    #[test]
    fn test_skip_single_line_comment() {
      let mut reader = Lexer::from_str("//test\n1");
      assert_tok(&mut reader, TokenType::Number, "1", 2, 1);
      assert_end(&mut reader, 2, 2);
    }

    #[test]
    fn test_unfinished_line_comment() {
      let mut reader = Lexer::from_str("//abc");
      assert_end(&mut reader, 1, 6);
    }

    #[test]
    fn test_skip_multi_comment() {
      let mut reader = Lexer::from_str("/*test*/1");
      assert_tok(&mut reader, TokenType::Number, "1", 1, 9);
      assert_end(&mut reader, 1, 10);
    }

    #[test]
    fn test_unfinished_multi_comment() {
        let mut reader = Lexer::from_str("/*test");
        assert_err(&mut reader, ErrorCode::UnclosedComment, 1, 1);
    }
}

<commit_msg>extended multi line comment test<commit_after>use std::fmt;
use lexer::reader::{CodeReader,StrReader,FileReader};
use lexer::token::{Token,TokenType};
use lexer::position::Position;
use error::{ParseError,ErrorCode};

pub mod reader;
pub mod token;
pub mod position;

struct CharPos {
    value: char,
    position: Position
}

impl fmt::Show for CharPos {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "char {} at line {:?}", self.value, self.position)
    }
}

impl Copy for CharPos {}

pub struct Lexer<T : CodeReader> {
    reader: T,
    position: Position,

    buffer: Vec<CharPos>,
    eof_reached: bool
}

impl Lexer<StrReader> {
    pub fn from_str(code: &'static str) -> Lexer<StrReader> {
        Lexer::new(StrReader::new(code))
    }
}

impl Lexer<StrReader> {
    pub fn from_file(filename: &'static str) -> Lexer<FileReader> {
        Lexer::new(FileReader::new(filename))
    }
}

impl<T : CodeReader> Lexer<T> {
    pub fn new(reader : T) -> Lexer<T> {
        let mut lexer = Lexer::<T> {
            reader: reader,
            position: Position::new(1, 1),
            buffer: Vec::with_capacity(10),
            eof_reached: false
        };
        lexer.fill_buffer();

        lexer
    }

    pub fn read_token(&mut self) -> Result<Token,ParseError> {
        loop {
            self.skip_white();

            if self.top().is_none() {
                return Ok(Token::new(TokenType::End, self.position));
            }

            if self.is_digit() {
                return self.read_number();

            } else if self.is_comment_start() {
                match self.read_comment() {
                    Some(err) => return Err(err),
                    _ => {}
                }

            } else if self.is_multi_comment_start() {
                match self.read_multi_comment() {
                    Some(err) => return Err(err),
                    _ => {}
                }

            } else {
                return Err( ParseError {
                  filename: self.reader.filename().to_string(),
                  position: self.position,
                  code: ErrorCode::UnknownChar,
                  message: "not implemented".to_string()
                } )
            }
        }
    }

    fn skip_white(&mut self) {
        while self.is_whitespace() {
            self.read_char();
        }
    }

    fn read_comment(&mut self) -> Option<ParseError> {
        while self.top().is_some() && !self.is_newline() {
            self.read_char();
        }

        None
    }

    fn read_multi_comment(&mut self) -> Option<ParseError> {
        let pos = self.top().unwrap().position;

        self.read_char();
        self.read_char();

        while self.top().is_some() && !self.is_multi_comment_end() {
          self.read_char();
        }

        if self.top().is_none() {
          return Some(ParseError {
              filename: self.reader.filename().to_string(),
              position: pos,
              code: ErrorCode::UnclosedComment,
              message: "unclosed comment".to_string()
          } );
        }

        self.read_char();
        self.read_char();

        None
    }

    fn read_number(&mut self) -> Result<Token,ParseError> {
        let mut tok = self.build_token(TokenType::Number);

        while self.is_digit() {
            let ch = self.read_char().unwrap().value;
            tok.value.push(ch);
        }

        Ok(tok)
    }

    fn read_char(&mut self) -> Option<CharPos> {
        if self.buffer.len() > 0 {
            let ch = self.buffer.remove(0);
            self.fill_buffer();

            Some(ch)
        } else {
            None
        }
    }

    fn top(&self) -> Option<CharPos> {
        self.at(0)
    }

    fn at(&self, index: usize) -> Option<CharPos> {
        if self.buffer.len() > index {
            Some(self.buffer[index])
        } else {
            None
        }
    }

    fn build_token(&self, ttype: TokenType) -> Token {
        Token::new(ttype, self.top().unwrap().position)
    }

    fn fill_buffer(&mut self) {
        while !self.eof_reached && self.buffer.len() < 10 {
            let ch = self.reader.read_char();

            if ch.is_some() {
                let ch = ch.unwrap();
                self.buffer.push(CharPos { value: ch, position: self.position });

                if ch == '\n' {
                    self.position.line += 1;
                    self.position.column = 1;
                } else {
                    self.position.column += 1;
                }
            } else {
                self.eof_reached = true;
            }
        }
    }

    fn is_comment_start(&self) -> bool {
        let top = self.top();
        let ntop = self.at(1);

        top.is_some() && top.unwrap().value == '/' &&
            ntop.is_some() && ntop.unwrap().value == '/'
    }

    fn is_multi_comment_start(&self) -> bool {
        let top = self.top();
        let ntop = self.at(1);

        top.is_some() && top.unwrap().value == '/' &&
            ntop.is_some() && ntop.unwrap().value == '*'
    }

    fn is_multi_comment_end(&self) -> bool {
        let top = self.top();
        let ntop = self.at(1);

        top.is_some() && top.unwrap().value == '*' &&
            ntop.is_some() && ntop.unwrap().value == '/'
    }

    fn is_digit(&self) -> bool {
        let top = self.top();

        top.is_some() && top.unwrap().value.is_digit(10)
    }

    fn is_whitespace(&self) -> bool {
        let top = self.top();

        top.is_some() && top.unwrap().value.is_whitespace()
    }

    fn is_newline(&self) -> bool {
        let top = self.top();

        top.is_some() && top.unwrap().value == '\n'
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use lexer::reader::StrReader;
    use lexer::token::TokenType;
    use error::ErrorCode;

    fn assert_end(reader: &mut Lexer<StrReader>, l: u32, c: u32) {
        assert_tok(reader, TokenType::End, "", l, c);
    }

    fn assert_tok(reader: &mut Lexer<StrReader>, ttype: TokenType, val: &'static str, l: u32, c: u32) {
        let tok = reader.read_token().unwrap();
        assert_eq!(ttype, tok.ttype);
        assert_eq!(val, tok.value);
        assert_eq!(l, tok.position.line);
        assert_eq!(c, tok.position.column);
    }

    fn assert_err(reader: &mut Lexer<StrReader>, code: ErrorCode, l: u32, c: u32) {
        let err = reader.read_token().unwrap_err();
        assert_eq!(code, err.code);
        assert_eq!(l, err.position.line);
        assert_eq!(c, err.position.column);
    }

    #[test]
    fn test_read_empty_file() {
        let mut reader = Lexer::from_str("");
        assert_end(&mut reader, 1, 1);
        assert_end(&mut reader, 1, 1);
    }

    #[test]
    fn test_read_numbers() {
        let mut reader = Lexer::from_str("1 2\n0123 10");
        assert_tok(&mut reader, TokenType::Number, "1", 1, 1);
        assert_tok(&mut reader, TokenType::Number, "2", 1, 3);
        assert_tok(&mut reader, TokenType::Number, "0123", 2, 1);
        assert_tok(&mut reader, TokenType::Number, "10", 2, 6);
        assert_end(&mut reader, 2, 8);
    }

    #[test]
    fn test_skip_single_line_comment() {
      let mut reader = Lexer::from_str("//test\n1");
      assert_tok(&mut reader, TokenType::Number, "1", 2, 1);
      assert_end(&mut reader, 2, 2);
    }

    #[test]
    fn test_unfinished_line_comment() {
      let mut reader = Lexer::from_str("//abc");
      assert_end(&mut reader, 1, 6);
    }

    #[test]
    fn test_skip_multi_comment() {
      let mut reader = Lexer::from_str("/*test*/1");
      assert_tok(&mut reader, TokenType::Number, "1", 1, 9);
      assert_end(&mut reader, 1, 10);
    }

    #[test]
    fn test_unfinished_multi_comment() {
        let mut reader = Lexer::from_str("/*test");
        assert_err(&mut reader, ErrorCode::UnclosedComment, 1, 1);

        let mut reader = Lexer::from_str("1/*test");
        assert_tok(&mut reader, TokenType::Number, "1", 1, 1);
        assert_err(&mut reader, ErrorCode::UnclosedComment, 1, 2);
    }
}

<|endoftext|>