<commit_before>/// Deserialization module.
///

pub use self::error::{Error, ParseError, Result};

use std::borrow::Cow;
use std::io;
use std::str;
use parse::Bytes;

use serde::de::{self, Deserializer as Deserializer_, DeserializeSeed, Visitor};

mod error;
#[cfg(test)]
mod tests;

/// The RON deserializer.
///
/// If you just want to simply deserialize a value,
/// you can use the `from_str` convenience function.
pub struct Deserializer<'de> {
    bytes: Bytes<'de>,
}

impl<'de> Deserializer<'de> {
    pub fn from_str(input: &'de str) -> Self {
        Deserializer {
            bytes: Bytes::new(input.as_bytes()),
        }
    }

    pub fn from_bytes(input: &'de [u8]) -> Self {
        Deserializer {
            bytes: Bytes::new(input),
        }
    }

    pub fn remainder(&self) -> Cow<str> {
        String::from_utf8_lossy(&self.bytes.bytes())
    }
}

/// A convenience function for reading data from a reader
/// and feeding into a deserializer
pub fn from_reader<R, T>(mut rdr: R) -> Result<T>
    where R: io::Read,
          T: de::DeserializeOwned
{
    let mut bytes = Vec::new();
    rdr.read_to_end(&mut bytes)?;
    let s = str::from_utf8(&bytes)?;
    from_str(s)
}

/// A convenience function for building a deserializer
/// and deserializing a value of type `T`.
pub fn from_str<'a, T>(s: &'a str) -> Result<T>
    where T: de::Deserialize<'a>
{
    let mut deserializer = Deserializer::from_str(s);
    let t = T::deserialize(&mut deserializer)?;

    deserializer.end()?;

    Ok(t)
}

impl<'de> Deserializer<'de> {
    /// Check if the remaining bytes are whitespace only,
    /// otherwise return an error.
    pub fn end(&mut self) -> Result<()> {
        self.bytes.skip_ws();

        if self.bytes.bytes().is_empty() {
            Ok(())
        } else {
            self.bytes.err(ParseError::TrailingCharacters)
        }
    }
}

impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
    type Error = Error;

    fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        panic!("Give me some!");
    }

    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_bool(self.bytes.bool()?)
    }

    fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_i8(self.bytes.signed_integer()?)
    }

    fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_i8(self.bytes.signed_integer()?)
    }

    fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_i32(self.bytes.signed_integer()?)
    }

    fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_i64(self.bytes.signed_integer()?)
    }

    fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_u8(self.bytes.unsigned_integer()?)
    }

    fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_u16(self.bytes.unsigned_integer()?)
    }

    fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_u32(self.bytes.unsigned_integer()?)
    }

    fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_u64(self.bytes.unsigned_integer()?)
    }

    fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_f32(self.bytes.float()?)
    }

    fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_f64(self.bytes.float()?)
    }

    fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_char(self.bytes.char()?)
    }

    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        use parse::ParsedStr;

        match self.bytes.string()? {
            ParsedStr::Allocated(s) => visitor.visit_string(s),
            ParsedStr::Slice(s) => visitor.visit_str(s),
        }
    }

    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        self.deserialize_str(visitor)
    }

    fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        self.deserialize_seq(visitor)
    }

    fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        self.deserialize_seq(visitor)
    }

    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        if self.bytes.consume("Some") && { self.bytes.skip_ws(); self.bytes.consume("(") } {
            let v = visitor.visit_some(&mut *self)?;

            self.bytes.skip_ws();

            if self.bytes.consume(")") {
                Ok(v)
            } else {
                self.bytes.err(ParseError::ExpectedOptionEnd)
            }

        } else if self.bytes.consume("None") {
            visitor.visit_none()
        } else {
            self.bytes.err(ParseError::ExpectedOption)
        }
    }

    // In Serde, unit means an anonymous value containing no data.
    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        if self.bytes.consume("()") {
            visitor.visit_unit()
        } else {
            self.bytes.err(ParseError::ExpectedUnit)
        }
    }

    fn deserialize_unit_struct<V>(
        self,
        name: &'static str,
        visitor: V
    ) -> Result<V::Value>
        where V: Visitor<'de>
    {
        if self.bytes.consume(name) {
            visitor.visit_unit()
        } else {
            self.deserialize_unit(visitor)
        }
    }

    fn deserialize_newtype_struct<V>(
        self,
        name: &'static str,
        visitor: V
    ) -> Result<V::Value>
        where V: Visitor<'de>
    {
        self.bytes.consume(name);

        self.bytes.skip_ws();

        if self.bytes.consume("(") {
            let value = visitor.visit_newtype_struct(&mut *self)?;
            self.bytes.comma();

            if self.bytes.consume(")") {
                Ok(value)
            } else {
                self.bytes.err(ParseError::ExpectedStructEnd)
            }
        } else {
            self.bytes.err(ParseError::ExpectedStruct)
        }
    }

    fn deserialize_seq<V>(mut self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        if self.bytes.consume("[") {
            let value = visitor.visit_seq(CommaSeparated::new(b']', &mut self))?;
            self.bytes.comma();

            if self.bytes.consume("]") {
                Ok(value)
            } else {
                self.bytes.err(ParseError::ExpectedArrayEnd)
            }
        } else {
            self.bytes.err(ParseError::ExpectedArray)
        }
    }

    // Tuples look just like sequences in JSON. Some formats may be able to
    // represent tuples more efficiently.
    //
    // As indicated by the length parameter, the `Deserialize` implementation
    // for a tuple in the Serde data model is required to know the length of the
    // tuple before even looking at the input data.
    fn deserialize_tuple<V>(
        mut self,
        _len: usize,
        visitor: V
    ) -> Result<V::Value>
        where V: Visitor<'de>
    {
        if self.bytes.consume("(") {
            let value = visitor.visit_seq(CommaSeparated::new(b')', &mut self))?;
            self.bytes.comma();

            if self.bytes.consume(")") {
                Ok(value)
            } else {
                self.bytes.err(ParseError::ExpectedArrayEnd)
            }
        } else {
            self.bytes.err(ParseError::ExpectedArray)
        }
    }

    fn deserialize_tuple_struct<V>(
        self,
        name: &'static str,
        len: usize,
        visitor: V
    ) -> Result<V::Value>
        where V: Visitor<'de>
    {
        self.bytes.consume(name);
        self.deserialize_tuple(len, visitor)
    }

    fn deserialize_map<V>(mut self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        if self.bytes.consume("{") {
            let value = visitor.visit_map(CommaSeparated::new(b'}', &mut self))?;
            self.bytes.comma();

            if self.bytes.consume("}") {
                Ok(value)
            } else {
                self.bytes.err(ParseError::ExpectedMapEnd)
            }
        } else {
            self.bytes.err(ParseError::ExpectedMap)
        }
    }

    fn deserialize_struct<V>(
        mut self,
        name: &'static str,
        _fields: &'static [&'static str],
        visitor: V
    ) -> Result<V::Value>
        where V: Visitor<'de>
    {
        self.bytes.consume(name);

        self.bytes.skip_ws();

        if self.bytes.consume("(") {
            let value = visitor.visit_map(CommaSeparated::new(b')', &mut self))?;
            self.bytes.comma();

            if self.bytes.consume(")") {
                Ok(value)
            } else {
                self.bytes.err(ParseError::ExpectedStructEnd)
            }
        } else {
            self.bytes.err(ParseError::ExpectedStruct)
        }
    }

    fn deserialize_enum<V>(
        self,
        _name: &'static str,
        _variants: &'static [&'static str],
        visitor: V
    ) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_enum(Enum::new(self))
    }

    fn deserialize_identifier<V>(
        self,
        visitor: V
    ) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_bytes(self.bytes.identifier()?)
    }

    fn deserialize_ignored_any<V>(
        self,
        visitor: V
    ) -> Result<V::Value>
        where V: Visitor<'de>
    {
        self.deserialize_any(visitor)
    }
}

struct CommaSeparated<'a, 'de: 'a> {
    de: &'a mut Deserializer<'de>,
    terminator: u8,
    had_comma: bool,
}

impl<'a, 'de> CommaSeparated<'a, 'de> {
    fn new(terminator: u8, de: &'a mut Deserializer<'de>) -> Self {
        CommaSeparated { de, terminator, had_comma: true }
    }

    fn err<T>(&self, kind: ParseError) -> Result<T> {
        self.de.bytes.err(kind)
    }

    fn error(&self, kind: ParseError) -> Error {
        self.de.bytes.error(kind)
    }

    fn has_element(&mut self) -> Result<bool> {
        self.de.bytes.skip_ws();

        Ok(self.had_comma &&
            self.de.bytes.peek().ok_or(self.error(ParseError::Eof))? != self.terminator)
    }
}

impl<'de, 'a> de::SeqAccess<'de> for CommaSeparated<'a, 'de> {
    type Error = Error;

    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
        where T: DeserializeSeed<'de>
    {
        if self.has_element()? {
            let res = seed.deserialize(&mut *self.de)?;

            self.had_comma = self.de.bytes.comma();

            Ok(Some(res))
        } else {
            Ok(None)
        }
    }
}

impl<'de, 'a> de::MapAccess<'de> for CommaSeparated<'a, 'de> {
    type Error = Error;

    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
        where K: DeserializeSeed<'de>
    {
        if self.has_element()? {
            seed.deserialize(&mut *self.de).map(Some)
        } else {
            Ok(None)
        }
    }

    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
        where V: DeserializeSeed<'de>
    {
        self.de.bytes.skip_ws();

        if self.de.bytes.consume(":") {
            self.de.bytes.skip_ws();

            let res = seed.deserialize(&mut *self.de)?;

            self.had_comma = self.de.bytes.comma();

            Ok(res)
        } else {
            self.err(ParseError::ExpectedMapColon)
        }
    }
}

struct Enum<'a, 'de: 'a> {
    de: &'a mut Deserializer<'de>,
}

impl<'a, 'de> Enum<'a, 'de> {
    fn new(de: &'a mut Deserializer<'de>) -> Self {
        Enum { de }
    }
}

