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

//!
//! # Regular language
//!
//! This provides a data structure representing a regular language. This is a more generalised form of a regular
//! expression (it supports symbol types other than simple strings). A regular language using the `u8` symbol forms
//! a simple regular expression.
//!

use std::iter::FromIterator;
use std::ops::Range;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone, PartialEq, Eq)]
pub enum Pattern<Symbol> {
    ///
    /// Matches nothing
    ///
    Epsilon,

    ///
    /// Matches a specific literal phrase
    ///
    Match(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    MatchAll(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    MatchAny(Vec<Pattern<Symbol>>)
}

pub use Pattern::*;

///
/// Implemented by things that can be converted into a pattern
///
pub trait ToPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn to_pattern(&self) -> Pattern<Symbol>;
}

///
/// Implemented by things that can be converted into a pattern
///
pub trait IntoPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn into_pattern(self) -> Pattern<Symbol>;
}

impl<Symbol> IntoPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self
    }
}

impl<Symbol> IntoPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        *self
    }
}

impl<'a, Symbol: Clone, PatternType: ToPattern<Symbol>> IntoPattern<Symbol> for &'a PatternType {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a, Symbol: Clone> IntoPattern<Symbol> for &'a [Symbol] {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a> IntoPattern<char> for &'a str {
    #[inline]
    fn into_pattern(self) -> Pattern<char> {
        self.to_pattern()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        self.clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        (**self).clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Vec<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.clone())
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for [Symbol] {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.to_vec())
    }
}

impl ToPattern<char> for str {
    #[inline]
    fn to_pattern(&self) -> Pattern<char> {
        Match(Vec::from_iter(self.chars()))
    }
}

///
/// Implemented by things that can build up patterns
///
/// Patterns are built in boxes to avoid the need for a lot of copying
///
pub trait PatternBuilder<Symbol> {
    /// Creates an empty pattern
    fn empty() -> Pattern<Symbol>;

    /// Appends a pattern to this one
    fn append(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol>;

    /// Matches either this pattern or the specified pattern
    fn or(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol>;

    /// Repeats the current pattern forever
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol>;

    /// Repeats the current pattern for a certain number of iterations
    fn repeat(self, count: Range<u32>) -> Pattern<Symbol>;
}

impl<Symbol> Pattern<Symbol> {

}

impl<Symbol> PatternBuilder<Symbol> for Pattern<Symbol> {
    fn empty() -> Pattern<Symbol> {
        Epsilon
    }

    fn append(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol> {
        MatchAll(vec![self, pattern.to_pattern()])
    }

    fn or(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol> {
        MatchAny(vec![self, pattern.to_pattern()])
    }

    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol> {
        RepeatInfinite(min_count, Box::new(self))
    }

    fn repeat(self, count: Range<u32>) -> Pattern<Symbol> {
        Repeat(count, Box::new(self))
    }
}

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

    #[test]
    fn can_convert_vec_to_pattern() {
        let pattern = vec![0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_array_to_pattern() {
        let pattern = [0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_string_to_pattern() {
        let pattern = "abc".into_pattern();

        assert!(pattern == Match(vec!['a', 'b', 'c']));
    }
}<commit_msg>Split PatternBuilder into two and use the IntoPattern trait for the ‘self’ side<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.
//

//!
//! # Regular language
//!
//! This provides a data structure representing a regular language. This is a more generalised form of a regular
//! expression (it supports symbol types other than simple strings). A regular language using the `u8` symbol forms
//! a simple regular expression.
//!

use std::iter::FromIterator;
use std::ops::Range;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone, PartialEq, Eq)]
pub enum Pattern<Symbol> {
    ///
    /// Matches nothing
    ///
    Epsilon,

    ///
    /// Matches a specific literal phrase
    ///
    Match(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    MatchAll(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    MatchAny(Vec<Pattern<Symbol>>)
}

pub use Pattern::*;

///
/// Implemented by things that can be converted into a pattern
///
pub trait ToPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn to_pattern(&self) -> Pattern<Symbol>;
}

///
/// Implemented by things that can be converted into a pattern
///
pub trait IntoPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn into_pattern(self) -> Pattern<Symbol>;
}

impl<Symbol> IntoPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self
    }
}

impl<Symbol> IntoPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        *self
    }
}

impl<'a, Symbol: Clone, PatternType: ToPattern<Symbol>> IntoPattern<Symbol> for &'a PatternType {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a, Symbol: Clone> IntoPattern<Symbol> for &'a [Symbol] {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a> IntoPattern<char> for &'a str {
    #[inline]
    fn into_pattern(self) -> Pattern<char> {
        self.to_pattern()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        self.clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        (**self).clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Vec<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.clone())
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for [Symbol] {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.to_vec())
    }
}

impl ToPattern<char> for str {
    #[inline]
    fn to_pattern(&self) -> Pattern<char> {
        Match(Vec::from_iter(self.chars()))
    }
}

///
/// Implemented by things that can modify existing patterns into other forms
///
/// Pattern transformers act by altering a single pattern object into a new form
///
pub trait PatternTransformer<Symbol> {
    /// Repeats the current pattern forever
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol>;

