<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

// SVG 1.1 (Second Edition)
// https://www.w3.org/TR/SVG/
<% data.new_style_struct("InheritedSVG",
                         inherited=True,
                         gecko_name="SVG") %>

// Section 10 - Text

${helpers.single_keyword("text-anchor",
                         "start middle end",
                         products="gecko",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG/text.html#TextAnchorProperty")}

// Section 11 - Painting: Filling, Stroking and Marker Symbols
${helpers.single_keyword("color-interpolation",
                         "srgb auto linearrgb",
                         products="gecko",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperty")}

${helpers.single_keyword("color-interpolation-filters", "linearrgb auto srgb",
                         products="gecko",
                         gecko_constant_prefix="NS_STYLE_COLOR_INTERPOLATION",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationFiltersProperty")}

${helpers.predefined_type(
    "fill", "SVGPaint",
    "::values::computed::SVGPaint::black()",
    products="gecko",
    animation_value_type="IntermediateSVGPaint",
    boxed=True,
    spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingFillPaint")}

${helpers.predefined_type("fill-opacity", "SVGOpacity", "Default::default()",
                          products="gecko", animation_value_type="ComputedValue",
                          spec="https://www.w3.org/TR/SVG11/painting.html#FillOpacityProperty")}

${helpers.single_keyword("fill-rule", "nonzero evenodd",
                         gecko_enum_prefix="StyleFillRule",
                         products="gecko", animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#FillRuleProperty")}

${helpers.single_keyword("shape-rendering",
                         "auto optimizespeed crispedges geometricprecision",
                         products="gecko",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#ShapeRenderingProperty")}

${helpers.predefined_type(
    "stroke", "SVGPaint",
    "Default::default()",
    products="gecko",
    animation_value_type="IntermediateSVGPaint",
    boxed=True,
    spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingStrokePaint")}

${helpers.predefined_type(
    "stroke-width", "SVGWidth",
    "::values::computed::NonNegativeLength::new(1.).into()",
    products="gecko",
    boxed="True",
    animation_value_type="::values::computed::SVGWidth",
    spec="https://www.w3.org/TR/SVG2/painting.html#StrokeWidth")}

${helpers.single_keyword("stroke-linecap", "butt round square",
                         products="gecko", animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty")}

${helpers.single_keyword("stroke-linejoin", "miter round bevel",
                         products="gecko", animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty")}

${helpers.predefined_type("stroke-miterlimit", "GreaterThanOrEqualToOneNumber",
                          "From::from(4.0)",
                          products="gecko",
                          animation_value_type="::values::computed::GreaterThanOrEqualToOneNumber",
                          spec="https://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty")}

${helpers.predefined_type("stroke-opacity", "SVGOpacity", "Default::default()",
                          products="gecko", animation_value_type="ComputedValue",
                          spec="https://www.w3.org/TR/SVG11/painting.html#StrokeOpacityProperty")}

${helpers.predefined_type(
    "stroke-dasharray",
    "SVGStrokeDashArray",
    "Default::default()",
    products="gecko",
    animation_value_type="::values::computed::SVGStrokeDashArray",
    spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing",
)}

${helpers.predefined_type(
    "stroke-dashoffset", "SVGLength",
    "Au(0).into()",
    products="gecko",
    boxed="True",
    animation_value_type="ComputedValue",
    spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing")}

// Section 14 - Clipping, Masking and Compositing
${helpers.single_keyword("clip-rule", "nonzero evenodd",
                         products="gecko",
                         gecko_enum_prefix="StyleFillRule",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/masking.html#ClipRuleProperty")}

${helpers.predefined_type("marker-start", "UrlOrNone", "Either::Second(None_)",
                          products="gecko",
                          boxed="True" if product == "gecko" else "False",
                          animation_value_type="discrete",
                          spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}

${helpers.predefined_type("marker-mid", "UrlOrNone", "Either::Second(None_)",
                          products="gecko",
                          boxed="True" if product == "gecko" else "False",
                          animation_value_type="discrete",
                          spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}

${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)",
                          products="gecko",
                          boxed="True" if product == "gecko" else "False",
                          animation_value_type="discrete",
                          spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}

<%helpers:longhand name="paint-order"
                   animation_value_type="discrete"
                   products="gecko"
                   spec="https://www.w3.org/TR/SVG2/painting.html#PaintOrder">
    use std::fmt;
    use style_traits::ToCss;

    pub const NORMAL: u8 = 0;
    pub const FILL: u8 = 1;
    pub const STROKE: u8 = 2;
    pub const MARKERS: u8 = 3;

    // number of bits for each component
    pub const SHIFT: u8 = 2;
    // mask with above bits set
    pub const MASK: u8 = 0b11;
    // number of non-normal keyword values
    pub const COUNT: u8 = 3;
    // all keywords
    pub const ALL: [u8; 3] = [FILL, STROKE, MARKERS];

    /// Represented as a six-bit field, of 3 two-bit pairs
    ///
    /// Each pair can be set to FILL, STROKE, or MARKERS
    /// Lowest significant bit pairs are highest priority.
    ///  `normal` is the empty bitfield. The three pairs are
    /// never zero in any case other than `normal`.
    ///
    /// Higher priority values, i.e. the values specified first,
    /// will be painted first (and may be covered by paintings of lower priority)
    #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
    #[derive(Clone, Copy, Debug, PartialEq, ToComputedValue)]
    pub struct SpecifiedValue(pub u8);

    pub mod computed_value {
        pub use super::SpecifiedValue as T;
    }

    pub fn get_initial_value() -> SpecifiedValue {
      SpecifiedValue(NORMAL)
    }

    impl SpecifiedValue {
        pub fn bits_at(&self, pos: u8) -> u8 {
            (self.0 >> pos * SHIFT) & MASK
        }
    }

    pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
                         -> Result<SpecifiedValue,ParseError<'i>> {
        if let Ok(()) = input.try(|i| i.expect_ident_matching("normal")) {
            Ok(SpecifiedValue(0))
        } else {
            let mut value = 0;
            // bitfield representing what we've seen so far
            // bit 1 is fill, bit 2 is stroke, bit 3 is markers
            let mut seen = 0;
            let mut pos = 0;

            loop {
                let result: Result<_, ParseError> = input.try(|i| {
                    try_match_ident_ignore_ascii_case! { i.expect_ident()?,
                        "fill" => Ok(FILL),
                        "stroke" => Ok(STROKE),
                        "markers" => Ok(MARKERS),
                    }
                });

                match result {
                    Ok(val) => {
                        if (seen & (1 << val)) != 0 {
                            // don't parse the same ident twice
                            return Err(StyleParseError::UnspecifiedError.into())
                        } else {
                            value |= val << (pos * SHIFT);
                            seen |= 1 << val;
                            pos += 1;
                        }
                    }
                    Err(_) => break,
                }
            }

            if value == 0 {
                // couldn't find any keyword
                Err(StyleParseError::UnspecifiedError.into())
            } else {
                // fill in rest
                for i in pos..COUNT {
                    for paint in &ALL {
                        // if not seen, set bit at position, mark as seen
                        if (seen & (1 << paint)) == 0 {
                            seen |= 1 << paint;
                            value |= paint << (i * SHIFT);
                            break;
                        }
                    }
                }

                Ok(SpecifiedValue(value))
            }
        }
    }

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            if self.0 == 0 {
                return dest.write_str("normal")
            }

            for pos in 0..COUNT {
                if pos != 0 {
                    dest.write_str(" ")?
                }
                match self.bits_at(pos) {
                    FILL => dest.write_str("fill")?,
                    STROKE => dest.write_str("stroke")?,
                    MARKERS => dest.write_str("markers")?,
                    _ => unreachable!(),
                }
            }
            Ok(())
        }
    }
</%helpers:longhand>

<%helpers:vector_longhand name="-moz-context-properties"
                   animation_value_type="none"
                   products="gecko"
                   spec="Nonstandard (Internal-only)"
                   allow_empty="True">
    use values::CustomIdent;

    pub type SpecifiedValue = CustomIdent;

    pub mod computed_value {
        pub type T = super::SpecifiedValue;
    }

    pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
                         -> Result<SpecifiedValue, ParseError<'i>> {
        let i = input.expect_ident()?;
        CustomIdent::from_ident(i, &["all", "none", "auto"])
    }
</%helpers:vector_longhand>
<commit_msg>style: Early return in a couple of places to deindent some code.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

// SVG 1.1 (Second Edition)
// https://www.w3.org/TR/SVG/
<% data.new_style_struct("InheritedSVG",
                         inherited=True,
                         gecko_name="SVG") %>

// Section 10 - Text

${helpers.single_keyword("text-anchor",
                         "start middle end",
                         products="gecko",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG/text.html#TextAnchorProperty")}

// Section 11 - Painting: Filling, Stroking and Marker Symbols
${helpers.single_keyword("color-interpolation",
                         "srgb auto linearrgb",
                         products="gecko",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperty")}

${helpers.single_keyword("color-interpolation-filters", "linearrgb auto srgb",
                         products="gecko",
                         gecko_constant_prefix="NS_STYLE_COLOR_INTERPOLATION",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationFiltersProperty")}

${helpers.predefined_type(
    "fill", "SVGPaint",
    "::values::computed::SVGPaint::black()",
    products="gecko",
    animation_value_type="IntermediateSVGPaint",
    boxed=True,
    spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingFillPaint")}

${helpers.predefined_type("fill-opacity", "SVGOpacity", "Default::default()",
                          products="gecko", animation_value_type="ComputedValue",
                          spec="https://www.w3.org/TR/SVG11/painting.html#FillOpacityProperty")}

${helpers.single_keyword("fill-rule", "nonzero evenodd",
                         gecko_enum_prefix="StyleFillRule",
                         products="gecko", animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#FillRuleProperty")}

${helpers.single_keyword("shape-rendering",
                         "auto optimizespeed crispedges geometricprecision",
                         products="gecko",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#ShapeRenderingProperty")}

${helpers.predefined_type(
    "stroke", "SVGPaint",
    "Default::default()",
    products="gecko",
    animation_value_type="IntermediateSVGPaint",
    boxed=True,
    spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingStrokePaint")}

${helpers.predefined_type(
    "stroke-width", "SVGWidth",
    "::values::computed::NonNegativeLength::new(1.).into()",
    products="gecko",
    boxed="True",
    animation_value_type="::values::computed::SVGWidth",
    spec="https://www.w3.org/TR/SVG2/painting.html#StrokeWidth")}

${helpers.single_keyword("stroke-linecap", "butt round square",
                         products="gecko", animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty")}

${helpers.single_keyword("stroke-linejoin", "miter round bevel",
                         products="gecko", animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty")}

${helpers.predefined_type("stroke-miterlimit", "GreaterThanOrEqualToOneNumber",
                          "From::from(4.0)",
                          products="gecko",
                          animation_value_type="::values::computed::GreaterThanOrEqualToOneNumber",
                          spec="https://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty")}

${helpers.predefined_type("stroke-opacity", "SVGOpacity", "Default::default()",
                          products="gecko", animation_value_type="ComputedValue",
                          spec="https://www.w3.org/TR/SVG11/painting.html#StrokeOpacityProperty")}

${helpers.predefined_type(
    "stroke-dasharray",
    "SVGStrokeDashArray",
    "Default::default()",
    products="gecko",
    animation_value_type="::values::computed::SVGStrokeDashArray",
    spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing",
)}

${helpers.predefined_type(
    "stroke-dashoffset", "SVGLength",
    "Au(0).into()",
    products="gecko",
    boxed="True",
    animation_value_type="ComputedValue",
    spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing")}

// Section 14 - Clipping, Masking and Compositing
${helpers.single_keyword("clip-rule", "nonzero evenodd",
                         products="gecko",
                         gecko_enum_prefix="StyleFillRule",
                         animation_value_type="discrete",
                         spec="https://www.w3.org/TR/SVG11/masking.html#ClipRuleProperty")}

${helpers.predefined_type("marker-start", "UrlOrNone", "Either::Second(None_)",
                          products="gecko",
                          boxed="True" if product == "gecko" else "False",
                          animation_value_type="discrete",
                          spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}

${helpers.predefined_type("marker-mid", "UrlOrNone", "Either::Second(None_)",
                          products="gecko",
                          boxed="True" if product == "gecko" else "False",
                          animation_value_type="discrete",
                          spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}

${helpers.predefined_type("marker-end", "UrlOrNone", "Either::Second(None_)",
                          products="gecko",
                          boxed="True" if product == "gecko" else "False",
                          animation_value_type="discrete",
                          spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties")}

<%helpers:longhand name="paint-order"
                   animation_value_type="discrete"
                   products="gecko"
                   spec="https://www.w3.org/TR/SVG2/painting.html#PaintOrder">
    use std::fmt;
    use style_traits::ToCss;

    pub const NORMAL: u8 = 0;
    pub const FILL: u8 = 1;
    pub const STROKE: u8 = 2;
    pub const MARKERS: u8 = 3;

    // number of bits for each component
    pub const SHIFT: u8 = 2;
    // mask with above bits set
    pub const MASK: u8 = 0b11;
    // number of non-normal keyword values
    pub const COUNT: u8 = 3;
    // all keywords
    pub const ALL: [u8; 3] = [FILL, STROKE, MARKERS];

    /// Represented as a six-bit field, of 3 two-bit pairs
    ///
    /// Each pair can be set to FILL, STROKE, or MARKERS
    /// Lowest significant bit pairs are highest priority.
    ///  `normal` is the empty bitfield. The three pairs are
    /// never zero in any case other than `normal`.
    ///
    /// Higher priority values, i.e. the values specified first,
    /// will be painted first (and may be covered by paintings of lower priority)
    #[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
    #[derive(Clone, Copy, Debug, PartialEq, ToComputedValue)]
    pub struct SpecifiedValue(pub u8);

    pub mod computed_value {
        pub use super::SpecifiedValue as T;
    }

    pub fn get_initial_value() -> SpecifiedValue {
      SpecifiedValue(NORMAL)
    }

    impl SpecifiedValue {
        pub fn bits_at(&self, pos: u8) -> u8 {
            (self.0 >> pos * SHIFT) & MASK
        }
    }

    pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
                         -> Result<SpecifiedValue,ParseError<'i>> {
        if let Ok(()) = input.try(|i| i.expect_ident_matching("normal")) {
            return Ok(SpecifiedValue(0))
        }

        let mut value = 0;
        // bitfield representing what we've seen so far
        // bit 1 is fill, bit 2 is stroke, bit 3 is markers
        let mut seen = 0;
        let mut pos = 0;

        loop {
            let result: Result<_, ParseError> = input.try(|i| {
                try_match_ident_ignore_ascii_case! { i.expect_ident()?,
                    "fill" => Ok(FILL),
                    "stroke" => Ok(STROKE),
                    "markers" => Ok(MARKERS),
                }
            });

            match result {
                Ok(val) => {
                    if (seen & (1 << val)) != 0 {
                        // don't parse the same ident twice
                        return Err(StyleParseError::UnspecifiedError.into())
                    }

                    value |= val << (pos * SHIFT);
                    seen |= 1 << val;
                    pos += 1;
                }
                Err(_) => break,
            }
        }

        if value == 0 {
            // couldn't find any keyword
            return Err(StyleParseError::UnspecifiedError.into())
        }

        // fill in rest
        for i in pos..COUNT {
            for paint in &ALL {
                // if not seen, set bit at position, mark as seen
                if (seen & (1 << paint)) == 0 {
                    seen |= 1 << paint;
                    value |= paint << (i * SHIFT);
                    break;
                }
            }
        }

        Ok(SpecifiedValue(value))
    }

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            if self.0 == 0 {
                return dest.write_str("normal")
            }

            for pos in 0..COUNT {
                if pos != 0 {
                    dest.write_str(" ")?
                }
                match self.bits_at(pos) {
                    FILL => dest.write_str("fill")?,
                    STROKE => dest.write_str("stroke")?,
                    MARKERS => dest.write_str("markers")?,
                    _ => unreachable!(),
                }
            }
            Ok(())
        }
    }
</%helpers:longhand>

<%helpers:vector_longhand name="-moz-context-properties"
                   animation_value_type="none"
                   products="gecko"
                   spec="Nonstandard (Internal-only)"
                   allow_empty="True">
    use values::CustomIdent;

    pub type SpecifiedValue = CustomIdent;

    pub mod computed_value {
        pub type T = super::SpecifiedValue;
    }

    pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
                         -> Result<SpecifiedValue, ParseError<'i>> {
        let i = input.expect_ident()?;
        CustomIdent::from_ident(i, &["all", "none", "auto"])
    }
</%helpers:vector_longhand>
<|endoftext|>


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

//! Numeric traits for generic mathematics
#![doc(html_logo_url = "https://rust-num.github.io/num/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://rust-num.github.io/num/favicon.ico",
       html_root_url = "https://rust-num.github.io/num/",
       html_playground_url = "http://play.integer32.com/")]

use std::ops::{Add, Sub, Mul, Div, Rem};

pub use bounds::Bounded;
pub use float::{Float, FloatConst};
pub use identities::{Zero, One, zero, one};
pub use ops::checked::*;
pub use ops::wrapping::*;
pub use ops::saturating::Saturating;
pub use sign::{Signed, Unsigned, abs, abs_sub, signum};
pub use cast::*;
pub use int::PrimInt;
pub use pow::{pow, checked_pow};

pub mod identities;
pub mod sign;
pub mod ops;
pub mod bounds;
pub mod float;
pub mod cast;
pub mod int;
pub mod pow;

/// The base trait for numeric types
pub trait Num: PartialEq + Zero + One
    + Add<Output = Self> + Sub<Output = Self>
    + Mul<Output = Self> + Div<Output = Self> + Rem<Output = Self>
{
    type FromStrRadixErr;

    /// Convert from a string and radix <= 36.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use num_traits::Num;
    ///
    /// let result = <i32 as Num>::from_str_radix("27", 10);
    /// assert_eq!(result, Ok(27));
    ///
    /// let result = <i32 as Num>::from_str_radix("foo", 10);
    /// assert!(result.is_err());
    /// ```
    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>;
}

macro_rules! int_trait_impl {
    ($name:ident for $($t:ty)*) => ($(
        impl $name for $t {
            type FromStrRadixErr = ::std::num::ParseIntError;
            #[inline]
            fn from_str_radix(s: &str, radix: u32)
                              -> Result<Self, ::std::num::ParseIntError>
            {
                <$t>::from_str_radix(s, radix)
            }
        }
    )*)
}
int_trait_impl!(Num for usize u8 u16 u32 u64 isize i8 i16 i32 i64);

#[derive(Debug)]
pub enum FloatErrorKind {
    Empty,
    Invalid,
}
// FIXME: std::num::ParseFloatError is stable in 1.0, but opaque to us,
// so there's not really any way for us to reuse it.
#[derive(Debug)]
pub struct ParseFloatError {
    pub kind: FloatErrorKind,
}

// FIXME: The standard library from_str_radix on floats was deprecated, so we're stuck
// with this implementation ourselves until we want to make a breaking change.
// (would have to drop it from `Num` though)
macro_rules! float_trait_impl {
    ($name:ident for $($t:ty)*) => ($(
        impl $name for $t {
            type FromStrRadixErr = ParseFloatError;

            fn from_str_radix(src: &str, radix: u32)
                              -> Result<Self, Self::FromStrRadixErr>
            {
                use self::FloatErrorKind::*;
                use self::ParseFloatError as PFE;

                // Special values
                match src {
                    "inf"   => return Ok(Float::infinity()),
                    "-inf"  => return Ok(Float::neg_infinity()),
                    "NaN"   => return Ok(Float::nan()),
                    _       => {},
                }

                fn slice_shift_char(src: &str) -> Option<(char, &str)> {
                    src.chars().nth(0).map(|ch| (ch, &src[1..]))
                }

                let (is_positive, src) =  match slice_shift_char(src) {
                    None             => return Err(PFE { kind: Empty }),
                    Some(('-', ""))  => return Err(PFE { kind: Empty }),
                    Some(('-', src)) => (false, src),
                    Some((_, _))     => (true,  src),
                };

                // The significand to accumulate
                let mut sig = if is_positive { 0.0 } else { -0.0 };
                // Necessary to detect overflow
                let mut prev_sig = sig;
                let mut cs = src.chars().enumerate();
                // Exponent prefix and exponent index offset
                let mut exp_info = None::<(char, usize)>;

                // Parse the integer part of the significand
                for (i, c) in cs.by_ref() {
                    match c.to_digit(radix) {
                        Some(digit) => {
                            // shift significand one digit left
                            sig = sig * (radix as $t);

                            // add/subtract current digit depending on sign
                            if is_positive {
                                sig = sig + ((digit as isize) as $t);
                            } else {
                                sig = sig - ((digit as isize) as $t);
                            }

                            // Detect overflow by comparing to last value, except
                            // if we've not seen any non-zero digits.
                            if prev_sig != 0.0 {
                                if is_positive && sig <= prev_sig
                                    { return Ok(Float::infinity()); }
                                if !is_positive && sig >= prev_sig
                                    { return Ok(Float::neg_infinity()); }

                                // Detect overflow by reversing the shift-and-add process
                                if is_positive && (prev_sig != (sig - digit as $t) / radix as $t)
                                    { return Ok(Float::infinity()); }
                                if !is_positive && (prev_sig != (sig + digit as $t) / radix as $t)
                                    { return Ok(Float::neg_infinity()); }
                            }
                            prev_sig = sig;
                        },
                        None => match c {
                            'e' | 'E' | 'p' | 'P' => {
                                exp_info = Some((c, i + 1));
                                break;  // start of exponent
                            },
                            '.' => {
                                break;  // start of fractional part
                            },
                            _ => {
                                return Err(PFE { kind: Invalid });
                            },
                        },
                    }
                }

                // If we are not yet at the exponent parse the fractional
                // part of the significand
                if exp_info.is_none() {
                    let mut power = 1.0;
                    for (i, c) in cs.by_ref() {
                        match c.to_digit(radix) {
                            Some(digit) => {
                                // Decrease power one order of magnitude
                                power = power / (radix as $t);
                                // add/subtract current digit depending on sign
                                sig = if is_positive {
                                    sig + (digit as $t) * power
                                } else {
                                    sig - (digit as $t) * power
                                };
                                // Detect overflow by comparing to last value
                                if is_positive && sig < prev_sig
                                    { return Ok(Float::infinity()); }
                                if !is_positive && sig > prev_sig
                                    { return Ok(Float::neg_infinity()); }
                                prev_sig = sig;
                            },
                            None => match c {
                                'e' | 'E' | 'p' | 'P' => {
                                    exp_info = Some((c, i + 1));
                                    break; // start of exponent
                                },
                                _ => {
                                    return Err(PFE { kind: Invalid });
                                },
                            },
                        }
                    }
                }

                // Parse and calculate the exponent
                let exp = match exp_info {
                    Some((c, offset)) => {
                        let base = match c {
                            'E' | 'e' if radix == 10 => 10.0,
                            'P' | 'p' if radix == 16 => 2.0,
                            _ => return Err(PFE { kind: Invalid }),
                        };

                        // Parse the exponent as decimal integer
                        let src = &src[offset..];
                        let (is_positive, exp) = match slice_shift_char(src) {
                            Some(('-', src)) => (false, src.parse::<usize>()),
                            Some(('+', src)) => (true,  src.parse::<usize>()),
                            Some((_, _))     => (true,  src.parse::<usize>()),
                            None             => return Err(PFE { kind: Invalid }),
                        };

                        match (is_positive, exp) {
                            (true,  Ok(exp)) => base.powi(exp as i32),
                            (false, Ok(exp)) => 1.0 / base.powi(exp as i32),
                            (_, Err(_))      => return Err(PFE { kind: Invalid }),
                        }
                    },
                    None => 1.0, // no exponent
                };

                Ok(sig * exp)
            }
        }
    )*)
}
float_trait_impl!(Num for f32 f64);

/// A value bounded by a minimum and a maximum
///
/// If input is less than min then min is returned, if input is greater than max then max is
/// returned.  Otherwise input is returned.
#[inline]
pub fn clamp<T: PartialOrd>(input: T, min: T, max: T) -> T {
    debug_assert!(min <= max, "min must be less than or equal to max");
    if input < min {
        min
    } else if input > max {
        max
    } else {
        input
    }
}

#[test]
fn clamp_test() {
    // Int test
    assert_eq!(1, clamp(1, -1, 2));
    assert_eq!(-1, clamp(-2, -1, 2));
    assert_eq!(2, clamp(3, -1, 2));

    // Float test
    assert_eq!(1.0, clamp(1.0, -1.0, 2.0));
    assert_eq!(-1.0, clamp(-2.0, -1.0, 2.0));
    assert_eq!(2.0, clamp(3.0, -1.0, 2.0));
}

#[test]
fn from_str_radix_unwrap() {
    // The Result error must impl Debug to allow unwrap()

    let i: i32 = Num::from_str_radix("0", 10).unwrap();
    assert_eq!(i, 0);

    let f: f32 = Num::from_str_radix("0.0", 10).unwrap();
    assert_eq!(f, 0.0);
}
<commit_msg>Improve documentation comments<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Numeric traits for generic mathematics
#![doc(html_logo_url = "https://rust-num.github.io/num/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://rust-num.github.io/num/favicon.ico",
       html_root_url = "https://rust-num.github.io/num/",
       html_playground_url = "http://play.integer32.com/")]

use std::ops::{Add, Sub, Mul, Div, Rem};

pub use bounds::Bounded;
pub use float::{Float, FloatConst};
pub use identities::{Zero, One, zero, one};
pub use ops::checked::*;
pub use ops::wrapping::*;
pub use ops::saturating::Saturating;
pub use sign::{Signed, Unsigned, abs, abs_sub, signum};
pub use cast::*;
pub use int::PrimInt;
pub use pow::{pow, checked_pow};

pub mod identities;
pub mod sign;
pub mod ops;
pub mod bounds;
pub mod float;
pub mod cast;
pub mod int;
pub mod pow;

/// The base trait for numeric types
pub trait Num: PartialEq + Zero + One
    + Add<Output = Self> + Sub<Output = Self>
    + Mul<Output = Self> + Div<Output = Self> + Rem<Output = Self>
{
    type FromStrRadixErr;

    /// Convert from a string and radix <= 36.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use num_traits::Num;
    ///
    /// let result = <i32 as Num>::from_str_radix("27", 10);
    /// assert_eq!(result, Ok(27));
    ///
    /// let result = <i32 as Num>::from_str_radix("foo", 10);
    /// assert!(result.is_err());
    /// ```
    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>;
}

macro_rules! int_trait_impl {
    ($name:ident for $($t:ty)*) => ($(
        impl $name for $t {
            type FromStrRadixErr = ::std::num::ParseIntError;
            #[inline]
            fn from_str_radix(s: &str, radix: u32)
                              -> Result<Self, ::std::num::ParseIntError>
            {
                <$t>::from_str_radix(s, radix)
            }
        }
    )*)
}
int_trait_impl!(Num for usize u8 u16 u32 u64 isize i8 i16 i32 i64);

#[derive(Debug)]
pub enum FloatErrorKind {
    Empty,
    Invalid,
}
// FIXME: std::num::ParseFloatError is stable in 1.0, but opaque to us,
// so there's not really any way for us to reuse it.
#[derive(Debug)]
pub struct ParseFloatError {
    pub kind: FloatErrorKind,
}

// FIXME: The standard library from_str_radix on floats was deprecated, so we're stuck
// with this implementation ourselves until we want to make a breaking change.
// (would have to drop it from `Num` though)
macro_rules! float_trait_impl {
    ($name:ident for $($t:ty)*) => ($(
        impl $name for $t {
            type FromStrRadixErr = ParseFloatError;

            fn from_str_radix(src: &str, radix: u32)
                              -> Result<Self, Self::FromStrRadixErr>
            {
                use self::FloatErrorKind::*;
                use self::ParseFloatError as PFE;

                // Special values
                match src {
                    "inf"   => return Ok(Float::infinity()),
                    "-inf"  => return Ok(Float::neg_infinity()),
                    "NaN"   => return Ok(Float::nan()),
                    _       => {},
                }

                fn slice_shift_char(src: &str) -> Option<(char, &str)> {
                    src.chars().nth(0).map(|ch| (ch, &src[1..]))
                }

                let (is_positive, src) =  match slice_shift_char(src) {
                    None             => return Err(PFE { kind: Empty }),
                    Some(('-', ""))  => return Err(PFE { kind: Empty }),
                    Some(('-', src)) => (false, src),
                    Some((_, _))     => (true,  src),
                };

                // The significand to accumulate
                let mut sig = if is_positive { 0.0 } else { -0.0 };
                // Necessary to detect overflow
                let mut prev_sig = sig;
                let mut cs = src.chars().enumerate();
                // Exponent prefix and exponent index offset
                let mut exp_info = None::<(char, usize)>;

                // Parse the integer part of the significand
                for (i, c) in cs.by_ref() {
                    match c.to_digit(radix) {
                        Some(digit) => {
                            // shift significand one digit left
                            sig = sig * (radix as $t);

                            // add/subtract current digit depending on sign
                            if is_positive {
                                sig = sig + ((digit as isize) as $t);
                            } else {
                                sig = sig - ((digit as isize) as $t);
                            }

                            // Detect overflow by comparing to last value, except
                            // if we've not seen any non-zero digits.
                            if prev_sig != 0.0 {
                                if is_positive && sig <= prev_sig
                                    { return Ok(Float::infinity()); }
                                if !is_positive && sig >= prev_sig
                                    { return Ok(Float::neg_infinity()); }

                                // Detect overflow by reversing the shift-and-add process
                                if is_positive && (prev_sig != (sig - digit as $t) / radix as $t)
                                    { return Ok(Float::infinity()); }
                                if !is_positive && (prev_sig != (sig + digit as $t) / radix as $t)
                                    { return Ok(Float::neg_infinity()); }
                            }
                            prev_sig = sig;
                        },
                        None => match c {
                            'e' | 'E' | 'p' | 'P' => {
                                exp_info = Some((c, i + 1));
                                break;  // start of exponent
                            },
                            '.' => {
                                break;  // start of fractional part
                            },
                            _ => {
                                return Err(PFE { kind: Invalid });
                            },
                        },
                    }
                }

                // If we are not yet at the exponent parse the fractional
                // part of the significand
                if exp_info.is_none() {
                    let mut power = 1.0;
                    for (i, c) in cs.by_ref() {
                        match c.to_digit(radix) {
                            Some(digit) => {
                                // Decrease power one order of magnitude
                                power = power / (radix as $t);
                                // add/subtract current digit depending on sign
                                sig = if is_positive {
                                    sig + (digit as $t) * power
                                } else {
                                    sig - (digit as $t) * power
                                };
                                // Detect overflow by comparing to last value
                                if is_positive && sig < prev_sig
                                    { return Ok(Float::infinity()); }
                                if !is_positive && sig > prev_sig
                                    { return Ok(Float::neg_infinity()); }
                                prev_sig = sig;
                            },
                            None => match c {
                                'e' | 'E' | 'p' | 'P' => {
                                    exp_info = Some((c, i + 1));
                                    break; // start of exponent
                                },
                                _ => {
                                    return Err(PFE { kind: Invalid });
                                },
                            },
                        }
                    }
                }

                // Parse and calculate the exponent
                let exp = match exp_info {
                    Some((c, offset)) => {
                        let base = match c {
                            'E' | 'e' if radix == 10 => 10.0,
                            'P' | 'p' if radix == 16 => 2.0,
                            _ => return Err(PFE { kind: Invalid }),
                        };

                        // Parse the exponent as decimal integer
                        let src = &src[offset..];
                        let (is_positive, exp) = match slice_shift_char(src) {
                            Some(('-', src)) => (false, src.parse::<usize>()),
                            Some(('+', src)) => (true,  src.parse::<usize>()),
                            Some((_, _))     => (true,  src.parse::<usize>()),
                            None             => return Err(PFE { kind: Invalid }),
                        };

                        match (is_positive, exp) {
                            (true,  Ok(exp)) => base.powi(exp as i32),
                            (false, Ok(exp)) => 1.0 / base.powi(exp as i32),
                            (_, Err(_))      => return Err(PFE { kind: Invalid }),
                        }
                    },
                    None => 1.0, // no exponent
                };

                Ok(sig * exp)
            }
        }
    )*)
}
float_trait_impl!(Num for f32 f64);

/// A value bounded by a minimum and a maximum
///
///  If input is less than min then this returns min.
///  If input is greater than max then this returns max.
///  Otherwise this returns input.
#[inline]
pub fn clamp<T: PartialOrd>(input: T, min: T, max: T) -> T {
    debug_assert!(min <= max, "min must be less than or equal to max");
    if input < min {
        min
    } else if input > max {
        max
    } else {
        input
    }
}

#[test]
fn clamp_test() {
    // Int test
    assert_eq!(1, clamp(1, -1, 2));
    assert_eq!(-1, clamp(-2, -1, 2));
    assert_eq!(2, clamp(3, -1, 2));

    // Float test
    assert_eq!(1.0, clamp(1.0, -1.0, 2.0));
    assert_eq!(-1.0, clamp(-2.0, -1.0, 2.0));
    assert_eq!(2.0, clamp(3.0, -1.0, 2.0));
}

#[test]
fn from_str_radix_unwrap() {
    // The Result error must impl Debug to allow unwrap()

    let i: i32 = Num::from_str_radix("0", 10).unwrap();
    assert_eq!(i, 0);

    let f: f32 = Num::from_str_radix("0.0", 10).unwrap();
    assert_eq!(f, 0.0);
}
<|endoftext|>


<commit_before>use ::ast::*;
use ::ast::ExprNode::*;
use ::ast::NumNode::*;
use super::*;
use super::parser_combinators::{Parser,parser};

#[test]
fn test_line_comment() {
    assert_eq!(parser(line_comment).parse(";this is a fake line comment\n"),
        Ok(((),"")));
}

#[test]
fn test_line_comment_ignore() {
    assert_eq!(parser(expr).parse(
r#";this is a fake line comment
ident"#),
        Ok((Name(NameNode { name: "ident".to_string() }), ""))
        )
}

#[test]
fn test_basic_ident() {
    assert_eq!(
        parser(expr).parse("ident"),
        Ok((Name(NameNode { name: "ident".to_string() }), ""))
        );
    assert_eq!(
        parser(expr).parse("a"),
        Ok((Name(NameNode { name: "a".to_string() }), ""))
        );
    assert_eq!(
        parser(expr).parse("ident_With\\special!Chars:~-+"),
        Ok((Name(NameNode { name: "ident_With\\special!Chars:~-+".to_string() }), ""))
        );
}

#[test]
fn test_basic_sexpr() {
    assert_eq!(
        parser(expr).parse("(ident arg1 arg2)"),
        Ok((SExpr(SExprNode {
            operator: box Name(NameNode { name: "ident".to_string() }),
            operands: vec![
                Name(NameNode { name: "arg1".to_string() }),
                Name(NameNode { name: "arg2".to_string() })
            ]
        }), ""))
        );
}

#[test]
fn test_lex_sint_pos() {
    assert_eq!(
        parser(number).parse("1234"),
        Ok((IntConst(IntNode { value: 1234isize }), ""))
        );
    assert_eq!(
        parser(number).parse("#d1234"),
        Ok((IntConst(IntNode { value: 1234isize }), ""))
        );
    assert_eq!(
        parser(number).parse("#D1234"),
        Ok((IntConst(IntNode { value: 1234isize }), ""))
        );
}

#[test]
fn test_lex_sint_neg() {
    assert_eq!(
        parser(number).parse("-1234"),
        Ok((IntConst(IntNode { value: -1234isize }), ""))
        );
}

#[test]
fn test_lex_sint_hex() {
    assert_eq!(
        parser(number).parse("#x0ff"),
        Ok((IntConst(IntNode { value: 0x0ffisize }), ""))
        );
    assert_eq!(
        parser(number).parse("#X0FF"),
        Ok((IntConst(IntNode { value: 0x0ffisize }), ""))
        );
}
/* // Currently unsupported
#[test]
fn test_parse_sint_bin_upper() {
    assert_eq!(
        parser(number).parse("0B01"),
        Ok((IntConst(IntNode { value: 0b01isize }), ""))
        );
    assert_eq!(
        parser(number).parse("0b01"),
        Ok((IntConst(IntNode { value: 0b01isize }), ""))
        );
}*/

#[test]
fn test_lex_uint() {
    assert_eq!(
        parser(number).parse("1234u"),
        Ok((UIntConst(UIntNode { value: 1234usize }), ""))
        );
    assert_eq!(
        parser(number).parse("4321U"),
        Ok((UIntConst(UIntNode { value: 4321usize }), ""))
        );
}

#[test]
fn test_lex_uint_hex() {
    assert_eq!(
        parser(number).parse("#x0ffu"),
        Ok((UIntConst(UIntNode { value: 0x0ffusize }), ""))
        );
    assert_eq!(
        parser(number).parse("#X0FFu"),
        Ok((UIntConst(UIntNode { value: 0x0ffusize }), ""))
        );
}

#[test]
fn test_lex_float() {
    assert_eq!(
        parser(number).parse("1.0"),
        Ok((FloatConst(FloatNode { value: 1.0f64 }), ""))
        );/* // Unsupported
    assert_eq!(
        parser(number).parse("1f").unwrap(),
        (FloatConst(FloatNode { value: 1.0f64 }), "")
        );
    assert_eq!(
        parser(number).parse("22.2222").unwrap(),
        (FloatConst(FloatNode { value: 22.2222f64 }), "")
        );
    assert_eq!(
        parser(number).parse("22.2222f").unwrap(),
        (FloatConst(FloatNode { value: 22.2222f64 }), "")
        );*/
}

/// This is the parsing component of basic arithmetic
/// integration target
///
/// ```lisp
/// (+ 10 10)
/// ```
#[test]
fn test_parse_arith() {
    assert_eq!(
        parser(expr).parse("(+ 10 10)"),
        Ok((
            SExpr(SExprNode {
                operator: box Name(NameNode { name: "+".to_string() }),
                operands: vec![
                    NumConst(IntConst(IntNode{ value: 10 })),
                    NumConst(IntConst(IntNode{ value: 10 }))
                ]
            }),
            ""))
        );
}

/// This is the parsing component of the CAR integration target
///
/// ```lisp
/// (car (cons 10 (cons 20 nil)))
/// ```
#[test]
fn test_parse_car() {
    assert_eq!(
        parser(expr).parse("(car (cons 10 (cons 20 nil)))"),
        Ok((
            SExpr(SExprNode {
                operator: box Name(NameNode { name: "car".to_string() }),
                operands: vec![
                    SExpr(SExprNode {
                        operator: box Name(NameNode { name: "cons".to_string() }),
                        operands: vec![
                            NumConst(IntConst(IntNode{ value: 10 })),
                            SExpr(SExprNode {
                                operator: box Name(NameNode { name: "cons".to_string() }),
                                operands: vec![
                                    NumConst(IntConst(IntNode{ value: 20 })),
                                    Name(NameNode { name: "nil".to_string() })
                                ]
                            })
                        ]
                    })
                ]
            }),
            ""))
        );
}

/// This is the parsing component of the CDR integration target
///
/// ```lisp
/// (cdr (cons 10 (cons 20 nil)))
/// ```
#[test]
fn test_parse_cdr() {
    assert_eq!(
        parser(expr).parse("(cdr (cons 10 (cons 20 nil)))"),
        Ok((
            SExpr(SExprNode {
                operator: box Name(NameNode { name: "cdr".to_string() }),
                operands: vec![
                    SExpr(SExprNode {
                        operator: box Name(NameNode { name: "cons".to_string() }),
                        operands: vec![
                            NumConst(IntConst(IntNode{ value: 10 })),
                            SExpr(SExprNode {
                                operator: box Name(NameNode { name: "cons".to_string() }),
                                operands: vec![
                                    NumConst(IntConst(IntNode{ value: 20 })),
                                    Name(NameNode { name: "nil".to_string() })
                                ]
                            })
                        ]
                    })
                ]
            }),
            ""))
        );
}

/// This is the parsing component of nested arithmetic
/// integration target
///
/// ```lisp
/// (- 20 (+ 5 5))
/// ```
#[test]
fn test_parse_nested_arith() {
    assert_eq!(
        parser(expr).parse("(- 20 (+ 5 5))"),
        Ok((
            SExpr(SExprNode {
                operator: box Name(NameNode { name: "-".to_string() }),
                operands: vec![
                    NumConst(IntConst(IntNode{ value: 20 })),
                    SExpr(SExprNode {
                        operator: box Name(NameNode { name: "+".to_string() }),
                        operands: vec![
                            NumConst(IntConst(IntNode{ value: 5 })),
                            NumConst(IntConst(IntNode{ value: 5 }))
                        ]
                    })
                ]
            }),
            ""))
        );
}

/// This is the parsing component of the `compile_basic_branching_1`
/// integration target.
///
/// ```lisp
/// (if (= 0 (- 1 1)) #t #f)
/// ``
#[test]
fn test_parse_basic_branching_1() {
    assert_eq!(
        parser(expr).parse("(if (= 0 (- 1 1)) #t #f)"),
        Ok((
            SExpr(SExprNode {
                operator: box Name(NameNode::new("if".to_string())),
                operands: vec![
                    SExpr(SExprNode{
                        operator: box Name(NameNode::new("=".to_string())),
                        operands: vec![
                            NumConst(IntConst(IntNode{value: 0})),
                            SExpr(SExprNode{
                                operator: box Name(NameNode::new("-".to_string())),
                                operands: vec![
                                    NumConst(IntConst(IntNode{ value: 1 })),
                                    NumConst(IntConst(IntNode{ value: 1 }))
                                ]
                            })
                        ]
                    }),
                    BoolConst(BoolNode{value:true}),
                    BoolConst(BoolNode{value:false}),
                ]
            }
            ),
            "")
        )
    )
}

/// This is the parsing component of the `compile_basic_branching_2`
/// integration target.
///
/// ```lisp
/// (+ 10 (if (nil? nil) 10 20))
/// ``
#[test]
fn test_parse_basic_branching_2() {
    assert_eq!(
        parser(expr).parse("(+ 10 (if (nil? nil) 10 20))"),
        Ok((
            SExpr(SExprNode {
                operator: box Name(NameNode::new("+".to_string())),
                operands: vec![
                    NumConst(IntConst(IntNode{value:10})),
                    SExpr(SExprNode{
                        operator: box Name(NameNode::new("if".to_string())),
                        operands: vec![
                            SExpr(SExprNode{
                                operator: box Name(NameNode::new("nil?".to_string())),
                                operands: vec![Name(NameNode::new("nil".to_string()))]

                            }),
                            NumConst(IntConst(IntNode{value:10})),
                            NumConst(IntConst(IntNode{value:20}))
                        ]
                    })
                ]
            }
            ),
            "")
        )
    )
}

#[test]
fn test_lex_bool() {
    assert_eq!(
        parser(bool_const).parse("#t"),
        Ok((BoolNode { value: true}, ""))
        );
    assert_eq!(
        parser(bool_const).parse("#T"),
        Ok((BoolNode { value: true}, ""))
        );
    assert_eq!(
        parser(bool_const).parse("#f"),
        Ok((BoolNode { value: false}, ""))
        );
    assert_eq!(
        parser(bool_const).parse("#F"),
        Ok((BoolNode { value: false}, ""))
        );
}

#[test]
fn test_lex_char() {
    assert_eq!(
        parser(character).parse("#\\c"),
        Ok((CharNode { value: 'c'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\A"),
        Ok((CharNode { value: 'A'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\tab"),
        Ok((CharNode { value: '\t'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\newline"),
        Ok((CharNode { value: '\n'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\nul"),
        Ok((CharNode { value: '\u{0000}' }, ""))
        );
    assert_eq!(
        parser(character).parse("#\\backspace"),
        Ok((CharNode { value: '\u{0008}' }, ""))
        );
    assert_eq!(
        parser(character).parse("#\\vtab"),
        Ok((CharNode { value: '\u{000B}' }, ""))
        );
    assert_eq!(
        parser(character).parse("#\\page"),
        Ok((CharNode { value: '\u{000C}' }, ""))
        );
    assert_eq!(
        parser(character).parse("#\\return"),
        Ok((CharNode { value: '\u{000D}' }, ""))
        );
    assert_eq!(
        parser(character).parse("#\\esc"),
        Ok((CharNode { value: '\u{001B}' }, ""))
        );
    assert_eq!(
        parser(character).parse("#\\delete"),
        Ok((CharNode { value: '\u{007F}' }, ""))
        );
    assert_eq!(
        parser(character).parse("#\\alarm"),
        Ok((CharNode { value: '\u{0007}' }, ""))
        );
    assert_eq!(
        parser(character).parse("#\\linefeed"),
        Ok((CharNode { value: '\n'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\space"),
        Ok((CharNode { value: ' '}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\x0020"),
        Ok((CharNode { value: ' '}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\x001B"),
        Ok((CharNode { value: '\u{001B}' }, ""))
        );
}

#[test]
fn test_lex_string() {
    assert_eq!(
        parser(string_const).parse("\"a string\""),
        Ok((StringNode { value: "a string".to_string() }, ""))
    );
    assert_eq!(
        parser(string_const).parse("\"a string with a\\ttab\""),
        Ok((StringNode { value: "a string with a\ttab".to_string() },""))
    );
    assert_eq!(
        parser(string_const).parse("\"a string with an \\\"escaped\\\" quote\""),
        Ok((StringNode { value: "a string with an \"escaped\" quote".to_string() },""))
    );
    assert_eq!(
        parser(string_const).parse("\"the\\\\worst string ever\\\"\""),
        Ok((StringNode { value: "the\\worst string ever\"".to_string() }, ""))
    );
}
<commit_msg>Add tests for parsing square brackets<commit_after>use ::ast::*;
use ::ast::ExprNode::*;
use ::ast::NumNode::*;
use super::*;
use super::parser_combinators::{Parser,parser};

#[test]
fn test_line_comment() {
    assert_eq!(parser(line_comment).parse(";this is a fake line comment\n"),
        Ok(((),"")));
}

#[test]
fn test_line_comment_ignore() {
    assert_eq!(parser(expr).parse(
r#";this is a fake line comment
ident"#),
        Ok((Name(NameNode { name: "ident".to_string() }), ""))
        )
}

#[test]
fn test_basic_ident() {
    assert_eq!(
        parser(expr).parse("ident"),
        Ok((Name(NameNode { name: "ident".to_string() }), ""))
        );
    assert_eq!(
        parser(expr).parse("a"),
        Ok((Name(NameNode { name: "a".to_string() }), ""))
        );
    assert_eq!(
        parser(expr).parse("ident_With\\special!Chars:~-+"),
        Ok((Name(NameNode { name: "ident_With\\special!Chars:~-+".to_string() }), ""))
        );
}

#[test]
fn test_basic_sexpr() {
    assert_eq!(
        parser(expr).parse("(ident arg1 arg2)"),
        Ok((SExpr(SExprNode {
            operator: box Name(NameNode { name: "ident".to_string() }),
            operands: vec![
                Name(NameNode { name: "arg1".to_string() }),
                Name(NameNode { name: "arg2".to_string() })
            ]
        }), ""))
        );
}
#[test]
fn test_square_bracket_sexpr() {
    assert_eq!(
        parser(expr).parse("[ident arg1 arg2]"),
        Ok((SExpr(SExprNode {
            operator: box Name(NameNode { name: "ident".to_string() }),
            operands: vec![
                Name(NameNode { name: "arg1".to_string() }),
                Name(NameNode { name: "arg2".to_string() })
            ]
        }), ""))
        );
}

#[test]
fn test_lex_sint_pos() {
    assert_eq!(
        parser(number).parse("1234"),
        Ok((IntConst(IntNode { value: 1234isize }), ""))
        );
    assert_eq!(
        parser(number).parse("#d1234"),
        Ok((IntConst(IntNode { value: 1234isize }), ""))
        );
    assert_eq!(
        parser(number).parse("#D1234"),
        Ok((IntConst(IntNode { value: 1234isize }), ""))
        );
}

#[test]
fn test_lex_sint_neg() {
    assert_eq!(
        parser(number).parse("-1234"),
        Ok((IntConst(IntNode { value: -1234isize }), ""))
        );
}

#[test]
fn test_lex_sint_hex() {
    assert_eq!(
        parser(number).parse("#x0ff"),
        Ok((IntConst(IntNode { value: 0x0ffisize }), ""))
        );
    assert_eq!(
        parser(number).parse("#X0FF"),
        Ok((IntConst(IntNode { value: 0x0ffisize }), ""))
        );
}
/* // Currently unsupported
#[test]
fn test_parse_sint_bin_upper() {
    assert_eq!(
        parser(number).parse("0B01"),
        Ok((IntConst(IntNode { value: 0b01isize }), ""))
        );
    assert_eq!(
        parser(number).parse("0b01"),
        Ok((IntConst(IntNode { value: 0b01isize }), ""))
        );
}*/

#[test]
fn test_lex_uint() {
    assert_eq!(
        parser(number).parse("1234u"),
        Ok((UIntConst(UIntNode { value: 1234usize }), ""))
        );
    assert_eq!(
        parser(number).parse("4321U"),
        Ok((UIntConst(UIntNode { value: 4321usize }), ""))
        );
}

#[test]
fn test_lex_uint_hex() {
    assert_eq!(
        parser(number).parse("#x0ffu"),
        Ok((UIntConst(UIntNode { value: 0x0ffusize }), ""))
        );
    assert_eq!(
        parser(number).parse("#X0FFu"),
        Ok((UIntConst(UIntNode { value: 0x0ffusize }), ""))
        );
}

#[test]
fn test_lex_float() {
    assert_eq!(
        parser(number).parse("1.0"),
        Ok((FloatConst(FloatNode { value: 1.0f64 }), ""))
        );/* // Unsupported
    assert_eq!(
        parser(number).parse("1f").unwrap(),
        (FloatConst(FloatNode { value: 1.0f64 }), "")
        );
    assert_eq!(
        parser(number).parse("22.2222").unwrap(),
        (FloatConst(FloatNode { value: 22.2222f64 }), "")
        );
    assert_eq!(
        parser(number).parse("22.2222f").unwrap(),
        (FloatConst(FloatNode { value: 22.2222f64 }), "")
        );*/
}

/// This is the parsing component of basic arithmetic
/// integration target
///
/// ```lisp
/// (+ 10 10)
/// ```
#[test]
fn test_parse_arith() {
    assert_eq!(
        parser(expr).parse("(+ 10 10)"),
        Ok((
            SExpr(SExprNode {
                operator: box Name(NameNode { name: "+".to_string() }),
                operands: vec![
                    NumConst(IntConst(IntNode{ value: 10 })),
                    NumConst(IntConst(IntNode{ value: 10 }))
                ]
            }),
            ""))
        );
}

/// This is the parsing component of the CAR integration target
///
/// ```lisp
/// (car (cons 10 (cons 20 nil)))
/// ```
#[test]
fn test_parse_car() {
    assert_eq!(
        parser(expr).parse("(car (cons 10 (cons 20 nil)))"),
        Ok((
            SExpr(SExprNode {
                operator: box Name(NameNode { name: "car".to_string() }),
                operands: vec![
                    SExpr(SExprNode {
                        operator: box Name(NameNode { name: "cons".to_string() }),
                        operands: vec![
                            NumConst(IntConst(IntNode{ value: 10 })),
                            SExpr(SExprNode {
                                operator: box Name(NameNode { name: "cons".to_string() }),
                                operands: vec![
                                    NumConst(IntConst(IntNode{ value: 20 })),
                                    Name(NameNode { name: "nil".to_string() })
                                ]
                            })
                        ]
                    })
                ]
            }),
            ""))
        );
}

/// This is the parsing component of the CDR integration target
///
/// ```lisp
/// (cdr (cons 10 (cons 20 nil)))
/// ```
#[test]
fn test_parse_cdr() {
    assert_eq!(
        parser(expr).parse("(cdr (cons 10 (cons 20 nil)))"),
        Ok((
            SExpr(SExprNode {
                operator: box Name(NameNode { name: "cdr".to_string() }),
                operands: vec![
                    SExpr(SExprNode {
                        operator: box Name(NameNode { name: "cons".to_string() }),
                        operands: vec![
                            NumConst(IntConst(IntNode{ value: 10 })),
                            SExpr(SExprNode {
                                operator: box Name(NameNode { name: "cons".to_string() }),
                                operands: vec![
                                    NumConst(IntConst(IntNode{ value: 20 })),
                                    Name(NameNode { name: "nil".to_string() })
                                ]
                            })
                        ]
                    })
                ]
            }),
            ""))
        );
}

/// This is the parsing component of nested arithmetic
/// integration target with square brackets added
/// (just to ensure that the parser handles them correctly)
///
/// ```lisp
/// (- 20 [+ 5 5])
/// ```
#[test]
fn test_parse_nested_arith_square_bracket() {
    assert_eq!(
        parser(expr).parse("(- 20 [+ 5 5])"),
        Ok((
            SExpr(SExprNode {
                operator: box Name(NameNode { name: "-".to_string() }),
                operands: vec![
                    NumConst(IntConst(IntNode{ value: 20 })),
                    SExpr(SExprNode {
                        operator: box Name(NameNode { name: "+".to_string() }),
                        operands: vec![
                            NumConst(IntConst(IntNode{ value: 5 })),
                            NumConst(IntConst(IntNode{ value: 5 }))
                        ]
                    })
                ]
            }),
            ""))
        );
}

/// This is the parsing component of nested arithmetic
/// integration target
///
/// ```lisp
/// (- 20 (+ 5 5))
/// ```
#[test]
fn test_parse_nested_arith() {
    assert_eq!(
        parser(expr).parse("(- 20 (+ 5 5))"),
        Ok((
            SExpr(SExprNode {
                operator: box Name(NameNode { name: "-".to_string() }),
                operands: vec![
                    NumConst(IntConst(IntNode{ value: 20 })),
                    SExpr(SExprNode {
                        operator: box Name(NameNode { name: "+".to_string() }),
                        operands: vec![
                            NumConst(IntConst(IntNode{ value: 5 })),
                            NumConst(IntConst(IntNode{ value: 5 }))
                        ]
                    })
                ]
            }),
            ""))
        );
}

/// This is the parsing component of the `compile_basic_branching_1`
/// integration target.
///
/// ```lisp
/// (if (= 0 (- 1 1)) #t #f)
/// ``
#[test]
fn test_parse_basic_branching_1() {
    assert_eq!(
        parser(expr).parse("(if (= 0 (- 1 1)) #t #f)"),
        Ok((
            SExpr(SExprNode {
                operator: box Name(NameNode::new("if".to_string())),
                operands: vec![
                    SExpr(SExprNode{
                        operator: box Name(NameNode::new("=".to_string())),
                        operands: vec![
                            NumConst(IntConst(IntNode{value: 0})),
                            SExpr(SExprNode{
                                operator: box Name(NameNode::new("-".to_string())),
                                operands: vec![
                                    NumConst(IntConst(IntNode{ value: 1 })),
                                    NumConst(IntConst(IntNode{ value: 1 }))
                                ]
                            })
                        ]
                    }),
                    BoolConst(BoolNode{value:true}),
                    BoolConst(BoolNode{value:false}),
                ]
            }
            ),
            "")
        )
    )
}

/// This is the parsing component of the `compile_basic_branching_2`
/// integration target.
///
/// ```lisp
/// (+ 10 (if (nil? nil) 10 20))
/// ``
#[test]
fn test_parse_basic_branching_2() {
    assert_eq!(
        parser(expr).parse("(+ 10 (if (nil? nil) 10 20))"),
        Ok((
            SExpr(SExprNode {
                operator: box Name(NameNode::new("+".to_string())),
                operands: vec![
                    NumConst(IntConst(IntNode{value:10})),
                    SExpr(SExprNode{
                        operator: box Name(NameNode::new("if".to_string())),
                        operands: vec![
                            SExpr(SExprNode{
                                operator: box Name(NameNode::new("nil?".to_string())),
                                operands: vec![Name(NameNode::new("nil".to_string()))]

                            }),
                            NumConst(IntConst(IntNode{value:10})),
                            NumConst(IntConst(IntNode{value:20}))
                        ]
                    })
                ]
            }
            ),
            "")
        )
    )
}

#[test]
fn test_lex_bool() {
    assert_eq!(
        parser(bool_const).parse("#t"),
        Ok((BoolNode { value: true}, ""))
        );
    assert_eq!(
        parser(bool_const).parse("#T"),
        Ok((BoolNode { value: true}, ""))
        );
    assert_eq!(
        parser(bool_const).parse("#f"),
        Ok((BoolNode { value: false}, ""))
        );
    assert_eq!(
        parser(bool_const).parse("#F"),
        Ok((BoolNode { value: false}, ""))
        );
}

#[test]
fn test_lex_char() {
    assert_eq!(
        parser(character).parse("#\\c"),
        Ok((CharNode { value: 'c'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\A"),
        Ok((CharNode { value: 'A'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\tab"),
        Ok((CharNode { value: '\t'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\newline"),
        Ok((CharNode { value: '\n'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\nul"),
        Ok((CharNode { value: '\u{0000}' }, ""))
        );
    assert_eq!(
        parser(character).parse("#\\backspace"),
        Ok((CharNode { value: '\u{0008}' }, ""))
        );
    assert_eq!(
        parser(character).parse("#\\vtab"),
        Ok((CharNode { value: '\u{000B}' }, ""))
        );
    assert_eq!(
        parser(character).parse("#\\page"),
        Ok((CharNode { value: '\u{000C}' }, ""))
        );
    assert_eq!(
        parser(character).parse("#\\return"),
        Ok((CharNode { value: '\u{000D}' }, ""))
        );
    assert_eq!(
        parser(character).parse("#\\esc"),
        Ok((CharNode { value: '\u{001B}' }, ""))
        );
    assert_eq!(
        parser(character).parse("#\\delete"),
        Ok((CharNode { value: '\u{007F}' }, ""))
        );
    assert_eq!(
        parser(character).parse("#\\alarm"),
        Ok((CharNode { value: '\u{0007}' }, ""))
        );
    assert_eq!(
        parser(character).parse("#\\linefeed"),
        Ok((CharNode { value: '\n'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\space"),
        Ok((CharNode { value: ' '}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\x0020"),
        Ok((CharNode { value: ' '}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\x001B"),
        Ok((CharNode { value: '\u{001B}' }, ""))
        );
}

#[test]
fn test_lex_string() {
    assert_eq!(
        parser(string_const).parse("\"a string\""),
        Ok((StringNode { value: "a string".to_string() }, ""))
    );
    assert_eq!(
        parser(string_const).parse("\"a string with a\\ttab\""),
        Ok((StringNode { value: "a string with a\ttab".to_string() },""))
    );
    assert_eq!(
        parser(string_const).parse("\"a string with an \\\"escaped\\\" quote\""),
        Ok((StringNode { value: "a string with an \"escaped\" quote".to_string() },""))
    );
    assert_eq!(
        parser(string_const).parse("\"the\\\\worst string ever\\\"\""),
        Ok((StringNode { value: "the\\worst string ever\"".to_string() }, ""))
    );
}
<|endoftext|>


<commit_before>use futures::{Future, FutureExt};
use tower_service::Service as TowerService;

use std::net::SocketAddr;
use std::pin::Pin;
use std::task::{Context, Poll};

use crate::{
    base::{http, Request, Response, Router},
    service::GlobalState,
};

pub struct Service {
    pub(crate) peer_addr: SocketAddr,
    pub(crate) state: GlobalState,
}

impl Service {
    pub fn new(peer_addr: SocketAddr, state: GlobalState) -> Self {
        Self { peer_addr, state }
    }
}

impl TowerService<Request> for Service {
    type Response = Response;
    type Error = http::Error;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + 'static>>;

    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Poll::Ready(Ok(()))
    }

    fn call(&mut self, req: Request) -> Self::Future {
        Router::call(self.peer_addr, req, self.state).boxed()
    }
}
<commit_msg>add CONNECTION header for keep-alive<commit_after>use futures::{Future, FutureExt};
use hyper::header;
use tower_service::Service as TowerService;

use std::net::SocketAddr;
use std::pin::Pin;
use std::task::{Context, Poll};

use crate::{
    base::{http, Request, Response, Router},
    service::GlobalState,
};

pub struct Service {
    pub(crate) peer_addr: SocketAddr,
    pub(crate) state: GlobalState,
}

impl Service {
    pub fn new(peer_addr: SocketAddr, state: GlobalState) -> Self {
        Self { peer_addr, state }
    }
}

impl TowerService<Request> for Service {
    type Response = Response;
    type Error = http::Error;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + 'static>>;

    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Poll::Ready(Ok(()))
    }

    fn call(&mut self, req: Request) -> Self::Future {
        let keepalive = if self.state.config().keep_alive {
            "Keep-Alive"
        } else {
            "Close"
        };

        Router::call(self.peer_addr, req, self.state)
            .map(move |resp| {
                resp.map(|mut resp| {
                    resp.headers_mut().insert(header::CONNECTION, keepalive.parse().unwrap());
                    resp
                })
            })
            .boxed()
    }
}
<|endoftext|>


<commit_before>use std::error;
use std::fs;
use std::io::Read;

use itertools::Itertools;

use fat;

pub fn add_file(args: &[String])
    -> Result<(), Box<error::Error>>
{
    expect_args!(args, 2);

    let file_name  = args[0].clone();
    let image_name = args[1].clone();
    let fat_file_name = if args.len() > 2 {
        args[2].clone()
    } else {
        file_name.clone()
    };

    let mut image = fat::Image::from_file(image_name.clone())?;

    // Don't overwrite a preexisting file.
    if let Ok(_) = image.get_file_entry(file_name.clone()) {
        return Err(errorf!("file {} already exists", file_name));
    }

    // Ensure input file exists.
    let file = fs::File::open(file_name)?;
    let metadata = file.metadata()?;

    // Create a root dir entry.
    let (entry, index) =
        image.create_file_entry(fat_file_name, metadata.len() as u32)?;

    // Get free FAT entries, fill sectors with file data.
    for chunk in &file.bytes().chunks(image.sector_size()) {
        let chunk = chunk
            .map(|b_res| b_res.unwrap_or(0))
            .collect::<Vec<_>>();

        // Get free sector.
        let entry_index: usize;
        match image.get_free_fat_entry() {
            Some(i) => entry_index = i,
            None => {
                // TODO: Remove entries written so far.
                panic!("image ran out of space while writing file")
            },
        }

        // Write chunk.
        image.write_data_sector(entry_index, &chunk)?;
    }

    image.save_file_entry(entry, index)?;
    image.save(image_name)?;
    Ok(())
}
<commit_msg>command/add: try basename before full path as name<commit_after>use std::error;
use std::fs;
use std::path;
use std::io::Read;

use itertools::Itertools;

use fat;

pub fn add_file(args: &[String])
    -> Result<(), Box<error::Error>>
{
    expect_args!(args, 2);

    let file_name  = args[0].clone();
    let image_name = args[1].clone();
    let fat_file_name = if args.len() > 2 {
        args[2].clone()
    } else {
        match path::Path::new(&file_name).file_name() {
            Some(n) => n.to_string_lossy().into_owned(),
            None => file_name.clone(),
        }
    };

    let mut image = fat::Image::from_file(image_name.clone())?;

    // Don't overwrite a preexisting file.
    if let Ok(_) = image.get_file_entry(file_name.clone()) {
        return Err(errorf!("file {} already exists", file_name));
    }

    // Ensure input file exists.
    let file = fs::File::open(file_name)?;
    let metadata = file.metadata()?;

    // Create a root dir entry.
    let (entry, index) =
        image.create_file_entry(fat_file_name, metadata.len() as u32)?;

    // Get free FAT entries, fill sectors with file data.
    for chunk in &file.bytes().chunks(image.sector_size()) {
        let chunk = chunk
            .map(|b_res| b_res.unwrap_or(0))
            .collect::<Vec<_>>();

        // Get free sector.
        let entry_index: usize;
        match image.get_free_fat_entry() {
            Some(i) => entry_index = i,
            None => {
                // TODO: Remove entries written so far.
                panic!("image ran out of space while writing file")
            },
        }

        // Write chunk.
        image.write_data_sector(entry_index, &chunk)?;
    }

    image.save_file_entry(entry, index)?;
    image.save(image_name)?;
    Ok(())
}
<|endoftext|>


<commit_before>//  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.
//! Flags contains code for converting a UCG Val into the json output target.
use std;
use std::io::Write;
use std::rc::Rc;

use serde_json;

use ast;
use build::Val;
use convert::traits::{Converter, Result};

/// JsonConverter implements the logic for converting a Val into the json output format.
pub struct JsonConverter {}

impl JsonConverter {
    pub fn new() -> Self {
        JsonConverter {}
    }

    fn convert_list(&self, items: &Vec<Rc<Val>>) -> std::io::Result<serde_json::Value> {
        let mut v = Vec::new();
        for val in items.iter() {
            v.push(try!(self.convert_value(val)));
        }
        Ok(serde_json::Value::Array(v))
    }

    fn convert_tuple(
        &self,
        items: &Vec<(ast::PositionedItem<String>, Rc<Val>)>,
    ) -> std::io::Result<serde_json::Value> {
        let mut mp = serde_json::Map::new();
        for &(ref k, ref v) in items.iter() {
            mp.entry(k.val.clone())
                .or_insert(try!(self.convert_value(v)));
        }
        Ok(serde_json::Value::Object(mp))
    }

    fn convert_value(&self, v: &Val) -> std::io::Result<serde_json::Value> {
        let jsn_val = match v {
            &Val::Boolean(b) => serde_json::Value::Bool(b),
            &Val::Empty => serde_json::Value::Null,
            &Val::Float(f) => {
                let n = match serde_json::Number::from_f64(f) {
                    Some(n) => n,
                    // In theory this should never happen. But on the off chance that it does...
                    None => panic!("Float is too large or Not a Number {}", f),
                };
                serde_json::Value::Number(n)
            }
            &Val::Int(i) => {
                let n = match serde_json::Number::from_f64(i as f64) {
                    Some(n) => n,
                    // In theory this should never happen. But on the off chance that it does...
                    None => panic!("Float is too large or Not a Number {}", i),
                };
                serde_json::Value::Number(n)
            }
            &Val::Str(ref s) => serde_json::Value::String(s.clone()),
            &Val::Macro(_) => {
                eprintln!("Skipping macro encoding as null...");
                serde_json::Value::Null
            }
            &Val::List(ref l) => try!(self.convert_list(l)),
            &Val::Tuple(ref t) => try!(self.convert_tuple(t)),
        };
        Ok(jsn_val)
    }

    fn write(&self, v: &Val, w: &mut Write) -> Result {
        let jsn_val = try!(self.convert_value(v));
        try!(serde_json::to_writer(w, &jsn_val));
        Ok(())
    }
}

impl Converter for JsonConverter {
    fn convert(&self, v: Rc<Val>, mut w: &mut Write) -> Result {
        self.write(&v, &mut w)
    }

    fn file_ext(&self) -> String {
        String::from("json")
    }

    fn description(&self) -> String {
        "Convert ucg Vals into valid json.".to_string()
    }
}
<commit_msg>FEATURE: Pretty print json output<commit_after>//  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.
//! Flags contains code for converting a UCG Val into the json output target.
use std;
use std::io::Write;
use std::rc::Rc;

use serde_json;

use ast;
use build::Val;
use convert::traits::{Converter, Result};

/// JsonConverter implements the logic for converting a Val into the json output format.
pub struct JsonConverter {}

impl JsonConverter {
    pub fn new() -> Self {
        JsonConverter {}
    }

    fn convert_list(&self, items: &Vec<Rc<Val>>) -> std::io::Result<serde_json::Value> {
        let mut v = Vec::new();
        for val in items.iter() {
            v.push(try!(self.convert_value(val)));
        }
        Ok(serde_json::Value::Array(v))
    }

    fn convert_tuple(
        &self,
        items: &Vec<(ast::PositionedItem<String>, Rc<Val>)>,
    ) -> std::io::Result<serde_json::Value> {
        let mut mp = serde_json::Map::new();
        for &(ref k, ref v) in items.iter() {
            mp.entry(k.val.clone())
                .or_insert(try!(self.convert_value(v)));
        }
        Ok(serde_json::Value::Object(mp))
    }

    fn convert_value(&self, v: &Val) -> std::io::Result<serde_json::Value> {
        let jsn_val = match v {
            &Val::Boolean(b) => serde_json::Value::Bool(b),
            &Val::Empty => serde_json::Value::Null,
            &Val::Float(f) => {
                let n = match serde_json::Number::from_f64(f) {
                    Some(n) => n,
                    // In theory this should never happen. But on the off chance that it does...
                    None => panic!("Float is too large or Not a Number {}", f),
                };
                serde_json::Value::Number(n)
            }
            &Val::Int(i) => {
                let n = match serde_json::Number::from_f64(i as f64) {
                    Some(n) => n,
                    // In theory this should never happen. But on the off chance that it does...
                    None => panic!("Float is too large or Not a Number {}", i),
                };
                serde_json::Value::Number(n)
            }
            &Val::Str(ref s) => serde_json::Value::String(s.clone()),
            &Val::Macro(_) => {
                eprintln!("Skipping macro encoding as null...");
                serde_json::Value::Null
            }
            &Val::List(ref l) => try!(self.convert_list(l)),
            &Val::Tuple(ref t) => try!(self.convert_tuple(t)),
        };
        Ok(jsn_val)
    }

    fn write(&self, v: &Val, w: &mut Write) -> Result {
        let jsn_val = try!(self.convert_value(v));
        try!(serde_json::to_writer_pretty(w, &jsn_val));
        Ok(())
    }
}

impl Converter for JsonConverter {
    fn convert(&self, v: Rc<Val>, mut w: &mut Write) -> Result {
        self.write(&v, &mut w)
    }

    fn file_ext(&self) -> String {
        String::from("json")
    }

    fn description(&self) -> String {
        "Convert ucg Vals into valid json.".to_string()
    }
}
<|endoftext|>