impl<'de, 'a> de::EnumAccess<'de> for Enum<'a, 'de> {
    type Error = Error;
    type Variant = Self;

    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
        where V: DeserializeSeed<'de>
    {
        let value = seed.deserialize(&mut *self.de)?;

        Ok((value, self))
    }
}

impl<'de, 'a> de::VariantAccess<'de> for Enum<'a, 'de> {
    type Error = Error;

    fn unit_variant(self) -> Result<()> {
        Ok(())
    }

    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
        where T: DeserializeSeed<'de>
    {
        self.de.bytes.skip_ws();

        if self.de.bytes.consume("(") {
            let val = seed.deserialize(&mut *self.de)?;

            self.de.bytes.comma();

            if self.de.bytes.consume(")") {
                Ok(val)
            } else {
                self.de.bytes.err(ParseError::ExpectedStructEnd)
            }
        } else {
            self.de.bytes.err(ParseError::ExpectedStruct)
        }
    }

    fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        self.de.bytes.skip_ws();

        self.de.deserialize_tuple(len, visitor)
    }

    fn struct_variant<V>(
        self,
        fields: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value>
        where V: Visitor<'de>
    {
        self.de.bytes.skip_ws();

        self.de.deserialize_struct("", fields, visitor)
    }
}
<commit_msg>Replace panic in deserialize_any with error message<commit_after>/// Deserialization module.
///

pub use self::error::{Error, ParseError, Result};

use std::borrow::Cow;
use std::io;
use std::str;
use parse::Bytes;

use serde::de::{self, Deserializer as Deserializer_, DeserializeSeed, Visitor};

mod error;
#[cfg(test)]
mod tests;

/// The RON deserializer.
///
/// If you just want to simply deserialize a value,
/// you can use the `from_str` convenience function.
pub struct Deserializer<'de> {
    bytes: Bytes<'de>,
}

impl<'de> Deserializer<'de> {
    pub fn from_str(input: &'de str) -> Self {
        Deserializer {
            bytes: Bytes::new(input.as_bytes()),
        }
    }

    pub fn from_bytes(input: &'de [u8]) -> Self {
        Deserializer {
            bytes: Bytes::new(input),
        }
    }

    pub fn remainder(&self) -> Cow<str> {
        String::from_utf8_lossy(&self.bytes.bytes())
    }
}

/// A convenience function for reading data from a reader
/// and feeding into a deserializer
pub fn from_reader<R, T>(mut rdr: R) -> Result<T>
    where R: io::Read,
          T: de::DeserializeOwned
{
    let mut bytes = Vec::new();
    rdr.read_to_end(&mut bytes)?;
    let s = str::from_utf8(&bytes)?;
    from_str(s)
}

/// A convenience function for building a deserializer
/// and deserializing a value of type `T`.
pub fn from_str<'a, T>(s: &'a str) -> Result<T>
    where T: de::Deserialize<'a>
{
    let mut deserializer = Deserializer::from_str(s);
    let t = T::deserialize(&mut deserializer)?;

    deserializer.end()?;

    Ok(t)
}

impl<'de> Deserializer<'de> {
    /// Check if the remaining bytes are whitespace only,
    /// otherwise return an error.
    pub fn end(&mut self) -> Result<()> {
        self.bytes.skip_ws();

        if self.bytes.bytes().is_empty() {
            Ok(())
        } else {
            self.bytes.err(ParseError::TrailingCharacters)
        }
    }
}

impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
    type Error = Error;

    fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        Err(Error::custom("RON does not support Deserializer::deserialize_any"))
    }

    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_bool(self.bytes.bool()?)
    }

    fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_i8(self.bytes.signed_integer()?)
    }

    fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_i8(self.bytes.signed_integer()?)
    }

    fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_i32(self.bytes.signed_integer()?)
    }

    fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_i64(self.bytes.signed_integer()?)
    }

    fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_u8(self.bytes.unsigned_integer()?)
    }

    fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_u16(self.bytes.unsigned_integer()?)
    }

    fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_u32(self.bytes.unsigned_integer()?)
    }

    fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_u64(self.bytes.unsigned_integer()?)
    }

    fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_f32(self.bytes.float()?)
    }

    fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_f64(self.bytes.float()?)
    }

    fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_char(self.bytes.char()?)
    }

    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        use parse::ParsedStr;

        match self.bytes.string()? {
            ParsedStr::Allocated(s) => visitor.visit_string(s),
            ParsedStr::Slice(s) => visitor.visit_str(s),
        }
    }

    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        self.deserialize_str(visitor)
    }

    fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        self.deserialize_seq(visitor)
    }

    fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        self.deserialize_seq(visitor)
    }

    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        if self.bytes.consume("Some") && { self.bytes.skip_ws(); self.bytes.consume("(") } {
            let v = visitor.visit_some(&mut *self)?;

            self.bytes.skip_ws();

            if self.bytes.consume(")") {
                Ok(v)
            } else {
                self.bytes.err(ParseError::ExpectedOptionEnd)
            }

        } else if self.bytes.consume("None") {
            visitor.visit_none()
        } else {
            self.bytes.err(ParseError::ExpectedOption)
        }
    }

    // In Serde, unit means an anonymous value containing no data.
    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        if self.bytes.consume("()") {
            visitor.visit_unit()
        } else {
            self.bytes.err(ParseError::ExpectedUnit)
        }
    }

    fn deserialize_unit_struct<V>(
        self,
        name: &'static str,
        visitor: V
    ) -> Result<V::Value>
        where V: Visitor<'de>
    {
        if self.bytes.consume(name) {
            visitor.visit_unit()
        } else {
            self.deserialize_unit(visitor)
        }
    }

    fn deserialize_newtype_struct<V>(
        self,
        name: &'static str,
        visitor: V
    ) -> Result<V::Value>
        where V: Visitor<'de>
    {
        self.bytes.consume(name);

        self.bytes.skip_ws();

        if self.bytes.consume("(") {
            let value = visitor.visit_newtype_struct(&mut *self)?;
            self.bytes.comma();

            if self.bytes.consume(")") {
                Ok(value)
            } else {
                self.bytes.err(ParseError::ExpectedStructEnd)
            }
        } else {
            self.bytes.err(ParseError::ExpectedStruct)
        }
    }

    fn deserialize_seq<V>(mut self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        if self.bytes.consume("[") {
            let value = visitor.visit_seq(CommaSeparated::new(b']', &mut self))?;
            self.bytes.comma();

            if self.bytes.consume("]") {
                Ok(value)
            } else {
                self.bytes.err(ParseError::ExpectedArrayEnd)
            }
        } else {
            self.bytes.err(ParseError::ExpectedArray)
        }
    }

    // Tuples look just like sequences in JSON. Some formats may be able to
    // represent tuples more efficiently.
    //
    // As indicated by the length parameter, the `Deserialize` implementation
    // for a tuple in the Serde data model is required to know the length of the
    // tuple before even looking at the input data.
    fn deserialize_tuple<V>(
        mut self,
        _len: usize,
        visitor: V
    ) -> Result<V::Value>
        where V: Visitor<'de>
    {
        if self.bytes.consume("(") {
            let value = visitor.visit_seq(CommaSeparated::new(b')', &mut self))?;
            self.bytes.comma();

            if self.bytes.consume(")") {
                Ok(value)
            } else {
                self.bytes.err(ParseError::ExpectedArrayEnd)
            }
        } else {
            self.bytes.err(ParseError::ExpectedArray)
        }
    }

    fn deserialize_tuple_struct<V>(
        self,
        name: &'static str,
        len: usize,
        visitor: V
    ) -> Result<V::Value>
        where V: Visitor<'de>
    {
        self.bytes.consume(name);
        self.deserialize_tuple(len, visitor)
    }

    fn deserialize_map<V>(mut self, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        if self.bytes.consume("{") {
            let value = visitor.visit_map(CommaSeparated::new(b'}', &mut self))?;
            self.bytes.comma();

            if self.bytes.consume("}") {
                Ok(value)
            } else {
                self.bytes.err(ParseError::ExpectedMapEnd)
            }
        } else {
            self.bytes.err(ParseError::ExpectedMap)
        }
    }

    fn deserialize_struct<V>(
        mut self,
        name: &'static str,
        _fields: &'static [&'static str],
        visitor: V
    ) -> Result<V::Value>
        where V: Visitor<'de>
    {
        self.bytes.consume(name);

        self.bytes.skip_ws();

        if self.bytes.consume("(") {
            let value = visitor.visit_map(CommaSeparated::new(b')', &mut self))?;
            self.bytes.comma();

            if self.bytes.consume(")") {
                Ok(value)
            } else {
                self.bytes.err(ParseError::ExpectedStructEnd)
            }
        } else {
            self.bytes.err(ParseError::ExpectedStruct)
        }
    }

    fn deserialize_enum<V>(
        self,
        _name: &'static str,
        _variants: &'static [&'static str],
        visitor: V
    ) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_enum(Enum::new(self))
    }

    fn deserialize_identifier<V>(
        self,
        visitor: V
    ) -> Result<V::Value>
        where V: Visitor<'de>
    {
        visitor.visit_bytes(self.bytes.identifier()?)
    }

    fn deserialize_ignored_any<V>(
        self,
        visitor: V
    ) -> Result<V::Value>
        where V: Visitor<'de>
    {
        self.deserialize_any(visitor)
    }
}

struct CommaSeparated<'a, 'de: 'a> {
    de: &'a mut Deserializer<'de>,
    terminator: u8,
    had_comma: bool,
}

impl<'a, 'de> CommaSeparated<'a, 'de> {
    fn new(terminator: u8, de: &'a mut Deserializer<'de>) -> Self {
        CommaSeparated { de, terminator, had_comma: true }
    }

    fn err<T>(&self, kind: ParseError) -> Result<T> {
        self.de.bytes.err(kind)
    }

    fn error(&self, kind: ParseError) -> Error {
        self.de.bytes.error(kind)
    }

    fn has_element(&mut self) -> Result<bool> {
        self.de.bytes.skip_ws();

        Ok(self.had_comma &&
            self.de.bytes.peek().ok_or(self.error(ParseError::Eof))? != self.terminator)
    }
}