    /// Repeats the current pattern for a certain number of iterations
    fn repeat(self, count: Range<u32>) -> Pattern<Symbol>;
}

///
/// Implemented by things that combine patterns together to create new patterns
///
pub trait PatternCreator<Symbol> {
    /// Appends a pattern to this one
    fn append(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol>;

    /// Matches either this pattern or the specified pattern
    fn or(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol>;
}

impl<Symbol> Pattern<Symbol> {

}

impl<Symbol, PatternType: IntoPattern<Symbol>> PatternTransformer<Symbol> for PatternType {
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol> {
        RepeatInfinite(min_count, Box::new(self.into_pattern()))
    }

    fn repeat(self, count: Range<u32>) -> Pattern<Symbol> {
        Repeat(count, Box::new(self.into_pattern()))
    }
}

impl<Symbol, PatternType: IntoPattern<Symbol>> PatternCreator<Symbol> for PatternType {
    fn append(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol> {
        MatchAll(vec![self.into_pattern(), pattern.to_pattern()])
    }

    fn or(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol> {
        MatchAny(vec![self.into_pattern(), pattern.to_pattern()])
    }
}

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

    #[test]
    fn can_convert_vec_to_pattern() {
        let pattern = vec![0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_array_to_pattern() {
        let pattern = [0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_string_to_pattern() {
        let pattern = "abc".into_pattern();

        assert!(pattern == Match(vec!['a', 'b', 'c']));
    }
}<|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.
//

//!
//! # Regular language
//!
//! This provides a data structure representing a regular language. This is a more generalised form of a regular
//! expression (it supports symbol types other than simple strings). A regular language using the `u8` symbol forms
//! a simple regular expression.
//!

use super::phrase::*;
use std::ops::Range;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone, PartialEq, Eq)]
pub enum Pattern<Symbol> {
    ///
    /// Matches nothing
    ///
    Epsilon,

    ///
    /// Matches a specific literal phrase
    ///
    Match(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    MatchAll(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    MatchAny(Vec<Pattern<Symbol>>)
}

pub use Pattern::*;

///
/// Implemented by things that can be converted into a pattern
///
pub trait IntoPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn into_pattern(self) -> Pattern<Symbol>;
}

/* -- want this to work, but it doesn't due to the trait below

impl<Symbol> IntoPattern<Symbol> for Pattern<Symbol> {
    fn into_pattern(self) -> Pattern<Symbol> {
        self
    }
}

impl<'a, Symbol: Clone> IntoPattern<Symbol> for &'a Pattern<Symbol> {
    fn into_pattern(self) -> Pattern<Symbol> {
        self.clone()
    }
}

impl<'a, Symbol: Clone> IntoPattern<Symbol> for &'a Box<Pattern<Symbol>> {
    fn into_pattern(self) -> Pattern<Symbol> {
        (**self).clone()
    }
}
*/

impl<'a, Symbol: Clone, Iterator: PhraseIterator<Symbol>, PhraseType: Phrase<Symbol, PhraseIterator=Iterator>> IntoPattern<Symbol> for PhraseType {
    ///
    /// Phrases can be turned into a literal matching pattern
    ///
    fn into_pattern(self) -> Pattern<Symbol> {
        let mut result = vec![];
        let mut reader = self.get_symbols();

        loop {
            match reader.next_symbol() {
                Some(symbol)    => result.push(symbol.clone()),
                None            => break
            }
        }

        Match(result)
    }
}

///
/// Implemented by things that can build up patterns
///
/// Patterns are built in boxes to avoid the need for a lot of copying
///
pub trait PatternBuilder<Symbol> {
    /// Creates an empty pattern
    fn empty() -> Box<Pattern<Symbol>>;

    /// Appends a pattern to this one
    fn append(self, pattern: IntoPattern<Symbol>) -> Box<Pattern<Symbol>>;

    /// Repeats the current pattern forever
    fn repeat_forever(self, min_count: u32) -> Box<Pattern<Symbol>>;

    /// Repeats the current pattern for a certain number of iterations
    fn repeat(self, count: Range<u32>) -> Box<Pattern<Symbol>>;
}

impl<Symbol> Pattern<Symbol> {

}

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

    #[test]
    fn can_convert_array_to_pattern() {
        let pattern = [0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_string_to_pattern() {
        let pattern = "abc".into_pattern();

        assert!(pattern == Match(vec!['a', 'b', 'c']));
    }
}<commit_msg>Maybe don’t want to box here?<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.
//

//!
//! # Regular language
//!
//! This provides a data structure representing a regular language. This is a more generalised form of a regular
//! expression (it supports symbol types other than simple strings). A regular language using the `u8` symbol forms
//! a simple regular expression.
//!

use super::phrase::*;
use std::ops::Range;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone, PartialEq, Eq)]
pub enum Pattern<Symbol> {
    ///
    /// Matches nothing
    ///
    Epsilon,

    ///
    /// Matches a specific literal phrase
    ///
    Match(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    MatchAll(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    MatchAny(Vec<Pattern<Symbol>>)
}

pub use Pattern::*;

///
/// Implemented by things that can be converted into a pattern
///
pub trait IntoPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn into_pattern(self) -> Pattern<Symbol>;
}

/* -- want this to work, but it doesn't due to the trait below

impl<Symbol> IntoPattern<Symbol> for Pattern<Symbol> {
    fn into_pattern(self) -> Pattern<Symbol> {
        self
    }
}

impl<'a, Symbol: Clone> IntoPattern<Symbol> for &'a Pattern<Symbol> {
    fn into_pattern(self) -> Pattern<Symbol> {
        self.clone()
    }
}

impl<'a, Symbol: Clone> IntoPattern<Symbol> for &'a Box<Pattern<Symbol>> {
    fn into_pattern(self) -> Pattern<Symbol> {
        (**self).clone()
    }
}
*/

impl<'a, Symbol: Clone, Iterator: PhraseIterator<Symbol>, PhraseType: Phrase<Symbol, PhraseIterator=Iterator>> IntoPattern<Symbol> for PhraseType {
    ///
    /// Phrases can be turned into a literal matching pattern
    ///
    fn into_pattern(self) -> Pattern<Symbol> {
        let mut result = vec![];
        let mut reader = self.get_symbols();

        loop {
            match reader.next_symbol() {
                Some(symbol)    => result.push(symbol.clone()),
                None            => break
            }
        }

        Match(result)
    }
}

///
/// Implemented by things that can build up patterns
///
/// Patterns are built in boxes to avoid the need for a lot of copying
///
pub trait PatternBuilder<Symbol> {
    /// Creates an empty pattern
    fn empty() -> Pattern<Symbol>;

    /// Appends a pattern to this one
    fn append(self, pattern: IntoPattern<Symbol>) -> Pattern<Symbol>;

    /// Repeats the current pattern forever
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol>;

    /// Repeats the current pattern for a certain number of iterations
    fn repeat(self, count: Range<u32>) -> Pattern<Symbol>;
}

impl<Symbol> Pattern<Symbol> {

}

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

    #[test]
    fn can_convert_array_to_pattern() {
        let pattern = [0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_string_to_pattern() {
        let pattern = "abc".into_pattern();

        assert!(pattern == Match(vec!['a', 'b', 'c']));
    }
}<|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.
//

//!
//! # Regular language
//!
//! This provides a data structure representing a regular language. This is a more generalised form of a regular
//! expression (it supports symbol types other than simple strings). A regular language using the `u8` symbol forms
//! a simple regular expression.
//!

use std::iter::FromIterator;
use std::ops::Range;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone, PartialEq, Eq)]
pub enum Pattern<Symbol> {
    ///
    /// Matches nothing
    ///
    Epsilon,

    ///
    /// Matches a specific literal phrase
    ///
    Match(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    MatchAll(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    MatchAny(Vec<Pattern<Symbol>>)
}

pub use Pattern::*;

///
/// Implemented by things that can be converted into a pattern
///
pub trait ToPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn to_pattern(&self) -> Pattern<Symbol>;
}

///
/// Implemented by things that can be converted into a pattern
///
pub trait IntoPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn into_pattern(self) -> Pattern<Symbol>;
}

impl<Symbol> IntoPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self
    }
}

impl<Symbol> IntoPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        *self
    }
}

impl<'a, Symbol: Clone, PatternType: ToPattern<Symbol>> IntoPattern<Symbol> for &'a PatternType {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a, Symbol: Clone> IntoPattern<Symbol> for &'a [Symbol] {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a> IntoPattern<char> for &'a str {
    #[inline]
    fn into_pattern(self) -> Pattern<char> {
        self.to_pattern()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        self.clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        (**self).clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Vec<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.clone())
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for [Symbol] {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.to_vec())
    }
}

impl ToPattern<char> for str {
    #[inline]
    fn to_pattern(&self) -> Pattern<char> {
        Match(Vec::from_iter(self.chars()))
    }
}

///
/// Implemented by things that can modify existing patterns into other forms
///
/// Pattern transformers act by altering a single pattern object into a new form
///
pub trait PatternTransformer<Symbol> {
    /// Repeats the current pattern forever
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol>;

    /// Repeats the current pattern for a certain number of iterations
    fn repeat(self, count: Range<u32>) -> Pattern<Symbol>;
}