impl<'de, 'a> de::SeqAccess<'de> for CommaSeparated<'a, 'de> {
    type Error = Error;

    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
        where T: DeserializeSeed<'de>
    {
        if self.has_element()? {
            let res = seed.deserialize(&mut *self.de)?;

            self.had_comma = self.de.bytes.comma();

            Ok(Some(res))
        } else {
            Ok(None)
        }
    }
}

impl<'de, 'a> de::MapAccess<'de> for CommaSeparated<'a, 'de> {
    type Error = Error;

    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
        where K: DeserializeSeed<'de>
    {
        if self.has_element()? {
            seed.deserialize(&mut *self.de).map(Some)
        } else {
            Ok(None)
        }
    }

    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
        where V: DeserializeSeed<'de>
    {
        self.de.bytes.skip_ws();

        if self.de.bytes.consume(":") {
            self.de.bytes.skip_ws();

            let res = seed.deserialize(&mut *self.de)?;

            self.had_comma = self.de.bytes.comma();

            Ok(res)
        } else {
            self.err(ParseError::ExpectedMapColon)
        }
    }
}

struct Enum<'a, 'de: 'a> {
    de: &'a mut Deserializer<'de>,
}

impl<'a, 'de> Enum<'a, 'de> {
    fn new(de: &'a mut Deserializer<'de>) -> Self {
        Enum { de }
    }
}

impl<'de, 'a> de::EnumAccess<'de> for Enum<'a, 'de> {
    type Error = Error;
    type Variant = Self;

    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
        where V: DeserializeSeed<'de>
    {
        let value = seed.deserialize(&mut *self.de)?;

        Ok((value, self))
    }
}

impl<'de, 'a> de::VariantAccess<'de> for Enum<'a, 'de> {
    type Error = Error;

    fn unit_variant(self) -> Result<()> {
        Ok(())
    }

    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
        where T: DeserializeSeed<'de>
    {
        self.de.bytes.skip_ws();

        if self.de.bytes.consume("(") {
            let val = seed.deserialize(&mut *self.de)?;

            self.de.bytes.comma();

            if self.de.bytes.consume(")") {
                Ok(val)
            } else {
                self.de.bytes.err(ParseError::ExpectedStructEnd)
            }
        } else {
            self.de.bytes.err(ParseError::ExpectedStruct)
        }
    }

    fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value>
        where V: Visitor<'de>
    {
        self.de.bytes.skip_ws();

        self.de.deserialize_tuple(len, visitor)
    }

    fn struct_variant<V>(
        self,
        fields: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value>
        where V: Visitor<'de>
    {
        self.de.bytes.skip_ws();

        self.de.deserialize_struct("", fields, visitor)
    }
}
<|endoftext|>


<commit_before>use alto::{self, SourceTrait};
use std::fs::File;
use std::path::Path;
use std::sync::mpsc::{Receiver, SyncSender, sync_channel};
use std::thread::spawn;
use vorbis::Decoder;

/// The device is responsible of managing synchronization and audio playback by providing a playback
/// cursor to a closure used as demo.
///
/// You shouldn’t have more than one Device per program.
pub struct Device {
  /// Playback length.
  len: f32,
  /// Sender used to send requests to audio thread.
  req_sx: SyncSender<Request>,
  /// Receiver used to receive responses from the audio thread.
  resp_rx: Receiver<Response>
}

enum Request {
  Toggle,
  PlaybackLength,
  PlaybackCursor,
  SetCursor(f32)
}

enum Response {
  PlaybackLength(f32),
  PlaybackCursor(f32)
}

impl Device {
  pub fn new<P>(track_path: P) -> Self where P: AsRef<Path> {
    info!("loading soundtrack {:?}", track_path.as_ref());

    // FIXME: stream the file instead?
    // load PCM data from the file
    let vorbis_decoder = Decoder::new(File::open(track_path).unwrap()).unwrap();
    let mut pcm_buffer = Vec::new();

    for packet in vorbis_decoder.into_packets().map(Result::unwrap) {
      pcm_buffer.extend(packet.data);
    }

    // create a channel to send requests to / retrieve them from the audio thread
    let (req_sx, req_rx) = sync_channel(0);
    // create a channel to receive responses / to send responses from the audio thread
    let (mut resp_sx, resp_rx) = sync_channel(0);

    info!("starting audio thread");

    let _ = spawn(move || {
      deb!("initializing OpenAL");

      let alto = alto::Alto::load_default().unwrap();
      let al_device = alto.open(None).unwrap();
      let al_ctx = al_device.new_context(None).unwrap();

      // create the required objects to play the soundtrack
      let mut al_buffer = al_ctx.new_buffer().unwrap();
      let mut al_source = al_ctx.new_streaming_source().unwrap();

      // compute the length of soundtrack
      let l = (al_buffer.size().unwrap() * 8 / (al_buffer.channels().unwrap() * al_buffer.bits().unwrap())) as f32 / al_buffer.frequency().unwrap() as f32;

      // fill the OpenAL buffers with the PCM data
      let _ = al_buffer.set_data::<alto::Stereo<_>, _>(&pcm_buffer[..], 44100);
      let _ = al_source.queue_buffer(al_buffer);

      loop {
        match req_rx.recv() {
          Ok(req) => dispatch_request(&mut al_source, l, req, &mut resp_sx),
          Err(_) => break
        }
      }

      info!("leaving the audio thread");
    });

    // get the length
    let _ = req_sx.send(Request::PlaybackLength);

    let len = match resp_rx.recv() {
      Ok(Response::PlaybackLength(len)) => len,
      _ => unimplemented!()
    };

    Device {
      len: len,
      req_sx: req_sx,
      resp_rx: resp_rx
    }
  }

  pub fn toggle(&self) {
    let _ = self.req_sx.send(Request::Toggle);
  }

  pub fn playback_len(&self) -> f32 {
    self.len
  }

  pub fn playback_cursor(&self) -> f32 {
    let _ = self.req_sx.send(Request::PlaybackCursor);

    match self.resp_rx.recv() {
      Ok(Response::PlaybackCursor(c)) => c,
      _ => unimplemented!()
    }
  }

  pub fn set_playback_cursor(&self, t: f32) {
    let _ = self.req_sx.send(Request::SetCursor(t));
  }
}

fn dispatch_request(source: &mut alto::StreamingSource, len: f32, req: Request, resp_sx: &mut SyncSender<Response>) {
  match req {
    Request::Toggle => {
      toggle_source(source);
    },

    Request::PlaybackLength => {
      let _ = resp_sx.send(Response::PlaybackLength(len));
    },

    Request::PlaybackCursor => {
      let _ = resp_sx.send(Response::PlaybackCursor(playback_cursor_source(source, len)));
    },

    Request::SetCursor(t) => {
      set_playback_cursor_source(source, t, len);
    }
  }
}

fn toggle_source(source: &mut alto::StreamingSource) {
  if source.state().unwrap() == alto::SourceState::Playing {
    // pause the OpenAL source
    let _ = source.pause();
  } else {
    // unpause the OpenAL source
    let _ = source.play();
  }
}

fn playback_cursor_source(source: &mut alto::StreamingSource, len: f32) -> f32 {
  let cursor = source.sec_offset().unwrap();

  // loop the device if we hit the end of the demo
  if cursor > len {
    let _ = source.rewind();
    0.
  } else {
    cursor
  }
}

pub fn set_playback_cursor_source(source: &mut alto::StreamingSource, t: f32, len: f32) {
  assert!(t >= 0. && t <= 1.);
  let _ = source.set_sec_offset(t * len);
}
<commit_msg>Moved the set_data before we compute the length.<commit_after>use alto::{self, SourceTrait};
use std::fs::File;
use std::path::Path;
use std::sync::mpsc::{Receiver, SyncSender, sync_channel};
use std::thread::spawn;
use vorbis::Decoder;

/// The device is responsible of managing synchronization and audio playback by providing a playback
/// cursor to a closure used as demo.
///
/// You shouldn’t have more than one Device per program.
pub struct Device {
  /// Playback length.
  len: f32,
  /// Sender used to send requests to audio thread.
  req_sx: SyncSender<Request>,
  /// Receiver used to receive responses from the audio thread.
  resp_rx: Receiver<Response>
}

enum Request {
  Toggle,
  PlaybackLength,
  PlaybackCursor,
  SetCursor(f32)
}

enum Response {
  PlaybackLength(f32),
  PlaybackCursor(f32)
}

impl Device {
  pub fn new<P>(track_path: P) -> Self where P: AsRef<Path> {
    info!("loading soundtrack {:?}", track_path.as_ref());

    // FIXME: stream the file instead?
    // load PCM data from the file
    let vorbis_decoder = Decoder::new(File::open(track_path).unwrap()).unwrap();
    let mut pcm_buffer = Vec::new();

    for packet in vorbis_decoder.into_packets().map(Result::unwrap) {
      pcm_buffer.extend(packet.data);
    }

    // create a channel to send requests to / retrieve them from the audio thread
    let (req_sx, req_rx) = sync_channel(0);
    // create a channel to receive responses / to send responses from the audio thread
    let (mut resp_sx, resp_rx) = sync_channel(0);

    info!("starting audio thread");

    let _ = spawn(move || {
      deb!("initializing OpenAL");

      let alto = alto::Alto::load_default().unwrap();
      let al_device = alto.open(None).unwrap();
      let al_ctx = al_device.new_context(None).unwrap();

      // create the required objects to play the soundtrack
      let mut al_buffer = al_ctx.new_buffer().unwrap();
      let mut al_source = al_ctx.new_streaming_source().unwrap();

      // fill the OpenAL buffers with the PCM data
      let _ = al_buffer.set_data::<alto::Stereo<_>, _>(&pcm_buffer[..], 44100);

      // compute the length of soundtrack
      let l = (al_buffer.size().unwrap() * 8 / (al_buffer.channels().unwrap() * al_buffer.bits().unwrap())) as f32 / al_buffer.frequency().unwrap() as f32;

      let _ = al_source.queue_buffer(al_buffer);

      loop {
        match req_rx.recv() {
          Ok(req) => dispatch_request(&mut al_source, l, req, &mut resp_sx),
          Err(_) => break
        }
      }

      info!("leaving the audio thread");
    });

    // get the length
    let _ = req_sx.send(Request::PlaybackLength);

    let len = match resp_rx.recv() {
      Ok(Response::PlaybackLength(len)) => len,
      _ => unimplemented!()
    };

    Device {
      len: len,
      req_sx: req_sx,
      resp_rx: resp_rx
    }
  }

  pub fn toggle(&self) {
    let _ = self.req_sx.send(Request::Toggle);
  }

  pub fn playback_len(&self) -> f32 {
    self.len
  }

  pub fn playback_cursor(&self) -> f32 {
    let _ = self.req_sx.send(Request::PlaybackCursor);

    match self.resp_rx.recv() {
      Ok(Response::PlaybackCursor(c)) => c,
      _ => unimplemented!()
    }
  }

  pub fn set_playback_cursor(&self, t: f32) {
    let _ = self.req_sx.send(Request::SetCursor(t));
  }
}

fn dispatch_request(source: &mut alto::StreamingSource, len: f32, req: Request, resp_sx: &mut SyncSender<Response>) {
  match req {
    Request::Toggle => {
      toggle_source(source);
    },

    Request::PlaybackLength => {
      let _ = resp_sx.send(Response::PlaybackLength(len));
    },

    Request::PlaybackCursor => {
      let _ = resp_sx.send(Response::PlaybackCursor(playback_cursor_source(source, len)));
    },

    Request::SetCursor(t) => {
      set_playback_cursor_source(source, t, len);
    }
  }
}

fn toggle_source(source: &mut alto::StreamingSource) {
  if source.state().unwrap() == alto::SourceState::Playing {
    // pause the OpenAL source
    let _ = source.pause();
  } else {
    // unpause the OpenAL source
    let _ = source.play();
  }
}

fn playback_cursor_source(source: &mut alto::StreamingSource, len: f32) -> f32 {
  let cursor = source.sec_offset().unwrap();

  // loop the device if we hit the end of the demo
  if cursor > len {
    let _ = source.rewind();
    0.
  } else {
    cursor
  }
}

pub fn set_playback_cursor_source(source: &mut alto::StreamingSource, t: f32, len: f32) {
  assert!(t >= 0. && t <= 1.);
  let _ = source.set_sec_offset(t * len);
}
<|endoftext|>


<commit_before>pub enum Command {
    Output,
    Input,
    Increment,
    Decrement,
    RightShift,
    LeftShift
}
<commit_msg>Add derive(Debug) to Command struct<commit_after>#[derive(Debug)]
pub enum Command {
    Output,
    Input,
    Increment,
    Decrement,
    RightShift,
    LeftShift
}
<|endoftext|>


<commit_before>extern crate chrono;

use chrono::prelude::*;
use regex::{Regex, Captures};

#[derive(Debug)]
pub enum Command {
    BadCommand,
    OneTimeEvent(OneTimeEventImpl),
    RepetitiveEvent(RepetitiveEventImpl),
}

#[derive(Debug)]
pub struct OneTimeEventImpl{
    pub event_time : DateTime<Utc>,
    pub event_text : String,
}

#[derive(Debug)]
pub struct RepetitiveEventImpl{
    pub event_start_time : DateTime<Utc>,
    pub event_wait_time : chrono::Duration,
    pub event_text : String,
}

const MOMENT_DAY_REGEX: &str =
    r"(?:(?P<m_day>[\d]+))?(?:-(?P<m_month>[\d]+))?(?:-(?P<m_year>[\d]+))?";

const MOMENT_TIME_REGEX: &str =
    r"(?P<m_hour>[\d]+)(?:[.|:](?P<m_minute>[\d]+))?";

const DURATION_REGEX: &str =
    r"(:?(?P<d_day>[\d]*)[D|d|Д|д])?(:?(?P<d_hour>[\d]*)[H|h|Ч|ч])?(:?(?P<d_minute>[\d]*)[M|m|М|м])?(:?(?P<d_second>[\d]*)[S|s|С|с])?";

pub fn parse_command(command_line : String, user_timezone: i32) -> Command {
    let command_line = String::from(command_line.trim());
    let mut result;
    result = try_parse_for(&command_line);
    if result.is_some() {
        return result.unwrap();
    }

    result = try_parse_at(&command_line, user_timezone);
    if result.is_some() {
        return result.unwrap();
    }

    result = try_parse_rep(&command_line, user_timezone);
    if result.is_some() {
        return result.unwrap();
    }

    warn!("parse_command: line {} doesn't match any regex", command_line);
    Command::BadCommand
}

fn try_parse_at(command_line : &String, user_timezone: i32) -> Option<Command>{
    let reg = String::from(r"^") + MOMENT_DAY_REGEX + r"\s*(at|At|в|В)\s*" + MOMENT_TIME_REGEX + r" (?P<main_text>.*)";
    let time_format = Regex::new(&reg[..]).unwrap();

    let date_captures = time_format.captures(command_line);

    if date_captures.is_none() {
        return None;
    }
    let date_captures = date_captures.unwrap();
    let text = date_captures.name("main_text").unwrap().as_str();

    if let Some(t) = get_datetime_from_capture(&date_captures, user_timezone){
        return Some(Command::OneTimeEvent
                (OneTimeEventImpl
                    { event_text : String::from(text)
                    , event_time : t}
                ));
    }
    None
}

fn try_parse_for(command_line : &String) -> Option<Command>{
    let reg = String::from("^") + DURATION_REGEX + r"(?P<divider> )(?P<main_text>.*)";
    let reg = Regex::new(&reg[..]).unwrap();

    let capture = reg.captures(command_line);
    if capture.is_none(){
        return None;
    }
    let capture = capture.unwrap();

    let text = capture.name("main_text").unwrap().as_str();
    let dt = get_duration_from_capture(&capture);
    if dt.is_none() {
        return None;
    }

    Some(Command::OneTimeEvent(OneTimeEventImpl
            { event_text : String::from(text)
            , event_time : Utc::now() + dt.unwrap() }
        ))
}

fn try_parse_rep(command_line: &String, user_timezone: i32) -> Option<Command> {
    let reg = String::from("^") + r"rep\s*" + MOMENT_DAY_REGEX
                                + r"\s+"    + MOMENT_TIME_REGEX
                                + r"\s+"    + DURATION_REGEX
                                + r"(?P<divider> )(?P<main_text>.*)";
    let reg = Regex::new(&reg[..]).unwrap();

    let capture = reg.captures(command_line);
    if capture.is_none(){
        return None;
    }
    let capture = capture.unwrap();

    let text = capture.name("main_text").unwrap().as_str();
    let time = get_datetime_from_capture(&capture, user_timezone);
    let dt = get_duration_from_capture(&capture);
    if time.is_none() || dt.is_none() {
        return None;
    }

    Some(Command::RepetitiveEvent(RepetitiveEventImpl
        {
            event_start_time : time.unwrap(),
            event_wait_time : dt.unwrap(),
            event_text : String::from(text),
        }
    ))
}

fn get_duration_from_capture(cap: &Captures) -> Option<chrono::Duration>{
    let day:    i64 = cap.name("d_day").map_or    (0, |c| c.as_str().parse().unwrap() );
    let hour:   i64 = cap.name("d_hour").map_or   (0, |c| c.as_str().parse().unwrap() );
    let minute: i64 = cap.name("d_minute").map_or (0, |c| c.as_str().parse().unwrap() );
    let second: i64 = cap.name("d_second").map_or (0, |c| c.as_str().parse().unwrap() );

    if day == 0 && hour == 0 && minute == 0 && second == 0 {
        return None;
    }

    Some(chrono::Duration::seconds(day * (60*60*24)
                                 + hour * (60*60)
                                 + minute * 60
                                 + second))
}

fn get_datetime_from_capture(cap: &Captures, tz: i32) -> Option<DateTime<Utc>>{
    let dt = chrono::Duration::seconds((tz as i64) * 60 * 60);
    let now = Utc::now() - dt;

    let day     = cap.name("m_day").map_or(now.day(),       |c| c.as_str().parse().unwrap());
    let month   = cap.name("m_month").map_or(now.month(),   |c| c.as_str().parse().unwrap());
    let year    = cap.name("m_year").map_or(now.year(),     |c| c.as_str().parse().unwrap());
    let minute  = cap.name("m_minute").map_or(0,            |c| c.as_str().parse().unwrap());

    let hour    = cap.name("m_hour").unwrap().as_str().parse().unwrap();

    use chrono::offset::LocalResult::Single;
    if let Single(date) = Utc.ymd_opt(year, month, day) {
        if let Some(datetime) = date.and_hms_opt(hour, minute, 0){
            return Some(datetime + dt);
        }
    }
    None
}