///
/// Implemented by things that combine patterns together to create new patterns
///
pub trait PatternCreator<Symbol> {
    /// Appends a pattern to this one
    fn append(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol>;

    /// Matches either this pattern or the specified pattern
    fn or(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol>;
}

impl<Symbol> Pattern<Symbol> {

}

impl<Symbol, PatternType: IntoPattern<Symbol>> PatternTransformer<Symbol> for PatternType {
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol> {
        RepeatInfinite(min_count, Box::new(self.into_pattern()))
    }

    fn repeat(self, count: Range<u32>) -> Pattern<Symbol> {
        Repeat(count, Box::new(self.into_pattern()))
    }
}

impl<Symbol, PatternType: IntoPattern<Symbol>> PatternCreator<Symbol> for PatternType {
    fn append(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol> {
        MatchAll(vec![self.into_pattern(), pattern.to_pattern()])
    }

    fn or(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol> {
        MatchAny(vec![self.into_pattern(), pattern.to_pattern()])
    }
}

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

    #[test]
    fn can_convert_vec_to_pattern() {
        let pattern = vec![0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_array_to_pattern() {
        let pattern = [0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_string_to_pattern() {
        let pattern = "abc".into_pattern();

        assert!(pattern == Match(vec!['a', 'b', 'c']));
    }

    #[test]
    fn can_repeat_pattern() {
        let pattern = "abc".repeat(1..2);

        assert!(pattern == Repeat(1..2, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_repeat_pattern_forever() {
        let pattern = "abc".repeat_forever(0);

        assert!(pattern == RepeatInfinite(0, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_append_pattern() {
        let pattern = "abc".append(&"def".into_pattern());

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
        //assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c', 'd', 'e', 'f'])]));
    }

    #[test]
    fn can_or_pattern() {
        let pattern = "abc".or(&"def".into_pattern());

        assert!(pattern == MatchAny(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }
}
<commit_msg>Change the combining method of pattern building to use IntoPattern<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.
//

//!
//! # Regular language
//!
//! This provides a data structure representing a regular language. This is a more generalised form of a regular
//! expression (it supports symbol types other than simple strings). A regular language using the `u8` symbol forms
//! a simple regular expression.
//!

use std::iter::FromIterator;
use std::ops::Range;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone, PartialEq, Eq)]
pub enum Pattern<Symbol> {
    ///
    /// Matches nothing
    ///
    Epsilon,

    ///
    /// Matches a specific literal phrase
    ///
    Match(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    MatchAll(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    MatchAny(Vec<Pattern<Symbol>>)
}

pub use Pattern::*;

///
/// Implemented by things that can be converted into a pattern
///
pub trait ToPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn to_pattern(&self) -> Pattern<Symbol>;
}

///
/// Implemented by things that can be converted into a pattern
///
pub trait IntoPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn into_pattern(self) -> Pattern<Symbol>;
}

impl<Symbol> IntoPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self
    }
}

impl<Symbol> IntoPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        *self
    }
}

impl<'a, Symbol: Clone, PatternType: ToPattern<Symbol>> IntoPattern<Symbol> for &'a PatternType {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a, Symbol: Clone> IntoPattern<Symbol> for &'a [Symbol] {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a> IntoPattern<char> for &'a str {
    #[inline]
    fn into_pattern(self) -> Pattern<char> {
        self.to_pattern()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        self.clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        (**self).clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Vec<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.clone())
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for [Symbol] {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.to_vec())
    }
}

impl ToPattern<char> for str {
    #[inline]
    fn to_pattern(&self) -> Pattern<char> {
        Match(Vec::from_iter(self.chars()))
    }
}

///
/// Implemented by things that can modify existing patterns into other forms
///
/// Pattern transformers act by altering a single pattern object into a new form
///
pub trait PatternTransformer<Symbol> {
    /// Repeats the current pattern forever
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol>;

    /// Repeats the current pattern for a certain number of iterations
    fn repeat(self, count: Range<u32>) -> Pattern<Symbol>;
}

///
/// Implemented by things that combine patterns together to create new patterns
///
pub trait PatternCombiner<Symbol, SecondPattern: IntoPattern<Symbol>> {
    /// Appends a pattern to this one
    fn append(self, pattern: SecondPattern) -> Pattern<Symbol>;

    /// Matches either this pattern or the specified pattern
    fn or(self, pattern: SecondPattern) -> Pattern<Symbol>;
}

impl<Symbol> Pattern<Symbol> {

}

impl<Symbol, PatternType: IntoPattern<Symbol>> PatternTransformer<Symbol> for PatternType {
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol> {
        RepeatInfinite(min_count, Box::new(self.into_pattern()))
    }

    fn repeat(self, count: Range<u32>) -> Pattern<Symbol> {
        Repeat(count, Box::new(self.into_pattern()))
    }
}

impl<Symbol, PatternType: IntoPattern<Symbol>, SecondPatternType: IntoPattern<Symbol>> PatternCombiner<Symbol, SecondPatternType> for PatternType {
    fn append(self, pattern: SecondPatternType) -> Pattern<Symbol> {
        MatchAll(vec![self.into_pattern(), pattern.into_pattern()])
    }

    fn or(self, pattern: SecondPatternType) -> Pattern<Symbol> {
        MatchAny(vec![self.into_pattern(), pattern.into_pattern()])
    }
}

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

    #[test]
    fn can_convert_vec_to_pattern() {
        let pattern = vec![0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_array_to_pattern() {
        let pattern = [0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_string_to_pattern() {
        let pattern = "abc".into_pattern();

        assert!(pattern == Match(vec!['a', 'b', 'c']));
    }

    #[test]
    fn can_repeat_pattern() {
        let pattern = "abc".repeat(1..2);

        assert!(pattern == Repeat(1..2, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_repeat_pattern_forever() {
        let pattern = "abc".repeat_forever(0);

        assert!(pattern == RepeatInfinite(0, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_append_pattern() {
        let pattern = "abc".append("def");

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
        //assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c', 'd', 'e', 'f'])]));
    }

    #[test]
    fn can_or_pattern() {
        let pattern = "abc".or("def");

        assert!(pattern == MatchAny(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }
}
<|endoftext|>


<commit_before>// DOCS

#![feature(plugin,core,collections,std_misc)]
#![plugin(peg_syntax_ext)]

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::borrow::ToOwned;
use std::str::FromStr;
use std::fmt;
use std::error::Error;

pub struct Property {
    /// Key in component.
    pub name: String,

    /// Parameters.
    pub params: HashMap<String, String>,

    /// Value as unparsed string.
    pub raw_value: String,

    /// Property group. E.g. a contentline like `foo.FN:Markus` would result in the group being
    /// `"foo"`.
    pub prop_group: Option<String>
}

impl Property {
    /// Create property from unescaped string.
    pub fn new(name: &str, value: &str) -> Property {
        Property {
            name: name.to_owned(),
            params: HashMap::new(),
            raw_value: escape_chars(value),
            prop_group: None
        }
    }

    /// Get value as unescaped string.
    pub fn value_as_string(&self) -> String {
        unescape_chars(self.raw_value.as_slice())
    }
}

impl Clone for Property {
    fn clone(&self) -> Self {
        Property {
            name: self.name.clone(),
            params: self.params.clone(),
            raw_value: self.raw_value.clone(),
            prop_group: self.prop_group.clone()
        }
    }
}

pub struct Component {
    /// The name of the component, such as `VCARD` or `VEVENT`.
    pub name: String,

    /// The component's properties.
    pub props: HashMap<String, Vec<Property>>,

    /// The component's child- or sub-components.
    pub subcomponents: Vec<Component>
}

impl Component {
    pub fn new(name: &str) -> Component {
        Component {
            name: name.to_string(),
            props: HashMap::new(),
            subcomponents: vec![]
        }
    }

    /// Retrieve one property (from many) by key. Returns `None` if nothing is found.
    pub fn single_prop(&self, key: &str) -> Option<&Property> {
        match self.props.get(key) {
            Some(x) => {
                match x.len() {
                    1 => Some(&x[0]),
                    _ => None
                }
            },
            None => None
        }
    }

    /// Retrieve a mutable vector of properties for this key. Creates one (and inserts it into the
    /// component) if none exists.
    pub fn all_props_mut(&mut self, key: &str) -> &mut Vec<Property> {
        match self.props.entry(String::from_str(key)) {
            Occupied(values) => values.into_mut(),
            Vacant(values) => values.insert(vec![])
        }
    }

    /// Retrieve properties by key. Returns an empty slice if key doesn't exist.
    pub fn all_props(&self, key: &str) -> &[Property] {
        static EMPTY: &'static [Property] = &[];
        match self.props.get(key) {
            Some(values) => values.as_slice(),
            None => EMPTY
        }
    }
}

impl FromStr for Component {
    type Err = String;

    /// Same as `vobject::parse_component`, but without the error messages.
    fn from_str(s: &str) -> Result<Component, String> {
        match parse_component(s) {
            Ok(x) => Ok(x),
            Err(e) => Err(e.into_string())
        }
    }
}

/// Parse a component. The error value is a human-readable message.
pub fn parse_component(s: &str) -> ParseResult<Component> {
    // XXX: The unfolding should be worked into the PEG
    // See feature request: https://github.com/kevinmehall/rust-peg/issues/26
    let unfolded = unfold_lines(s);
    match parser::component(unfolded.as_slice()) {
        Ok(x) => Ok(x),
        Err(e) => Err(ParseError::from_peg_error(e))
    }
}

/// Write a component. The error value is a human-readable message.
pub fn write_component(c: &Component) -> String {
    fn inner(buf: &mut String, c: &Component) {
        buf.push_str("BEGIN:");
        buf.push_str(c.name.as_slice());&
        buf.push_str("\r\n");

        for (prop_name, props) in c.props.iter() {
            for prop in props.iter() {
                match prop.prop_group {
                    Some(ref x) => { buf.push_str(x.as_slice()); buf.push('.'); },
                    None => ()
                };
                buf.push_str(prop_name.as_slice());
                for (param_key, param_value) in prop.params.iter() {
                    buf.push(';');
                    buf.push_str(param_key.as_slice());
                    buf.push('=');
                    buf.push_str(param_value.as_slice());
                };
                buf.push(':');
                buf.push_str(fold_line(prop.raw_value.as_slice()).as_slice());
                buf.push_str("\r\n");
            };
        };

        for subcomponent in c.subcomponents.iter() {
            inner(buf, subcomponent);
        };

        buf.push_str("END:");
        buf.push_str(c.name.as_slice());
        buf.push_str("\r\n");
    }

    let mut buf = String::new();
    inner(&mut buf, c);
    buf
}

/// Escape text for a VObject property value.
pub fn escape_chars(s: &str) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\n")
        .replace("\\", "\\\\")
        .replace(";", "\\;")
        .replace(",", "\\,")
        .replace("\r\n", "\\n")
        .replace("\n", "\\n")
}

/// Unescape text from a VObject property value.
pub fn unescape_chars(s: &str) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\\n")
        .replace("\r\n", "\n")
        .replace("\\n", "\n")
        .replace("\\,", ",")
        .replace("\\;", ";")
        .replace("\\\\", "\\")
}

/// Unfold contentline.
pub fn unfold_lines(s: &str) -> String {
    s
        .replace("\r\n ", "").replace("\r\n\t", "")
        .replace("\n ", "").replace("\n\t", "")
        .replace("\r ", "").replace("\r\t", "")
}

/// Fold contentline to 75 chars. This function assumes the input to be unfolded, which means no
/// '\n' or '\r' in it.
pub fn fold_line(s: &str) -> String {
    let mut rv = String::new();
    for (i, c) in s.chars().enumerate() {
        rv.push(c);
        if i != 0 && i % 75 == 0 {
            rv.push_str("\r\n ");
        };
    };
    rv
}

#[derive(PartialEq, Eq, Debug)]
pub struct ParseError {
    desc: String,
    orig: Option<parser::ParseError>
}

pub type ParseResult<T> = Result<T, ParseError>;

impl Error for ParseError {
    fn description(&self) -> &str {
        self.desc.as_slice()
    }

    fn cause(&self) -> Option<&Error> {
        match self.parser_error() {
            Some(x) => Some(&*x),
            None => None
        }
    }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.description().fmt(f)
    }
}

impl ParseError {
    pub fn new(desc: String, cause: Option<parser::ParseError>) -> Self {
        ParseError {
            desc: desc,
            orig: cause
        }
    }

    pub fn from_peg_error(e: parser::ParseError) -> Self {
        ParseError {
            desc: format!("{}", e).to_owned(),
            orig: Some(e)
        }
    }

    pub fn into_string(self) -> String {
        self.desc
    }

    /// Access the underlying parser error.
    pub fn parser_error(&self) -> Option<&parser::ParseError> {
        self.orig.as_ref()
    }

    /// The line where the error occured.
    ///
    /// The value might be warped because content lines are unfolded before the parser keeps track
    /// of line numbers.
    pub fn line(&self) -> Option<&usize> {
        match self.parser_error() {
            Some(e) => Some(&e.line),
            None => None
        }
    }

    /// The column where the error occured.
    ///
    /// The value might be warped because content lines are unfolded before the parser keeps track
    /// of line numbers.
    pub fn column(&self) -> Option<&usize> {
        match self.parser_error() {
            Some(e) => Some(&e.column),
            None => None
        }
    }
}

peg! parser(r#"
use super::{Component,Property};
use std::collections::HashMap;

components -> Vec<Component>
    = cs:component ** eols __ { cs }

    #[pub]
    component -> Component
        = name:component_begin
          ps:props
          cs:components
          component_end {
            let mut rv = Component::new(name);
            rv.subcomponents = cs;

            for (k, v) in ps.into_iter() {
                rv.all_props_mut(k).push(v);
            };

            rv
        }

    component_begin -> &'input str
        = "BEGIN:" v:value __ { v }

    component_end -> &'input str
        = "END:" v:value __ { v }

props -> Vec<(&'input str, Property)>
    = ps:prop ++ eols __ { ps }

    prop -> (&'input str, Property)
        = !"BEGIN:" !"END:" g:group? k:name p:params ":" v:value {
            (k, Property { name: k.to_string(), params: p, raw_value: v.to_string(), prop_group: g })
        }

    group -> String
        = g:group_name "." { g.to_string() }

        group_name -> &'input str
            = group_char+ { match_str }

    name -> &'input str
        = iana_token+ { match_str }

    params -> HashMap<String, String>
        = ps:(";" p:param {p})* {
            let mut rv: HashMap<String, String> = HashMap::with_capacity(ps.len());
            rv.extend(ps.into_iter().map(|(k, v)| (k.to_string(), v.to_string())));
            rv
        }

        param -> (&'input str, &'input str)
            // FIXME: Doesn't handle comma-separated values
            = k:param_name v:("=" v:param_value { v })? {
                (k, match v {
                    Some(x) => x,
                    None => ""
                })
            }

        param_name -> &'input str
            = iana_token+ { match_str }

        param_value -> &'input str
            = x:(quoted_string / param_text) { x }

        param_text -> &'input str
            = safe_char* { match_str }

    value -> &'input str
        = value_char+ { match_str }

quoted_string -> &'input str
    = dquote x:quoted_content dquote { x }

quoted_content -> &'input str
    = qsafe_char* { match_str }

iana_token = ([a-zA-Z0-9] / "-")+
group_char = ([a-zA-Z0-9] / "-")
qsafe_char = !dquote !ctl value_char
safe_char = !";" !":" qsafe_char

value_char = !eol .

eol = "\r\n" / "\n" / "\r"
dquote = "\""
eols = eol+

// Taken from vCard. vCalendar's is a subset. Together with the definition of "qsafe_char" this
// might reject a bunch of valid iCalendars, but I can't imagine one.
ctl = [\u{00}-\u{1F}] / "\u{7F}"

whitespace = " " / "\t"
__ = (eol / whitespace)*

"#);
<commit_msg>Nightly updates<commit_after>// DOCS

#![feature(plugin,collections,str_char)]
#![plugin(peg_syntax_ext)]

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::borrow::ToOwned;
use std::str::FromStr;
use std::fmt;
use std::error::Error;

pub struct Property {
    /// Key in component.
    pub name: String,

    /// Parameters.
    pub params: HashMap<String, String>,

    /// Value as unparsed string.
    pub raw_value: String,

    /// Property group. E.g. a contentline like `foo.FN:Markus` would result in the group being
    /// `"foo"`.
    pub prop_group: Option<String>
}

impl Property {
    /// Create property from unescaped string.
    pub fn new(name: &str, value: &str) -> Property {
        Property {
            name: name.to_owned(),
            params: HashMap::new(),
            raw_value: escape_chars(value),
            prop_group: None
        }
    }

    /// Get value as unescaped string.
    pub fn value_as_string(&self) -> String {
        unescape_chars(&self.raw_value[..])
    }
}

impl Clone for Property {
    fn clone(&self) -> Self {
        Property {
            name: self.name.clone(),
            params: self.params.clone(),
            raw_value: self.raw_value.clone(),
            prop_group: self.prop_group.clone()
        }
    }
}

pub struct Component {
    /// The name of the component, such as `VCARD` or `VEVENT`.
    pub name: String,

    /// The component's properties.
    pub props: HashMap<String, Vec<Property>>,

    /// The component's child- or sub-components.
    pub subcomponents: Vec<Component>
}

impl Component {
    pub fn new(name: &str) -> Component {
        Component {
            name: name.to_string(),
            props: HashMap::new(),
            subcomponents: vec![]
        }
    }

    /// Retrieve one property (from many) by key. Returns `None` if nothing is found.
    pub fn single_prop(&self, key: &str) -> Option<&Property> {
        match self.props.get(key) {
            Some(x) => {
                match x.len() {
                    1 => Some(&x[0]),
                    _ => None
                }
            },
            None => None
        }
    }

    /// Retrieve a mutable vector of properties for this key. Creates one (and inserts it into the
    /// component) if none exists.
    pub fn all_props_mut(&mut self, key: &str) -> &mut Vec<Property> {
        match self.props.entry(String::from_str(key)) {
            Occupied(values) => values.into_mut(),
            Vacant(values) => values.insert(vec![])
        }
    }

    /// Retrieve properties by key. Returns an empty slice if key doesn't exist.
    pub fn all_props(&self, key: &str) -> &[Property] {
        static EMPTY: &'static [Property] = &[];
        match self.props.get(key) {
            Some(values) => &values[..],
            None => EMPTY
        }
    }
}

impl FromStr for Component {
    type Err = String;

    /// Same as `vobject::parse_component`, but without the error messages.
    fn from_str(s: &str) -> Result<Component, String> {
        match parse_component(s) {
            Ok(x) => Ok(x),
            Err(e) => Err(e.into_string())
        }
    }
}

/// Parse a component. The error value is a human-readable message.
pub fn parse_component(s: &str) -> ParseResult<Component> {
    // XXX: The unfolding should be worked into the PEG
    // See feature request: https://github.com/kevinmehall/rust-peg/issues/26
    let unfolded = unfold_lines(s);
    match parser::component(&unfolded[..]) {
        Ok(x) => Ok(x),
        Err(e) => Err(ParseError::from_peg_error(e))
    }
}

/// Write a component. The error value is a human-readable message.
pub fn write_component(c: &Component) -> String {
    fn inner(buf: &mut String, c: &Component) {
        buf.push_str("BEGIN:");
        buf.push_str(&c.name[..]);
        buf.push_str("\r\n");

        for (prop_name, props) in c.props.iter() {
            for prop in props.iter() {
                match prop.prop_group {
                    Some(ref x) => { buf.push_str(&x[..]); buf.push('.'); },
                    None => ()
                };
                buf.push_str(&prop_name[..]);
                for (param_key, param_value) in prop.params.iter() {
                    buf.push(';');
                    buf.push_str(&param_key[..]);
                    buf.push('=');
                    buf.push_str(&param_value[..]);
                };
                buf.push(':');
                buf.push_str(&fold_line(&prop.raw_value[..])[..]);
                buf.push_str("\r\n");
            };
        };

        for subcomponent in c.subcomponents.iter() {
            inner(buf, subcomponent);
        };

        buf.push_str("END:");
        buf.push_str(&c.name[..]);
        buf.push_str("\r\n");
    }

    let mut buf = String::new();
    inner(&mut buf, c);
    buf
}

/// Escape text for a VObject property value.
pub fn escape_chars(s: &str) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\n")
        .replace("\\", "\\\\")
        .replace(";", "\\;")
        .replace(",", "\\,")
        .replace("\r\n", "\\n")
        .replace("\n", "\\n")
}

/// Unescape text from a VObject property value.
pub fn unescape_chars(s: &str) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\\n")
        .replace("\r\n", "\n")
        .replace("\\n", "\n")
        .replace("\\,", ",")
        .replace("\\;", ";")
        .replace("\\\\", "\\")
}

/// Unfold contentline.
pub fn unfold_lines(s: &str) -> String {
    s
        .replace("\r\n ", "").replace("\r\n\t", "")
        .replace("\n ", "").replace("\n\t", "")
        .replace("\r ", "").replace("\r\t", "")
}

/// Fold contentline to 75 chars. This function assumes the input to be unfolded, which means no
/// '\n' or '\r' in it.
pub fn fold_line(s: &str) -> String {
    let mut rv = String::new();
    for (i, c) in s.chars().enumerate() {
        rv.push(c);
        if i != 0 && i % 75 == 0 {
            rv.push_str("\r\n ");
        };
    };
    rv
}

#[derive(PartialEq, Eq, Debug)]
pub struct ParseError {
    desc: String,
    orig: Option<parser::ParseError>
}

pub type ParseResult<T> = Result<T, ParseError>;

impl Error for ParseError {
    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        match self.parser_error() {
            Some(x) => Some(&*x),
            None => None
        }
    }
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.description().fmt(f)
    }
}

impl ParseError {
    pub fn new(desc: String, cause: Option<parser::ParseError>) -> Self {
        ParseError {
            desc: desc,
            orig: cause
        }
    }

    pub fn from_peg_error(e: parser::ParseError) -> Self {
        ParseError {
            desc: format!("{}", e).to_owned(),
            orig: Some(e)
        }
    }

    pub fn into_string(self) -> String {
        self.desc
    }

    /// Access the underlying parser error.
    pub fn parser_error(&self) -> Option<&parser::ParseError> {
        self.orig.as_ref()
    }

    /// The line where the error occured.
    ///
    /// The value might be warped because content lines are unfolded before the parser keeps track
    /// of line numbers.
    pub fn line(&self) -> Option<&usize> {
        match self.parser_error() {
            Some(e) => Some(&e.line),
            None => None
        }
    }

    /// The column where the error occured.
    ///
    /// The value might be warped because content lines are unfolded before the parser keeps track
    /// of line numbers.
    pub fn column(&self) -> Option<&usize> {
        match self.parser_error() {
            Some(e) => Some(&e.column),
            None => None
        }
    }
}

peg! parser(r#"
use super::{Component,Property};
use std::collections::HashMap;

components -> Vec<Component>
    = cs:component ** eols __ { cs }

    #[pub]
    component -> Component
        = name:component_begin
          ps:props
          cs:components
          component_end {
            let mut rv = Component::new(name);
            rv.subcomponents = cs;

            for (k, v) in ps.into_iter() {
                rv.all_props_mut(k).push(v);
            };

            rv
        }

    component_begin -> &'input str
        = "BEGIN:" v:value __ { v }

    component_end -> &'input str
        = "END:" v:value __ { v }

props -> Vec<(&'input str, Property)>
    = ps:prop ++ eols __ { ps }

    prop -> (&'input str, Property)
        = !"BEGIN:" !"END:" g:group? k:name p:params ":" v:value {
            (k, Property { name: k.to_string(), params: p, raw_value: v.to_string(), prop_group: g })
        }

    group -> String
        = g:group_name "." { g.to_string() }

        group_name -> &'input str
            = group_char+ { match_str }

    name -> &'input str
        = iana_token+ { match_str }

    params -> HashMap<String, String>
        = ps:(";" p:param {p})* {
            let mut rv: HashMap<String, String> = HashMap::with_capacity(ps.len());
            rv.extend(ps.into_iter().map(|(k, v)| (k.to_string(), v.to_string())));
            rv
        }

        param -> (&'input str, &'input str)
            // FIXME: Doesn't handle comma-separated values
            = k:param_name v:("=" v:param_value { v })? {
                (k, match v {
                    Some(x) => x,
                    None => ""
                })
            }

        param_name -> &'input str
            = iana_token+ { match_str }

        param_value -> &'input str
            = x:(quoted_string / param_text) { x }

        param_text -> &'input str
            = safe_char* { match_str }

    value -> &'input str
        = value_char+ { match_str }

quoted_string -> &'input str
    = dquote x:quoted_content dquote { x }

quoted_content -> &'input str
    = qsafe_char* { match_str }

iana_token = ([a-zA-Z0-9] / "-")+
group_char = ([a-zA-Z0-9] / "-")
qsafe_char = !dquote !ctl value_char
safe_char = !";" !":" qsafe_char

value_char = !eol .

eol = "\r\n" / "\n" / "\r"
dquote = "\""
eols = eol+

// Taken from vCard. vCalendar's is a subset. Together with the definition of "qsafe_char" this
// might reject a bunch of valid iCalendars, but I can't imagine one.
ctl = [\u{00}-\u{1F}] / "\u{7F}"

whitespace = " " / "\t"
__ = (eol / whitespace)*

"#);
<|endoftext|>


<commit_before>use error::{SassError, ErrorKind, Result};
use sass::op::Op;
use sass::number_value::NumberValue;

use std::borrow::Cow;
use std::fmt;
use std::cmp;

#[derive(Debug, Clone, PartialEq)]
pub struct ColorValue<'a> {
    pub red: u8,
    pub green: u8,
    pub blue: u8,
    pub computed: bool,
    pub original: Cow<'a, str>,
}

impl<'a, 'b> ColorValue<'a> {
    pub fn from_hex(hex: Cow<'a, str>) -> Result<ColorValue<'a>> {
        if hex.len() == 4 {
            Ok(ColorValue {
                red:   u8::from_str_radix(&hex[1..2], 16).unwrap() * 17,
                green: u8::from_str_radix(&hex[2..3], 16).unwrap() * 17,
                blue:  u8::from_str_radix(&hex[3..4], 16).unwrap() * 17,
                computed: false,
                original: hex,
            })
        } else if hex.len() == 7 {
            Ok(ColorValue {
                red:   u8::from_str_radix(&hex[1..3], 16).unwrap(),
                green: u8::from_str_radix(&hex[3..5], 16).unwrap(),
                blue:  u8::from_str_radix(&hex[5..7], 16).unwrap(),
                computed: false,
                original: hex,
            })
        } else {
            Err(SassError {
                kind: ErrorKind::InvalidColor,
                message: format!("Invalid hex color: {}", hex),
            })
        }
    }

    pub fn from_computed(r: u8, g: u8, b: u8) -> ColorValue<'a> {
        ColorValue {
            red: r, green: g, blue: b,
            computed: true,
            original: hex_format(r, g, b).into(),
        }
    }

    pub fn into_owned(self) -> ColorValue<'b> {
        ColorValue {
            red: self.red, green: self.green, blue: self.blue,
            computed: false,
            original: self.original.into_owned().into(),
        }
    }

    pub fn apply_math(self, op: Op, nv: NumberValue<'a>) -> Result<ColorValue<'a>> {
        let num   = nv.scalar as u8;
        let red   = try!(saturating_math(op, self.red, num));
        let green = try!(saturating_math(op, self.green, num));
        let blue  = try!(saturating_math(op, self.blue, num));
        Ok(ColorValue::from_computed(red, green, blue))
    }

    pub fn combine_colors(self, op: Op, c: ColorValue<'a>) -> Result<ColorValue<'a>> {
        let red   = try!(saturating_math(op, self.red, c.red));
        let green = try!(saturating_math(op, self.green, c.green));
        let blue  = try!(saturating_math(op, self.blue, c.blue));
        Ok(ColorValue::from_computed(red, green, blue))
    }

    pub fn to_named_color(&self) -> String {
        // TODO once we have alpha channel: 'transparent', 0x00000000

        String::from(match (self.red, self.green, self.blue) {
            // standard colors
            (0, 255, 255)   => "cyan",    // Sass prefers cyan over aqua
            (0, 0, 0)       => "black",
            (0, 0, 255)     => "blue",
            (255, 0, 255)   => "magenta", // Sass prefers magenta over fuchsia
            (80, 80, 80)    => "gray",    // Sass prefers this spelling over grey
            (0, 80, 0)      => "green",
            (0, 255, 0)     => "lime",
            (80, 0, 0)      => "maroon",
            (0, 0, 80)      => "navy",
            (80, 80, 0)     => "olive",
            (80, 0, 80)     => "purple",
            (255, 0, 0)     => "red",
            (192, 192, 192) => "silver",
            (0, 80, 80)     => "teal",
            (255, 255, 255) => "white",
            (255, 255, 0)   => "yellow",
            // the rest of the named colors, converted as I get around to it
            (169, 169, 169) => "darkgrey",
            (47, 79, 79)    => "darkslategrey",
            (69, 69, 69)    => "dimgrey",
            (211, 211, 211) => "lightgrey",
            (77, 88, 99)    => "lightslategrey",
            (70, 80, 90)    => "slategrey",
            (240, 248, 255) => "aliceblue",
            (250, 235, 215) => "antiquewhite",
            (127, 255, 212) => "aquamarine",
            (240, 255, 255) => "azure",
            (245, 245, 220) => "beige",
            (255, 228, 196) => "bisque",
            (255, 235, 205) => "blanchedalmond",
            (138, 43, 226)  => "blueviolet",
            (165, 42, 42)   => "brown",
            (222, 184, 135) => "burlywood",
            (95, 158, 160)  => "cadetblue",

            (r, g, b)       => return hex_format(r, g, b),
        })
               // 'chartreuse'           => 7FFF00,
               // 'chocolate'            => D2691E,
               // 'coral'                => FF7F50,
               // 'cornflowerblue'       => 6495ED,
               // 'cornsilk'             => FFF8DC,
               // 'crimson'              => DC143C,
               // 'darkblue'             => 00008B,
               // 'darkcyan'             => 008B8B,
               // 'darkgoldenrod'        => B8860B,
               // 'darkgray'             => A9A9A9,
               // 'darkgreen'            => 006400,
               // 'darkkhaki'            => BDB76B,
               // 'darkmagenta'          => 8B008B,
               // 'darkolivegreen'       => 556B2F,
               // 'darkorange'           => FF8C00,
               // 'darkorchid'           => 9932CC,
               // 'darkred'              => 8B0000,
               // 'darksalmon'           => E9967A,
               // 'darkseagreen'         => 8FBC8F,
               // 'darkslateblue'        => 483D8B,
               // 'darkslategray'        => 2F4F4F,
               // 'darkturquoise'        => 00CED1,
               // 'darkviolet'           => 9400D3,
               // 'deeppink'             => FF1493,
               // 'deepskyblue'          => 00BFFF,
               // 'dimgray'              => 696969,
               // 'dodgerblue'           => 1E90FF,
               // 'firebrick'            => B22222,
               // 'floralwhite'          => FFFAF0,
               // 'forestgreen'          => 228B22,
               // 'gainsboro'            => DCDCDC,
               // 'ghostwhite'           => F8F8FF,
               // 'gold'                 => FFD700,
               // 'goldenrod'            => DAA520,
               // 'greenyellow'          => ADFF2F,
               // 'honeydew'             => F0FFF0,
               // 'hotpink'              => FF69B4,
               // 'indianred'            => CD5C5C,
               // 'indigo'               => 4B0082,
               // 'ivory'                => FFFFF0,
               // 'khaki'                => F0E68C,
               // 'lavender'             => E6E6FA,
               // 'lavenderblush'        => FFF0F5,
               // 'lawngreen'            => 7CFC00,
               // 'lemonchiffon'         => FFFACD,
               // 'lightblue'            => ADD8E6,
               // 'lightcoral'           => F08080,
               // 'lightcyan'            => E0FFFF,
               // 'lightgoldenrodyellow' => FAFAD2,
               // 'lightgreen'           => 90EE90,
               // 'lightgray'            => D3D3D3,
               // 'lightpink'            => FFB6C1,
               // 'lightsalmon'          => FFA07A,
               // 'lightseagreen'        => 20B2AA,
               // 'lightskyblue'         => 87CEFA,
               // 'lightslategray'       => 778899,
               // 'lightsteelblue'       => B0C4DE,
               // 'lightyellow'          => FFFFE0,
               // 'limegreen'            => 32CD32,
               // 'linen'                => FAF0E6,
               // 'mediumaquamarine'     => 66CDAA,
               // 'mediumblue'           => 0000CD,
               // 'mediumorchid'         => BA55D3,
               // 'mediumpurple'         => 9370DB,
               // 'mediumseagreen'       => 3CB371,
               // 'mediumslateblue'      => 7B68EE,
               // 'mediumspringgreen'    => 00FA9A,
               // 'mediumturquoise'      => 48D1CC,
               // 'mediumvioletred'      => C71585,
               // 'midnightblue'         => 191970,
               // 'mintcream'            => F5FFFA,
               // 'mistyrose'            => FFE4E1,
               // 'moccasin'             => FFE4B5,
               // 'navajowhite'          => FFDEAD,
               // 'oldlace'              => FDF5E6,
               // 'olivedrab'            => 6B8E23,
               // 'orange'               => FFA500,
               // 'orangered'            => FF4500,
               // 'orchid'               => DA70D6,
               // 'palegoldenrod'        => EEE8AA,
               // 'palegreen'            => 98FB98,
               // 'paleturquoise'        => AFEEEE,
               // 'palevioletred'        => DB7093,
               // 'papayawhip'           => FFEFD5,
               // 'peachpuff'            => FFDAB9,
               // 'peru'                 => CD853F,
               // 'pink'                 => FFC0CB,
               // 'plum'                 => DDA0DD,
               // 'powderblue'           => B0E0E6,
               // 'rebeccapurple'        => 663399,
               // 'rosybrown'            => BC8F8F,
               // 'royalblue'            => 4169E1,
               // 'saddlebrown'          => 8B4513,
               // 'salmon'               => FA8072,
               // 'sandybrown'           => F4A460,
               // 'seagreen'             => 2E8B57,
               // 'seashell'             => FFF5EE,
               // 'sienna'               => A0522D,
               // 'skyblue'              => 87CEEB,
               // 'slateblue'            => 6A5ACD,
               // 'slategray'            => 708090,
               // 'snow'                 => FFFAFA,
               // 'springgreen'          => 00FF7F,
               // 'steelblue'            => 4682B4,
               // 'tan'                  => D2B48C,
               // 'thistle'              => D8BFD8,
               // 'tomato'               => FF6347,
               // 'turquoise'            => 40E0D0,
               // 'violet'               => EE82EE,
               // 'wheat'                => F5DEB3,
               // 'whitesmoke'           => F5F5F5,
               // 'yellowgreen'          => 9ACD32,
    }
}

// Not the color kind of saturating.
fn saturating_math(op: Op, a: u8, b: u8) -> Result<u8> {
    Ok(match op {
        Op::Plus    => a.saturating_add(b),
        Op::Minus   => a.saturating_sub(b),
        Op::Star    => cmp::max(cmp::min(a as i32 * b as i32, 255), 0) as u8,
        Op::Slash   => cmp::max(cmp::min(a as i32 / b as i32, 255), 0) as u8,
        Op::Percent => cmp::max(cmp::min(a as i32 % b as i32, 255), 0) as u8,
        other => return Err(SassError {
            kind: ErrorKind::InvalidOperator,
            message: format!(
                "Cannot apply operator {:?} on color as math",
                other
            ),
        }),

    })
}

fn hex_format(red: u8, green: u8, blue: u8) -> String {
    format!("#{:02x}{:02x}{:02x}", red, green, blue)
}

impl<'a> fmt::Display for ColorValue<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let candidate = if self.computed {
            self.to_named_color()
        } else {
            hex_format(self.red, self.green, self.blue)
        };
        if candidate.len() < self.original.len() {
            write!(f, "{}", candidate)
        } else {
            write!(f, "{}", self.original)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use sass::number_value::NumberValue;
    use sass::op::Op;
    use std::borrow::Cow::Borrowed;

    #[test]
    fn it_ignores_overflow_when_not_a_named_color() {
        let c = ColorValue::from_hex(Borrowed("#ff0000")).unwrap();
        let res = c.apply_math(Op::Plus, NumberValue::from_scalar(1.0)).unwrap();
        assert_eq!("#ff0101", format!("{}", res));
    }
}
<commit_msg>f with computed<commit_after>use error::{SassError, ErrorKind, Result};
use sass::op::Op;
use sass::number_value::NumberValue;

use std::borrow::Cow;
use std::fmt;
use std::cmp;

#[derive(Debug, Clone, PartialEq)]
pub struct ColorValue<'a> {
    pub red: u8,
    pub green: u8,
    pub blue: u8,
    pub computed: bool,
    pub original: Cow<'a, str>,
}

impl<'a, 'b> ColorValue<'a> {
    pub fn from_hex(hex: Cow<'a, str>) -> Result<ColorValue<'a>> {
        if hex.len() == 4 {
            Ok(ColorValue {
                red:   u8::from_str_radix(&hex[1..2], 16).unwrap() * 17,
                green: u8::from_str_radix(&hex[2..3], 16).unwrap() * 17,
                blue:  u8::from_str_radix(&hex[3..4], 16).unwrap() * 17,
                computed: false,
                original: hex,
            })
        } else if hex.len() == 7 {
            Ok(ColorValue {
                red:   u8::from_str_radix(&hex[1..3], 16).unwrap(),
                green: u8::from_str_radix(&hex[3..5], 16).unwrap(),
                blue:  u8::from_str_radix(&hex[5..7], 16).unwrap(),
                computed: false,
                original: hex,
            })
        } else {
            Err(SassError {
                kind: ErrorKind::InvalidColor,
                message: format!("Invalid hex color: {}", hex),
            })
        }
    }

    pub fn from_computed(r: u8, g: u8, b: u8) -> ColorValue<'a> {
        ColorValue {
            red: r, green: g, blue: b,
            computed: true,
            original: hex_format(r, g, b).into(),
        }
    }

    pub fn into_owned(self) -> ColorValue<'b> {
        ColorValue {
            red: self.red, green: self.green, blue: self.blue,
            computed: self.computed,
            original: self.original.into_owned().into(),
        }
    }

    pub fn apply_math(self, op: Op, nv: NumberValue<'a>) -> Result<ColorValue<'a>> {
        let num   = nv.scalar as u8;
        let red   = try!(saturating_math(op, self.red, num));
        let green = try!(saturating_math(op, self.green, num));
        let blue  = try!(saturating_math(op, self.blue, num));
        Ok(ColorValue::from_computed(red, green, blue))
    }

    pub fn combine_colors(self, op: Op, c: ColorValue<'a>) -> Result<ColorValue<'a>> {
        let red   = try!(saturating_math(op, self.red, c.red));
        let green = try!(saturating_math(op, self.green, c.green));
        let blue  = try!(saturating_math(op, self.blue, c.blue));
        Ok(ColorValue::from_computed(red, green, blue))
    }

    pub fn to_named_color(&self) -> String {
        // TODO once we have alpha channel: 'transparent', 0x00000000

        String::from(match (self.red, self.green, self.blue) {
            // standard colors
            (0, 255, 255)   => "cyan",    // Sass prefers cyan over aqua
            (0, 0, 0)       => "black",
            (0, 0, 255)     => "blue",
            (255, 0, 255)   => "magenta", // Sass prefers magenta over fuchsia
            (80, 80, 80)    => "gray",    // Sass prefers this spelling over grey
            (0, 80, 0)      => "green",
            (0, 255, 0)     => "lime",
            (80, 0, 0)      => "maroon",
            (0, 0, 80)      => "navy",
            (80, 80, 0)     => "olive",
            (80, 0, 80)     => "purple",
            (255, 0, 0)     => "red",
            (192, 192, 192) => "silver",
            (0, 80, 80)     => "teal",
            (255, 255, 255) => "white",
            (255, 255, 0)   => "yellow",
            // the rest of the named colors, converted as I get around to it
            (169, 169, 169) => "darkgrey",
            (47, 79, 79)    => "darkslategrey",
            (69, 69, 69)    => "dimgrey",
            (211, 211, 211) => "lightgrey",
            (77, 88, 99)    => "lightslategrey",
            (70, 80, 90)    => "slategrey",
            (240, 248, 255) => "aliceblue",
            (250, 235, 215) => "antiquewhite",
            (127, 255, 212) => "aquamarine",
            (240, 255, 255) => "azure",
            (245, 245, 220) => "beige",
            (255, 228, 196) => "bisque",
            (255, 235, 205) => "blanchedalmond",
            (138, 43, 226)  => "blueviolet",
            (165, 42, 42)   => "brown",
            (222, 184, 135) => "burlywood",
            (95, 158, 160)  => "cadetblue",

            (r, g, b)       => return hex_format(r, g, b),
        })
               // 'chartreuse'           => 7FFF00,
               // 'chocolate'            => D2691E,
               // 'coral'                => FF7F50,
               // 'cornflowerblue'       => 6495ED,
               // 'cornsilk'             => FFF8DC,
               // 'crimson'              => DC143C,
               // 'darkblue'             => 00008B,
               // 'darkcyan'             => 008B8B,
               // 'darkgoldenrod'        => B8860B,
               // 'darkgray'             => A9A9A9,
               // 'darkgreen'            => 006400,
               // 'darkkhaki'            => BDB76B,
               // 'darkmagenta'          => 8B008B,
               // 'darkolivegreen'       => 556B2F,
               // 'darkorange'           => FF8C00,
               // 'darkorchid'           => 9932CC,
               // 'darkred'              => 8B0000,
               // 'darksalmon'           => E9967A,
               // 'darkseagreen'         => 8FBC8F,
               // 'darkslateblue'        => 483D8B,
               // 'darkslategray'        => 2F4F4F,
               // 'darkturquoise'        => 00CED1,
               // 'darkviolet'           => 9400D3,
               // 'deeppink'             => FF1493,
               // 'deepskyblue'          => 00BFFF,
               // 'dimgray'              => 696969,
               // 'dodgerblue'           => 1E90FF,
               // 'firebrick'            => B22222,
               // 'floralwhite'          => FFFAF0,
               // 'forestgreen'          => 228B22,
               // 'gainsboro'            => DCDCDC,
               // 'ghostwhite'           => F8F8FF,
               // 'gold'                 => FFD700,
               // 'goldenrod'            => DAA520,
               // 'greenyellow'          => ADFF2F,
               // 'honeydew'             => F0FFF0,
               // 'hotpink'              => FF69B4,
               // 'indianred'            => CD5C5C,
               // 'indigo'               => 4B0082,
               // 'ivory'                => FFFFF0,
               // 'khaki'                => F0E68C,
               // 'lavender'             => E6E6FA,
               // 'lavenderblush'        => FFF0F5,
               // 'lawngreen'            => 7CFC00,
               // 'lemonchiffon'         => FFFACD,
               // 'lightblue'            => ADD8E6,
               // 'lightcoral'           => F08080,
               // 'lightcyan'            => E0FFFF,
               // 'lightgoldenrodyellow' => FAFAD2,
               // 'lightgreen'           => 90EE90,
               // 'lightgray'            => D3D3D3,
               // 'lightpink'            => FFB6C1,
               // 'lightsalmon'          => FFA07A,
               // 'lightseagreen'        => 20B2AA,
               // 'lightskyblue'         => 87CEFA,
               // 'lightslategray'       => 778899,
               // 'lightsteelblue'       => B0C4DE,
               // 'lightyellow'          => FFFFE0,
               // 'limegreen'            => 32CD32,
               // 'linen'                => FAF0E6,
               // 'mediumaquamarine'     => 66CDAA,
               // 'mediumblue'           => 0000CD,
               // 'mediumorchid'         => BA55D3,
               // 'mediumpurple'         => 9370DB,
               // 'mediumseagreen'       => 3CB371,
               // 'mediumslateblue'      => 7B68EE,
               // 'mediumspringgreen'    => 00FA9A,
               // 'mediumturquoise'      => 48D1CC,
               // 'mediumvioletred'      => C71585,
               // 'midnightblue'         => 191970,
               // 'mintcream'            => F5FFFA,
               // 'mistyrose'            => FFE4E1,
               // 'moccasin'             => FFE4B5,
               // 'navajowhite'          => FFDEAD,
               // 'oldlace'              => FDF5E6,
               // 'olivedrab'            => 6B8E23,
               // 'orange'               => FFA500,
               // 'orangered'            => FF4500,
               // 'orchid'               => DA70D6,
               // 'palegoldenrod'        => EEE8AA,
               // 'palegreen'            => 98FB98,
               // 'paleturquoise'        => AFEEEE,
               // 'palevioletred'        => DB7093,
               // 'papayawhip'           => FFEFD5,
               // 'peachpuff'            => FFDAB9,
               // 'peru'                 => CD853F,
               // 'pink'                 => FFC0CB,
               // 'plum'                 => DDA0DD,
               // 'powderblue'           => B0E0E6,
               // 'rebeccapurple'        => 663399,
               // 'rosybrown'            => BC8F8F,
               // 'royalblue'            => 4169E1,
               // 'saddlebrown'          => 8B4513,
               // 'salmon'               => FA8072,
               // 'sandybrown'           => F4A460,
               // 'seagreen'             => 2E8B57,
               // 'seashell'             => FFF5EE,
               // 'sienna'               => A0522D,
               // 'skyblue'              => 87CEEB,
               // 'slateblue'            => 6A5ACD,
               // 'slategray'            => 708090,
               // 'snow'                 => FFFAFA,
               // 'springgreen'          => 00FF7F,
               // 'steelblue'            => 4682B4,
               // 'tan'                  => D2B48C,
               // 'thistle'              => D8BFD8,
               // 'tomato'               => FF6347,
               // 'turquoise'            => 40E0D0,
               // 'violet'               => EE82EE,
               // 'wheat'                => F5DEB3,
               // 'whitesmoke'           => F5F5F5,
               // 'yellowgreen'          => 9ACD32,
    }
}

// Not the color kind of saturating.
fn saturating_math(op: Op, a: u8, b: u8) -> Result<u8> {
    Ok(match op {
        Op::Plus    => a.saturating_add(b),
        Op::Minus   => a.saturating_sub(b),
        Op::Star    => cmp::max(cmp::min(a as i32 * b as i32, 255), 0) as u8,
        Op::Slash   => cmp::max(cmp::min(a as i32 / b as i32, 255), 0) as u8,
        Op::Percent => cmp::max(cmp::min(a as i32 % b as i32, 255), 0) as u8,
        other => return Err(SassError {
            kind: ErrorKind::InvalidOperator,
            message: format!(
                "Cannot apply operator {:?} on color as math",
                other
            ),
        }),

    })
}

fn hex_format(red: u8, green: u8, blue: u8) -> String {
    format!("#{:02x}{:02x}{:02x}", red, green, blue)
}

impl<'a> fmt::Display for ColorValue<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let candidate = if self.computed {
            self.to_named_color()
        } else {
            hex_format(self.red, self.green, self.blue)
        };
        if candidate.len() < self.original.len() {
            write!(f, "{}", candidate)
        } else {
            write!(f, "{}", self.original)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use sass::number_value::NumberValue;
    use sass::op::Op;
    use std::borrow::Cow::Borrowed;

    #[test]
    fn it_ignores_overflow_when_not_a_named_color() {
        let c = ColorValue::from_hex(Borrowed("#ff0000")).unwrap();
        let res = c.apply_math(Op::Plus, NumberValue::from_scalar(1.0)).unwrap();
        assert!(res.computed);
        assert_eq!("#ff0101", format!("{}", res));
    }

    #[test]
    fn it_prefers_named_colors_if_computed() {
        let c = ColorValue::from_computed(192, 192, 192);
        assert_eq!("silver", format!("{}", c));
    }

    #[test]
    fn combining_colors_results_in_computed() {
        let c = ColorValue::from_hex(Borrowed("#ff0000")).unwrap();
        let d = ColorValue::from_hex(Borrowed("#00ff00")).unwrap();
        let res = c.combine_colors(Op::Plus, d).unwrap();
        assert!(res.computed);
        assert_eq!("yellow", format!("{}", res));
    }
}
<|endoftext|>