//-------- TESTS ---------------------------------------------------------------

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

    #[test]
    fn parse_for_general() {
        let command = String::from("1d2h3m4s");
        let text = "some text";
        let command_text = command + " " + text;
        let dt = chrono::Duration::seconds((1 as i64) * (60*60*24)  // days
                                        + (2 as i64) * (60*60)      // hours
                                        + (3 as i64) * 60           // minutes
                                        + (4 as i64)                // seconds
                                        );
        let result = try_parse_for(&command_text);
        assert!(result.is_some());
        match result.unwrap(){
            OneTimeEvent(res) => {
                assert_eq!(res.event_text, text);
                assert!(time_moment_eq(res.event_time, Utc::now() + dt));
            },
            _ => panic!("Wrong command type")
        };
    }

    #[test]
    fn parse_for_hm() {
        let command = String::from("2h30m");
        let text = "some text";
        let command_text = command + " " + text;
        let dt = chrono::Duration::seconds((0 as i64) * (60*60*24)  // days
                                        + (2 as i64) * (60*60)      // hours
                                        + (30 as i64) * 60           // minutes
                                        + (0 as i64)                // seconds
                                        );
        let result = try_parse_for(&command_text);
        assert!(result.is_some());
        match result.unwrap(){
            OneTimeEvent(res) => {
                assert_eq!(res.event_text, text);
                assert!(time_moment_eq(res.event_time, Utc::now() + dt));
            },
            _ => panic!("Wrong command type")
        };
    }

    #[test]
    // #[ignore]
    fn parse_for_negative() {
        let command = String::from("1d-2h3m4s");
        let text = "some text";
        let command_text = command + " " + text;
        let result = try_parse_for(&command_text);
        assert!(result.is_none());
    }

    #[test]
    // #[ignore]
    fn parse_for_misspell() {
        let command = String::from("1d2j3m4s");
        let text = "some text";
        let command_text = command + " " + text;
        let result = try_parse_for(&command_text);
        assert!(result.is_none());
    }

    #[test]
    fn parse_at_tests() {
        {
            let command = String::from("24-10 at 18.30");
            let text = "some text";
            let command_text = command + " " + text;
            let now = Utc::now();
            let t = Utc.ymd(now.year(), 10, 24).and_hms(18-3, 30, 0);

            let result = try_parse_at(&command_text, -3);
            assert!(result.is_some());
            match result.unwrap(){
                OneTimeEvent(res) => {
                    assert_eq!(res.event_text, text);
                    assert_eq!(res.event_time, t);
                },
                _ => panic!("Wrong command type")
            };
        }

        {
            let command = String::from("24 at 18.30");
            let text = "some text";
            let command_text = command + " " + text;
            let now = Utc::now();
            let t = Utc.ymd(now.year(), now.month(), 24).and_hms(18-3, 30, 0);

            let result = try_parse_at(&command_text, -3);
            assert!(result.is_some());
            match result.unwrap(){
                OneTimeEvent(res) => {
                    assert_eq!(res.event_text, text);
                    assert_eq!(res.event_time, t);
                },
                _ => panic!("Wrong command type")
            };
        }
        {
            let command = String::from("at 18.30");
            let text = "some text";
            let command_text = command + " " + text;
            let now = Utc::now();
            let t = Utc.ymd(now.year(), now.month(), now.day()).and_hms(18, 30, 0);

            let result = try_parse_at(&command_text, 0);
            assert!(result.is_some());
            match result.unwrap(){
                OneTimeEvent(res) => {
                    assert_eq!(res.event_text, text);
                    assert_eq!(res.event_time, t);
                },
                _ => panic!("Wrong command type")
            };
        }
        {
            let command = String::from("at 18");
            let text = "some text";
            let command_text = command + " " + text;
            let now = Utc::now();
            let t = Utc.ymd(now.year(), now.month(), now.day()).and_hms(18, 0, 0);

            let result = try_parse_at(&command_text, 0);
            assert!(result.is_some());
            match result.unwrap(){
                OneTimeEvent(res) => {
                    assert_eq!(res.event_text, text);
                    assert_eq!(res.event_time, t);
                },
                _ => panic!("Wrong command type")
            };
        }
    }

    #[test]
    fn parse_wrong_at_tests() {
        {
            let command = String::from("30-02 at 18");
            let text = "some text";
            let command_text = command + " " + text;

            let result = try_parse_at(&command_text, -3);
            assert!(result.is_none());
        }
        {
            let command = String::from("30-20 at 18");
            let text = "some text";
            let command_text = command + " " + text;

            let result = try_parse_at(&command_text, -3);
            assert!(result.is_none());
        }
        {
            let command = String::from("at 25");
            let text = "some text";
            let command_text = command + " " + text;

            let result = try_parse_at(&command_text, -3);
            assert!(result.is_none());
        }
        {
            let command = String::from("at 23.60");
            let text = "some text";
            let command_text = command + " " + text;

            let result = try_parse_at(&command_text, -3);
            assert!(result.is_none());
        }
    }

    #[test]
    fn parse_rep_general() {
        let command = String::from("rep 06-10 10.00 5m");
        let text = "test rep";
        let command_text = command + " " + text;
        let now = Utc::now();
        let t = Utc.ymd(now.year(), 10, 6).and_hms(10-3, 0, 0);
        let dt = chrono::Duration::seconds((0 as i64) * (60*60*24)  // days
                                        + (0 as i64) * (60*60)      // hours
                                        + (5 as i64) * 60           // minutes
                                        + (0 as i64)                // seconds
                                        );
        let result = try_parse_rep(&command_text, -3);
        assert!(result.is_some());
        match result.unwrap(){
            RepetitiveEvent(res) => {
                assert_eq!(res.event_start_time, t);
                assert_eq!(res.event_wait_time, dt);
                assert_eq!(res.event_text, text);
            },
            _ => panic!("Wrong command type")
        };
    }

    fn time_moment_eq(t1: DateTime<Utc>, t2: DateTime<Utc>) -> bool{
        t1.signed_duration_since(t2).num_milliseconds().abs() < 100
    }
}<commit_msg>Hotfix<commit_after>extern crate chrono;

use chrono::prelude::*;
use regex::{Regex, Captures};

#[derive(Debug)]
pub enum Command {
    BadCommand,
    OneTimeEvent(OneTimeEventImpl),
    RepetitiveEvent(RepetitiveEventImpl),
}

#[derive(Debug)]
pub struct OneTimeEventImpl{
    pub event_time : DateTime<Utc>,
    pub event_text : String,
}

#[derive(Debug)]
pub struct RepetitiveEventImpl{
    pub event_start_time : DateTime<Utc>,
    pub event_wait_time : chrono::Duration,
    pub event_text : String,
}

const MOMENT_DAY_REGEX: &str =
    r"(?:(?P<m_day>[\d]+))?(?:-(?P<m_month>[\d]+))?(?:-(?P<m_year>[\d]+))?";

const MOMENT_TIME_REGEX: &str =
    r"(?P<m_hour>[\d]+)(?:[.|:](?P<m_minute>[\d]+))?";

const DURATION_REGEX: &str =
    r"(:?(?P<d_day>[\d]*)[D|d|Д|д])?(:?(?P<d_hour>[\d]*)[H|h|Ч|ч])?(:?(?P<d_minute>[\d]*)[M|m|М|м])?(:?(?P<d_second>[\d]*)[S|s|С|с])?";

pub fn parse_command(command_line : String, user_timezone: i32) -> Command {
    let command_line = String::from(command_line.trim());
    let mut result;
    result = try_parse_for(&command_line);
    if result.is_some() {
        return result.unwrap();
    }

    result = try_parse_at(&command_line, user_timezone);
    if result.is_some() {
        return result.unwrap();
    }

    result = try_parse_rep(&command_line, user_timezone);
    if result.is_some() {
        return result.unwrap();
    }

    warn!("parse_command: line {} doesn't match any regex", command_line);
    Command::BadCommand
}

fn try_parse_at(command_line : &String, user_timezone: i32) -> Option<Command>{
    let reg = String::from(r"^") + MOMENT_DAY_REGEX + r"\s*(at|At|в|В)\s*" + MOMENT_TIME_REGEX + r" (?P<main_text>.*)";
    let time_format = Regex::new(&reg[..]).unwrap();

    let date_captures = time_format.captures(command_line);

    if date_captures.is_none() {
        return None;
    }
    let date_captures = date_captures.unwrap();
    let text = date_captures.name("main_text").unwrap().as_str();

    if let Some(t) = get_datetime_from_capture(&date_captures, user_timezone){
        return Some(Command::OneTimeEvent
                (OneTimeEventImpl
                    { event_text : String::from(text)
                    , event_time : t}
                ));
    }
    None
}

fn try_parse_for(command_line : &String) -> Option<Command>{
    let reg = String::from("^") + DURATION_REGEX + r"(?P<divider> )(?P<main_text>.*)";
    let reg = Regex::new(&reg[..]).unwrap();

    let capture = reg.captures(command_line);
    if capture.is_none(){
        return None;
    }
    let capture = capture.unwrap();

    let text = capture.name("main_text").unwrap().as_str();
    let dt = get_duration_from_capture(&capture);
    if dt.is_none() {
        return None;
    }

    Some(Command::OneTimeEvent(OneTimeEventImpl
            { event_text : String::from(text)
            , event_time : Utc::now() + dt.unwrap() }
        ))
}

fn try_parse_rep(command_line: &String, user_timezone: i32) -> Option<Command> {
    let reg = String::from("^") + r"rep\s*" + MOMENT_DAY_REGEX
                                + r"\s+"    + MOMENT_TIME_REGEX
                                + r"\s+"    + DURATION_REGEX
                                + r"(?P<divider> )(?P<main_text>.*)";
    let reg = Regex::new(&reg[..]).unwrap();

    let capture = reg.captures(command_line);
    if capture.is_none(){
        return None;
    }
    let capture = capture.unwrap();

    let text = capture.name("main_text").unwrap().as_str();
    let time = get_datetime_from_capture(&capture, user_timezone);
    let dt = get_duration_from_capture(&capture);
    if time.is_none() || dt.is_none() {
        return None;
    }

    Some(Command::RepetitiveEvent(RepetitiveEventImpl
        {
            event_start_time : time.unwrap(),
            event_wait_time : dt.unwrap(),
            event_text : String::from(text),
        }
    ))
}

fn get_duration_from_capture(cap: &Captures) -> Option<chrono::Duration>{
    let day:    i64 = cap.name("d_day").map_or    (0, |c| c.as_str().parse().unwrap_or(0) );
    let hour:   i64 = cap.name("d_hour").map_or   (0, |c| c.as_str().parse().unwrap_or(0) );
    let minute: i64 = cap.name("d_minute").map_or (0, |c| c.as_str().parse().unwrap_or(0) );
    let second: i64 = cap.name("d_second").map_or (0, |c| c.as_str().parse().unwrap_or(0) );

    if day == 0 && hour == 0 && minute == 0 && second == 0 {
        return None;
    }

    Some(chrono::Duration::seconds(day * (60*60*24)
                                 + hour * (60*60)
                                 + minute * 60
                                 + second))
}

fn get_datetime_from_capture(cap: &Captures, tz: i32) -> Option<DateTime<Utc>>{
    let dt = chrono::Duration::seconds((tz as i64) * 60 * 60);
    let now = Utc::now() - dt;

    let day     = cap.name("m_day").map_or(now.day(),       |c| c.as_str().parse().unwrap());
    let month   = cap.name("m_month").map_or(now.month(),   |c| c.as_str().parse().unwrap());
    let year    = cap.name("m_year").map_or(now.year(),     |c| c.as_str().parse().unwrap());
    let minute  = cap.name("m_minute").map_or(0,            |c| c.as_str().parse().unwrap());

    let hour    = cap.name("m_hour").unwrap().as_str().parse().unwrap();

    use chrono::offset::LocalResult::Single;
    if let Single(date) = Utc.ymd_opt(year, month, day) {
        if let Some(datetime) = date.and_hms_opt(hour, minute, 0){
            return Some(datetime + dt);
        }
    }
    None
}

//-------- TESTS ---------------------------------------------------------------

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

    #[test]
    fn parse_for_general() {
        let command = String::from("1d2h3m4s");
        let text = "some text";
        let command_text = command + " " + text;
        let dt = chrono::Duration::seconds((1 as i64) * (60*60*24)  // days
                                        + (2 as i64) * (60*60)      // hours
                                        + (3 as i64) * 60           // minutes
                                        + (4 as i64)                // seconds
                                        );
        let result = try_parse_for(&command_text);
        assert!(result.is_some());
        match result.unwrap(){
            OneTimeEvent(res) => {
                assert_eq!(res.event_text, text);
                assert!(time_moment_eq(res.event_time, Utc::now() + dt));
            },
            _ => panic!("Wrong command type")
        };
    }

    #[test]
    fn parse_for_hm() {
        let command = String::from("2h30m");
        let text = "some text";
        let command_text = command + " " + text;
        let dt = chrono::Duration::seconds((0 as i64) * (60*60*24)  // days
                                        + (2 as i64) * (60*60)      // hours
                                        + (30 as i64) * 60           // minutes
                                        + (0 as i64)                // seconds
                                        );
        let result = try_parse_for(&command_text);
        assert!(result.is_some());
        match result.unwrap(){
            OneTimeEvent(res) => {
                assert_eq!(res.event_text, text);
                assert!(time_moment_eq(res.event_time, Utc::now() + dt));
            },
            _ => panic!("Wrong command type")
        };
    }

    #[test]
    // #[ignore]
    fn parse_for_negative() {
        let command = String::from("1d-2h3m4s");
        let text = "some text";
        let command_text = command + " " + text;
        let result = try_parse_for(&command_text);
        assert!(result.is_none());
    }

    #[test]
    // #[ignore]
    fn parse_for_misspell() {
        let command = String::from("1d2j3m4s");
        let text = "some text";
        let command_text = command + " " + text;
        let result = try_parse_for(&command_text);
        assert!(result.is_none());
    }

    #[test]
    fn parse_at_tests() {
        {
            let command = String::from("24-10 at 18.30");
            let text = "some text";
            let command_text = command + " " + text;
            let now = Utc::now();
            let t = Utc.ymd(now.year(), 10, 24).and_hms(18-3, 30, 0);

            let result = try_parse_at(&command_text, -3);
            assert!(result.is_some());
            match result.unwrap(){
                OneTimeEvent(res) => {
                    assert_eq!(res.event_text, text);
                    assert_eq!(res.event_time, t);
                },
                _ => panic!("Wrong command type")
            };
        }

        {
            let command = String::from("24 at 18.30");
            let text = "some text";
            let command_text = command + " " + text;
            let now = Utc::now();
            let t = Utc.ymd(now.year(), now.month(), 24).and_hms(18-3, 30, 0);

            let result = try_parse_at(&command_text, -3);
            assert!(result.is_some());
            match result.unwrap(){
                OneTimeEvent(res) => {
                    assert_eq!(res.event_text, text);
                    assert_eq!(res.event_time, t);
                },
                _ => panic!("Wrong command type")
            };
        }
        {
            let command = String::from("at 18.30");
            let text = "some text";
            let command_text = command + " " + text;
            let now = Utc::now();
            let t = Utc.ymd(now.year(), now.month(), now.day()).and_hms(18, 30, 0);

            let result = try_parse_at(&command_text, 0);
            assert!(result.is_some());
            match result.unwrap(){
                OneTimeEvent(res) => {
                    assert_eq!(res.event_text, text);
                    assert_eq!(res.event_time, t);
                },
                _ => panic!("Wrong command type")
            };
        }
        {
            let command = String::from("at 18");
            let text = "some text";
            let command_text = command + " " + text;
            let now = Utc::now();
            let t = Utc.ymd(now.year(), now.month(), now.day()).and_hms(18, 0, 0);

            let result = try_parse_at(&command_text, 0);
            assert!(result.is_some());
            match result.unwrap(){
                OneTimeEvent(res) => {
                    assert_eq!(res.event_text, text);
                    assert_eq!(res.event_time, t);
                },
                _ => panic!("Wrong command type")
            };
        }
    }

    #[test]
    fn parse_wrong_at_tests() {
        {
            let command = String::from("30-02 at 18");
            let text = "some text";
            let command_text = command + " " + text;

            let result = try_parse_at(&command_text, -3);
            assert!(result.is_none());
        }
        {
            let command = String::from("30-20 at 18");
            let text = "some text";
            let command_text = command + " " + text;

            let result = try_parse_at(&command_text, -3);
            assert!(result.is_none());
        }
        {
            let command = String::from("at 25");
            let text = "some text";
            let command_text = command + " " + text;

            let result = try_parse_at(&command_text, -3);
            assert!(result.is_none());
        }
        {
            let command = String::from("at 23.60");
            let text = "some text";
            let command_text = command + " " + text;

            let result = try_parse_at(&command_text, -3);
            assert!(result.is_none());
        }
    }

    #[test]
    fn parse_rep_general() {
        let command = String::from("rep 06-10 10.00 5m");
        let text = "test rep";
        let command_text = command + " " + text;
        let now = Utc::now();
        let t = Utc.ymd(now.year(), 10, 6).and_hms(10-3, 0, 0);
        let dt = chrono::Duration::seconds((0 as i64) * (60*60*24)  // days
                                        + (0 as i64) * (60*60)      // hours
                                        + (5 as i64) * 60           // minutes
                                        + (0 as i64)                // seconds
                                        );
        let result = try_parse_rep(&command_text, -3);
        assert!(result.is_some());
        match result.unwrap(){
            RepetitiveEvent(res) => {
                assert_eq!(res.event_start_time, t);
                assert_eq!(res.event_wait_time, dt);
                assert_eq!(res.event_text, text);
            },
            _ => panic!("Wrong command type")
        };
    }

    // TODO: research this case
    #[test]
    fn parse_for_negative_2() {
        let command = String::from("С мал");
        let text = "some text";
        let command_text = command + " " + text;
        let result = try_parse_for(&command_text);
        assert!(result.is_none());
    }

    fn time_moment_eq(t1: DateTime<Utc>, t2: DateTime<Utc>) -> bool{
        t1.signed_duration_since(t2).num_milliseconds().abs() < 100
    }
}<|endoftext|>


<commit_before>// Copyright 2015 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.

// Format comments.

use std::iter;

use string::{StringFormat, rewrite_string};
use utils::make_indent;

pub fn rewrite_comment(orig: &str, block_style: bool, width: usize, offset: usize) -> String {
    let s = orig.trim();

    // Edge case: block comments. Let's not trim their lines (for now).
    let (opener, closer, line_start) = if block_style {
        ("/* ", " */", " * ")
    } else {
        ("// ", "", "// ")
    };

    let max_chars = width.checked_sub(closer.len()).unwrap_or(1)
                         .checked_sub(opener.len()).unwrap_or(1);

    let fmt = StringFormat {
        opener: "",
        closer: "",
        line_start: line_start,
        line_end: "",
        width: max_chars,
        offset: offset + opener.len() - line_start.len(),
        trim_end: true,
    };

    let indent_str = make_indent(offset);
    let line_breaks = s.chars().filter(|&c| c == '\n').count();

    let (_, mut s) = s.lines().enumerate()
        .map(|(i, mut line)| {
            line = line.trim();

            // Drop old closer.
            if i == line_breaks && line.ends_with("*/") && !line.starts_with("//") {
                line = &line[..(line.len() - 2)];
            }

            line.trim_right()
        })
        .map(left_trim_comment_line)
        .map(|line| {
            if line_breaks == 0 {
                line.trim_left()
            } else {
                line
            }
        })
        .fold((true, opener.to_owned()), |(first, mut acc), line| {
            if !first {
                acc.push('\n');
                acc.push_str(&indent_str);
                acc.push_str(line_start);
            }

            if line.len() > max_chars {
                acc.push_str(&rewrite_string(line, &fmt));
            } else {
                acc.push_str(line);
            }

            (false, acc)
        });

    s.push_str(closer);

    s
}

fn left_trim_comment_line<'a>(line: &'a str) -> &'a str {
    if line.starts_with("/* ") || line.starts_with("// ") {
        &line[3..]
    } else if line.starts_with("/*") || line.starts_with("* ") || line.starts_with("//") {
        &line[2..]
    } else if line.starts_with("*") {
        &line[1..]
    } else {
        line
    }
}

#[test]
fn format_comments() {
    assert_eq!("/* test */", rewrite_comment(" //test", true, 100, 100));
    assert_eq!("// comment\n// on a", rewrite_comment("// comment on a", false, 10, 0));

    assert_eq!("//  A multi line comment\n            // between args.",
               rewrite_comment("//  A multi line comment\n             // between args.",
                               false,
                               60,
                               12));

    let input = "// comment";
    let expected = "/* com\n                                                                      \
                    * men\n                                                                      \
                    * t */";
    assert_eq!(expected, rewrite_comment(input, true, 9, 69));

    assert_eq!("/* trimmed */", rewrite_comment("/*   trimmed    */", true, 100, 100));
}

pub trait FindUncommented {
    fn find_uncommented(&self, pat: &str) -> Option<usize>;
}

impl FindUncommented for str {
    fn find_uncommented(&self, pat: &str) -> Option<usize> {
        let mut needle_iter = pat.chars();
        for (kind, (i, b)) in CharClasses::new(self.char_indices()) {
            match needle_iter.next() {
                None => {
                    return Some(i - pat.len());
                }
                Some(c) => match kind {
                    CodeCharKind::Normal if b == c => {}
                    _ => {
                        needle_iter = pat.chars();
                    }
                },
            }
        }

        // Handle case where the pattern is a suffix of the search string
        match needle_iter.next() {
            Some(_) => None,
            None => Some(self.len() - pat.len()),
        }
    }
}

#[test]
fn test_find_uncommented() {
    fn check(haystack: &str, needle: &str, expected: Option<usize>) {
        println!("haystack {:?}, needle: {:?}", haystack, needle);
        assert_eq!(expected, haystack.find_uncommented(needle));
    }

    check("/*/ */test", "test", Some(6));
    check("//test\ntest", "test", Some(7));
    check("/* comment only */", "whatever", None);
    check("/* comment */ some text /* more commentary */ result", "result", Some(46));
    check("sup // sup", "p", Some(2));
    check("sup", "x", None);
    check("π? /**/ π is nice!", "π is nice", Some(9));
    check("/*sup yo? \n sup*/ sup", "p", Some(20));
    check("hel/*lohello*/lo", "hello", None);
    check("acb", "ab", None);
    check(",/*A*/ ", ",", Some(0));
    check("abc", "abc", Some(0));
    check("/* abc */", "abc", None);
    check("/**/abc/* */", "abc", Some(4));
    check("\"/* abc */\"", "abc", Some(4));
    check("\"/* abc", "abc", Some(4));
}

// Returns the first byte position after the first comment. The given string
// is expected to be prefixed by a comment, including delimiters.
// Good: "/* /* inner */ outer */ code();"
// Bad:  "code(); // hello\n world!"
pub fn find_comment_end(s: &str) -> Option<usize> {
    let mut iter = CharClasses::new(s.char_indices());
    for (kind, (i, _c)) in &mut iter {
        if kind == CodeCharKind::Normal {
            return Some(i);
        }
    }

    // Handle case where the comment ends at the end of s.
    if iter.status == CharClassesStatus::Normal {
        Some(s.len())
    } else {
        None
    }
}

#[test]
fn comment_end() {
    assert_eq!(Some(6), find_comment_end("// hi\n"));
    assert_eq!(Some(9), find_comment_end("/* sup */ "));
    assert_eq!(Some(9), find_comment_end("/*/**/ */ "));
    assert_eq!(Some(6), find_comment_end("/*/ */ weird!"));
    assert_eq!(None, find_comment_end("/* hi /* test */"));
    assert_eq!(None, find_comment_end("// hi /* test */"));
    assert_eq!(Some(9), find_comment_end("// hi /*\n."));
}

/// Returns true if text contains any comment.
pub fn contains_comment(text: &str) -> bool {
    CharClasses::new(text.chars()).any(|(kind, _)| kind == CodeCharKind::Comment )
}

pub fn uncommented(text: &str) -> String {
    CharClasses::new(text.chars()).filter_map(|(s, c)| match s {
        CodeCharKind::Normal => Some(c),
        CodeCharKind::Comment => None
    }).collect()
}

#[test]
fn test_uncommented() {
    assert_eq!(&uncommented("abc/*...*/"), "abc");
    assert_eq!(&uncommented("// .... /* \n../* /* *** / */ */a/* // */c\n"), "..ac\n");
    assert_eq!(&uncommented("abc \" /* */\" qsdf"), "abc \" /* */\" qsdf");
}

#[test]
fn test_contains_comment() {
    assert_eq!(contains_comment("abc"), false);
    assert_eq!(contains_comment("abc // qsdf"), true);
    assert_eq!(contains_comment("abc /* kqsdf"), true);
    assert_eq!(contains_comment("abc \" /* */\" qsdf"), false);
}

struct CharClasses<T>
    where T: Iterator,
          T::Item: RichChar
{
    base: iter::Peekable<T>,
    status: CharClassesStatus,
}

trait RichChar {
    fn get_char(&self) -> char;
}

impl RichChar for char {
    fn get_char(&self) -> char {
        *self
    }
}

impl RichChar for (usize, char) {
    fn get_char(&self) -> char {
        self.1
    }
}

#[derive(PartialEq, Eq, Debug, Clone, Copy)]
enum CharClassesStatus {
    Normal,
    LitString,
    LitStringEscape,
    LitChar,
    LitCharEscape,
    // The u32 is the nesting deepness of the comment
    BlockComment(u32),
    // Status when the '/' has been consumed, but not yet the '*', deepness is the new deepness
    // (after the comment opening).
    BlockCommentOpening(u32),
    // Status when the '*' has been consumed, but not yet the '/', deepness is the new deepness
    // (after the comment closing).
    BlockCommentClosing(u32),
    LineComment,
}

#[derive(PartialEq, Eq, Debug, Clone, Copy)]
enum CodeCharKind {
    Normal,
    Comment,
}

impl<T> CharClasses<T> where T: Iterator, T::Item: RichChar {
    fn new(base: T) -> CharClasses<T> {
        CharClasses { base: base.peekable(), status: CharClassesStatus::Normal }
    }
}

impl<T> Iterator for CharClasses<T> where T: Iterator, T::Item: RichChar {
    type Item = (CodeCharKind, T::Item);

    fn next(&mut self) -> Option<(CodeCharKind, T::Item)> {
        let item = try_opt!(self.base.next());
        let chr = item.get_char();
        self.status = match self.status {
            CharClassesStatus::LitString => match chr {
                '"' => CharClassesStatus::Normal,
                '\\' => CharClassesStatus::LitStringEscape,
                _ => CharClassesStatus::LitString,
            },
            CharClassesStatus::LitStringEscape => CharClassesStatus::LitString,
            CharClassesStatus::LitChar => match chr {
                '\\' => CharClassesStatus::LitCharEscape,
                '\'' => CharClassesStatus::Normal,
                _ => CharClassesStatus::LitChar,
            },
            CharClassesStatus::LitCharEscape => CharClassesStatus::LitChar,
            CharClassesStatus::Normal => {
                match chr {
                    '"' => CharClassesStatus::LitString,
                    '\'' => CharClassesStatus::LitChar,
                    '/' => match self.base.peek() {
                        Some(next) if next.get_char() == '*' => {
                            self.status = CharClassesStatus::BlockCommentOpening(1);
                            return Some((CodeCharKind::Comment, item));
                        }
                        Some(next) if next.get_char() == '/' => {
                            self.status = CharClassesStatus::LineComment;
                            return Some((CodeCharKind::Comment, item));
                        }
                        _ => CharClassesStatus::Normal,
                    },
                    _ => CharClassesStatus::Normal,
                }
            }
            CharClassesStatus::BlockComment(deepness) => {
                if deepness == 0 {
                    // This is the closing '/'
                    assert_eq!(chr, '/');
                    self.status = CharClassesStatus::Normal;
                    return Some((CodeCharKind::Comment, item));
                }
                self.status = match self.base.peek() {
                    Some(next) if next.get_char() == '/' && chr == '*' =>
                        CharClassesStatus::BlockCommentClosing(deepness - 1),
                    Some(next) if next.get_char() == '*' && chr == '/' =>
                        CharClassesStatus::BlockCommentOpening(deepness + 1),
                    _ => CharClassesStatus::BlockComment(deepness),
                };
                return Some((CodeCharKind::Comment, item));
            }
            CharClassesStatus::BlockCommentOpening(deepness) => {
                assert_eq!(chr, '*');
                self.status = CharClassesStatus::BlockComment(deepness);
                return Some((CodeCharKind::Comment, item));
            }
            CharClassesStatus::BlockCommentClosing(deepness) => {
                assert_eq!(chr, '/');
                self.status = if deepness == 0 {
                    CharClassesStatus::Normal
                } else {
                    CharClassesStatus::BlockComment(deepness)
                };
                return Some((CodeCharKind::Comment, item));
            }
            CharClassesStatus::LineComment => {
                self.status = match chr {
                    '\n' => CharClassesStatus::Normal,
                    _ => CharClassesStatus::LineComment,
                };
                return Some((CodeCharKind::Comment, item));
            }
        };
        return Some((CodeCharKind::Normal, item));
    }
}
<commit_msg>Add a test module to comments<commit_after>// Copyright 2015 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.

// Format comments.

use std::iter;

use string::{StringFormat, rewrite_string};
use utils::make_indent;

pub fn rewrite_comment(orig: &str, block_style: bool, width: usize, offset: usize) -> String {
    let s = orig.trim();

    // Edge case: block comments. Let's not trim their lines (for now).
    let (opener, closer, line_start) = if block_style {
        ("/* ", " */", " * ")
    } else {
        ("// ", "", "// ")
    };

    let max_chars = width.checked_sub(closer.len()).unwrap_or(1)
                         .checked_sub(opener.len()).unwrap_or(1);

    let fmt = StringFormat {
        opener: "",
        closer: "",
        line_start: line_start,
        line_end: "",
        width: max_chars,
        offset: offset + opener.len() - line_start.len(),
        trim_end: true,
    };

    let indent_str = make_indent(offset);
    let line_breaks = s.chars().filter(|&c| c == '\n').count();

    let (_, mut s) = s.lines().enumerate()
        .map(|(i, mut line)| {
            line = line.trim();

            // Drop old closer.
            if i == line_breaks && line.ends_with("*/") && !line.starts_with("//") {
                line = &line[..(line.len() - 2)];
            }

            line.trim_right()
        })
        .map(left_trim_comment_line)
        .map(|line| {
            if line_breaks == 0 {
                line.trim_left()
            } else {
                line
            }
        })
        .fold((true, opener.to_owned()), |(first, mut acc), line| {
            if !first {
                acc.push('\n');
                acc.push_str(&indent_str);
                acc.push_str(line_start);
            }

            if line.len() > max_chars {
                acc.push_str(&rewrite_string(line, &fmt));
            } else {
                acc.push_str(line);
            }

            (false, acc)
        });

    s.push_str(closer);

    s
}

fn left_trim_comment_line<'a>(line: &'a str) -> &'a str {
    if line.starts_with("/* ") || line.starts_with("// ") {
        &line[3..]
    } else if line.starts_with("/*") || line.starts_with("* ") || line.starts_with("//") {
        &line[2..]
    } else if line.starts_with("*") {
        &line[1..]
    } else {
        line
    }
}

pub trait FindUncommented {
    fn find_uncommented(&self, pat: &str) -> Option<usize>;
}

impl FindUncommented for str {
    fn find_uncommented(&self, pat: &str) -> Option<usize> {
        let mut needle_iter = pat.chars();
        for (kind, (i, b)) in CharClasses::new(self.char_indices()) {
            match needle_iter.next() {
                None => {
                    return Some(i - pat.len());
                }
                Some(c) => match kind {
                    CodeCharKind::Normal if b == c => {}
                    _ => {
                        needle_iter = pat.chars();
                    }
                },
            }
        }

        // Handle case where the pattern is a suffix of the search string
        match needle_iter.next() {
            Some(_) => None,
            None => Some(self.len() - pat.len()),
        }
    }
}

// Returns the first byte position after the first comment. The given string
// is expected to be prefixed by a comment, including delimiters.
// Good: "/* /* inner */ outer */ code();"
// Bad:  "code(); // hello\n world!"
pub fn find_comment_end(s: &str) -> Option<usize> {
    let mut iter = CharClasses::new(s.char_indices());
    for (kind, (i, _c)) in &mut iter {
        if kind == CodeCharKind::Normal {
            return Some(i);
        }
    }

    // Handle case where the comment ends at the end of s.
    if iter.status == CharClassesStatus::Normal {
        Some(s.len())
    } else {
        None
    }
}

#[test]
fn comment_end() {
    assert_eq!(Some(6), find_comment_end("// hi\n"));
    assert_eq!(Some(9), find_comment_end("/* sup */ "));
    assert_eq!(Some(9), find_comment_end("/*/**/ */ "));
    assert_eq!(Some(6), find_comment_end("/*/ */ weird!"));
    assert_eq!(None, find_comment_end("/* hi /* test */"));
    assert_eq!(None, find_comment_end("// hi /* test */"));
    assert_eq!(Some(9), find_comment_end("// hi /*\n."));
}

/// Returns true if text contains any comment.
pub fn contains_comment(text: &str) -> bool {
    CharClasses::new(text.chars()).any(|(kind, _)| kind == CodeCharKind::Comment )
}

struct CharClasses<T>
    where T: Iterator,
          T::Item: RichChar
{
    base: iter::Peekable<T>,
    status: CharClassesStatus,
}

trait RichChar {
    fn get_char(&self) -> char;
}

impl RichChar for char {
    fn get_char(&self) -> char {
        *self
    }
}

impl RichChar for (usize, char) {
    fn get_char(&self) -> char {
        self.1
    }
}

#[derive(PartialEq, Eq, Debug, Clone, Copy)]
enum CharClassesStatus {
    Normal,
    LitString,
    LitStringEscape,
    LitChar,
    LitCharEscape,
    // The u32 is the nesting deepness of the comment
    BlockComment(u32),
    // Status when the '/' has been consumed, but not yet the '*', deepness is the new deepness
    // (after the comment opening).
    BlockCommentOpening(u32),
    // Status when the '*' has been consumed, but not yet the '/', deepness is the new deepness
    // (after the comment closing).
    BlockCommentClosing(u32),
    LineComment,
}

#[derive(PartialEq, Eq, Debug, Clone, Copy)]
enum CodeCharKind {
    Normal,
    Comment,
}

impl<T> CharClasses<T> where T: Iterator, T::Item: RichChar {
    fn new(base: T) -> CharClasses<T> {
        CharClasses { base: base.peekable(), status: CharClassesStatus::Normal }
    }
}

impl<T> Iterator for CharClasses<T> where T: Iterator, T::Item: RichChar {
    type Item = (CodeCharKind, T::Item);

    fn next(&mut self) -> Option<(CodeCharKind, T::Item)> {
        let item = try_opt!(self.base.next());
        let chr = item.get_char();
        self.status = match self.status {
            CharClassesStatus::LitString => match chr {
                '"' => CharClassesStatus::Normal,
                '\\' => CharClassesStatus::LitStringEscape,
                _ => CharClassesStatus::LitString,
            },
            CharClassesStatus::LitStringEscape => CharClassesStatus::LitString,
            CharClassesStatus::LitChar => match chr {
                '\\' => CharClassesStatus::LitCharEscape,
                '\'' => CharClassesStatus::Normal,
                _ => CharClassesStatus::LitChar,
            },
            CharClassesStatus::LitCharEscape => CharClassesStatus::LitChar,
            CharClassesStatus::Normal => {
                match chr {
                    '"' => CharClassesStatus::LitString,
                    '\'' => CharClassesStatus::LitChar,
                    '/' => match self.base.peek() {
                        Some(next) if next.get_char() == '*' => {
                            self.status = CharClassesStatus::BlockCommentOpening(1);
                            return Some((CodeCharKind::Comment, item));
                        }
                        Some(next) if next.get_char() == '/' => {
                            self.status = CharClassesStatus::LineComment;
                            return Some((CodeCharKind::Comment, item));
                        }
                        _ => CharClassesStatus::Normal,
                    },
                    _ => CharClassesStatus::Normal,
                }
            }
            CharClassesStatus::BlockComment(deepness) => {
                if deepness == 0 {
                    // This is the closing '/'
                    assert_eq!(chr, '/');
                    self.status = CharClassesStatus::Normal;
                    return Some((CodeCharKind::Comment, item));
                }
                self.status = match self.base.peek() {
                    Some(next) if next.get_char() == '/' && chr == '*' =>
                        CharClassesStatus::BlockCommentClosing(deepness - 1),
                    Some(next) if next.get_char() == '*' && chr == '/' =>
                        CharClassesStatus::BlockCommentOpening(deepness + 1),
                    _ => CharClassesStatus::BlockComment(deepness),
                };
                return Some((CodeCharKind::Comment, item));
            }
            CharClassesStatus::BlockCommentOpening(deepness) => {
                assert_eq!(chr, '*');
                self.status = CharClassesStatus::BlockComment(deepness);
                return Some((CodeCharKind::Comment, item));
            }
            CharClassesStatus::BlockCommentClosing(deepness) => {
                assert_eq!(chr, '/');
                self.status = if deepness == 0 {
                    CharClassesStatus::Normal
                } else {
                    CharClassesStatus::BlockComment(deepness)
                };
                return Some((CodeCharKind::Comment, item));
            }
            CharClassesStatus::LineComment => {
                self.status = match chr {
                    '\n' => CharClassesStatus::Normal,
                    _ => CharClassesStatus::LineComment,
                };
                return Some((CodeCharKind::Comment, item));
            }
        };
        return Some((CodeCharKind::Normal, item));
    }
}

#[cfg(test)]
mod test {
    use super::{CharClasses, CodeCharKind, contains_comment, rewrite_comment, FindUncommented};

    #[test]
    fn format_comments() {
        assert_eq!("/* test */", rewrite_comment(" //test", true, 100, 100));
        assert_eq!("// comment\n// on a", rewrite_comment("// comment on a", false, 10, 0));

        assert_eq!("//  A multi line comment\n            // between args.",
                   rewrite_comment("//  A multi line comment\n             // between args.",
                                   false,
                                   60,
                                   12));

        let input = "// comment";
        let expected = "/* com\n                                                                      \
                        * men\n                                                                      \
                        * t */";
        assert_eq!(expected, rewrite_comment(input, true, 9, 69));

        assert_eq!("/* trimmed */", rewrite_comment("/*   trimmed    */", true, 100, 100));
    }

    // This is probably intended to be a non-test fn, but it is not used. I'm
    // keeping it around unless it helps us test stuff.
    fn uncommented(text: &str) -> String {
        CharClasses::new(text.chars()).filter_map(|(s, c)| match s {
            CodeCharKind::Normal => Some(c),
            CodeCharKind::Comment => None
        }).collect()
    }

    #[test]
    fn test_uncommented() {
        assert_eq!(&uncommented("abc/*...*/"), "abc");
        assert_eq!(&uncommented("// .... /* \n../* /* *** / */ */a/* // */c\n"), "..ac\n");
        assert_eq!(&uncommented("abc \" /* */\" qsdf"), "abc \" /* */\" qsdf");
    }

    #[test]
    fn test_contains_comment() {
        assert_eq!(contains_comment("abc"), false);
        assert_eq!(contains_comment("abc // qsdf"), true);
        assert_eq!(contains_comment("abc /* kqsdf"), true);
        assert_eq!(contains_comment("abc \" /* */\" qsdf"), false);
    }

    #[test]
    fn test_find_uncommented() {
        fn check(haystack: &str, needle: &str, expected: Option<usize>) {
            println!("haystack {:?}, needle: {:?}", haystack, needle);
            assert_eq!(expected, haystack.find_uncommented(needle));
        }

        check("/*/ */test", "test", Some(6));
        check("//test\ntest", "test", Some(7));
        check("/* comment only */", "whatever", None);
        check("/* comment */ some text /* more commentary */ result", "result", Some(46));
        check("sup // sup", "p", Some(2));
        check("sup", "x", None);
        check("π? /**/ π is nice!", "π is nice", Some(9));
        check("/*sup yo? \n sup*/ sup", "p", Some(20));
        check("hel/*lohello*/lo", "hello", None);
        check("acb", "ab", None);
        check(",/*A*/ ", ",", Some(0));
        check("abc", "abc", Some(0));
        check("/* abc */", "abc", None);
        check("/**/abc/* */", "abc", Some(4));
        check("\"/* abc */\"", "abc", Some(4));
        check("\"/* abc", "abc", Some(4));
    }
}
<|endoftext|>