<commit_before>use std::collections::BTreeMap;
use std::io::{Read, Seek};

use events::{Event, Reader};
use {u64_option_to_usize, Date, Error};

#[derive(Clone, Debug, PartialEq)]
pub enum Value {
    Array(Vec<Value>),
    Dictionary(BTreeMap<String, Value>),
    Boolean(bool),
    Data(Vec<u8>),
    Date(Date),
    Real(f64),
    Integer(i64),
    String(String),
}

impl Value {
    pub fn read<R: Read + Seek>(reader: R) -> Result<Value, Error> {
        let reader = Reader::new(reader);
        Value::from_events(reader)
    }

    pub fn from_events<T>(events: T) -> Result<Value, Error>
    where
        T: IntoIterator<Item = Result<Event, Error>>,
    {
        Builder::new(events.into_iter()).build()
    }

    pub fn into_events(self) -> Vec<Event> {
        let mut events = Vec::new();
        self.into_events_inner(&mut events);
        events
    }

    fn into_events_inner(self, events: &mut Vec<Event>) {
        match self {
            Value::Array(array) => {
                events.push(Event::StartArray(Some(array.len() as u64)));
                for value in array {
                    value.into_events_inner(events);
                }
                events.push(Event::EndArray);
            }
            Value::Dictionary(dict) => {
                events.push(Event::StartDictionary(Some(dict.len() as u64)));
                for (key, value) in dict {
                    events.push(Event::StringValue(key));
                    value.into_events_inner(events);
                }
                events.push(Event::EndDictionary);
            }
            Value::Boolean(value) => events.push(Event::BooleanValue(value)),
            Value::Data(value) => events.push(Event::DataValue(value)),
            Value::Date(value) => events.push(Event::DateValue(value)),
            Value::Real(value) => events.push(Event::RealValue(value)),
            Value::Integer(value) => events.push(Event::IntegerValue(value)),
            Value::String(value) => events.push(Event::StringValue(value)),
        }
    }

    /// If the `Value` is an Array, returns the associated Vec.
    /// Returns None otherwise.
    pub fn as_array(&self) -> Option<&Vec<Value>> {
        match *self {
            Value::Array(ref array) => Some(array),
            _ => None,
        }
    }

    /// If the `Value` is an Array, returns the associated mutable Vec.
    /// Returns None otherwise.
    pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value>> {
        match *self {
            Value::Array(ref mut array) => Some(array),
            _ => None,
        }
    }

    /// If the `Value` is a Dictionary, returns the associated BTreeMap.
    /// Returns None otherwise.
    pub fn as_dictionary(&self) -> Option<&BTreeMap<String, Value>> {
        match *self {
            Value::Dictionary(ref map) => Some(map),
            _ => None,
        }
    }

    /// If the `Value` is a Dictionary, returns the associated mutable BTreeMap.
    /// Returns None otherwise.
    pub fn as_dictionary_mut(&mut self) -> Option<&mut BTreeMap<String, Value>> {
        match *self {
            Value::Dictionary(ref mut map) => Some(map),
            _ => None,
        }
    }

    /// If the `Value` is a Boolean, returns the associated bool.
    /// Returns None otherwise.
    pub fn as_boolean(&self) -> Option<bool> {
        match *self {
            Value::Boolean(v) => Some(v),
            _ => None,
        }
    }

    /// If the `Value` is a Data, returns the underlying Vec.
    /// Returns None otherwise.
    ///
    /// This method consumes the `Value`. If this is not desired, please use
    /// `as_data` method.
    pub fn into_data(self) -> Option<Vec<u8>> {
        match self {
            Value::Data(data) => Some(data),
            _ => None,
        }
    }

    /// If the `Value` is a Data, returns the associated Vec.
    /// Returns None otherwise.
    pub fn as_data(&self) -> Option<&[u8]> {
        match *self {
            Value::Data(ref data) => Some(data),
            _ => None,
        }
    }

    /// If the `Value` is a Date, returns the associated DateTime.
    /// Returns None otherwise.
    pub fn as_date(&self) -> Option<&Date> {
        match *self {
            Value::Date(ref date) => Some(date),
            _ => None,
        }
    }

    /// If the `Value` is a Real, returns the associated f64.
    /// Returns None otherwise.
    pub fn as_real(&self) -> Option<f64> {
        match *self {
            Value::Real(v) => Some(v),
            _ => None,
        }
    }

    /// If the `Value` is an Integer, returns the associated i64.
    /// Returns None otherwise.
    pub fn as_integer(&self) -> Option<i64> {
        match *self {
            Value::Integer(v) => Some(v),
            _ => None,
        }
    }

    /// If the `Value` is a String, returns the underlying String.
    /// Returns None otherwise.
    ///
    /// This method consumes the `Value`. If this is not desired, please use
    /// `as_string` method.
    pub fn into_string(self) -> Option<String> {
        match self {
            Value::String(v) => Some(v),
            _ => None,
        }
    }

    /// If the `Value` is a String, returns the associated str.
    /// Returns None otherwise.
    pub fn as_string(&self) -> Option<&str> {
        match *self {
            Value::String(ref v) => Some(v),
            _ => None,
        }
    }
}

impl From<Vec<Value>> for Value {
    fn from(from: Vec<Value>) -> Value {
        Value::Array(from)
    }
}

impl From<BTreeMap<String, Value>> for Value {
    fn from(from: BTreeMap<String, Value>) -> Value {
        Value::Dictionary(from)
    }
}

impl From<bool> for Value {
    fn from(from: bool) -> Value {
        Value::Boolean(from)
    }
}

impl<'a> From<&'a bool> for Value {
    fn from(from: &'a bool) -> Value {
        Value::Boolean(*from)
    }
}

impl From<Date> for Value {
    fn from(from: Date) -> Value {
        Value::Date(from)
    }
}

impl<'a> From<&'a Date> for Value {
    fn from(from: &'a Date) -> Value {
        Value::Date(from.clone())
    }
}

impl From<f64> for Value {
    fn from(from: f64) -> Value {
        Value::Real(from)
    }
}

impl From<f32> for Value {
    fn from(from: f32) -> Value {
        Value::Real(from.into())
    }
}

impl From<i64> for Value {
    fn from(from: i64) -> Value {
        Value::Integer(from)
    }
}

impl From<i32> for Value {
    fn from(from: i32) -> Value {
        Value::Integer(from.into())
    }
}

impl From<i16> for Value {
    fn from(from: i16) -> Value {
        Value::Integer(from.into())
    }
}

impl From<i8> for Value {
    fn from(from: i8) -> Value {
        Value::Integer(from.into())
    }
}

impl From<u32> for Value {
    fn from(from: u32) -> Value {
        Value::Integer(from.into())
    }
}

impl From<u16> for Value {
    fn from(from: u16) -> Value {
        Value::Integer(from.into())
    }
}

impl From<u8> for Value {
    fn from(from: u8) -> Value {
        Value::Integer(from.into())
    }
}

impl<'a> From<&'a f64> for Value {
    fn from(from: &'a f64) -> Value {
        Value::Real(*from)
    }
}

impl<'a> From<&'a f32> for Value {
    fn from(from: &'a f32) -> Value {
        Value::Real((*from).into())
    }
}

impl<'a> From<&'a i64> for Value {
    fn from(from: &'a i64) -> Value {
        Value::Integer(*from)
    }
}

impl<'a> From<&'a i32> for Value {
    fn from(from: &'a i32) -> Value {
        Value::Integer((*from).into())
    }
}

impl<'a> From<&'a i16> for Value {
    fn from(from: &'a i16) -> Value {
        Value::Integer((*from).into())
    }
}

impl<'a> From<&'a i8> for Value {
    fn from(from: &'a i8) -> Value {
        Value::Integer((*from).into())
    }
}

impl<'a> From<&'a u32> for Value {
    fn from(from: &'a u32) -> Value {
        Value::Integer((*from).into())
    }
}

impl<'a> From<&'a u16> for Value {
    fn from(from: &'a u16) -> Value {
        Value::Integer((*from).into())
    }
}

impl<'a> From<&'a u8> for Value {
    fn from(from: &'a u8) -> Value {
        Value::Integer((*from).into())
    }
}

impl From<String> for Value {
    fn from(from: String) -> Value {
        Value::String(from)
    }
}

impl<'a> From<&'a str> for Value {
    fn from(from: &'a str) -> Value {
        Value::String(from.into())
    }
}

struct Builder<T> {
    stream: T,
    token: Option<Event>,
}

impl<T: Iterator<Item = Result<Event, Error>>> Builder<T> {
    fn new(stream: T) -> Builder<T> {
        Builder {
            stream,
            token: None,
        }
    }

    fn build(mut self) -> Result<Value, Error> {
        self.bump()?;
        let plist = self.build_value()?;

        // Ensure the stream has been fully consumed
        self.bump()?;
        match self.token {
            None => Ok(plist),
            _ => Err(Error::InvalidData),
        }
    }

    fn bump(&mut self) -> Result<(), Error> {
        self.token = match self.stream.next() {
            Some(Ok(token)) => Some(token),
            Some(Err(err)) => return Err(err),
            None => None,
        };
        Ok(())
    }

    fn build_value(&mut self) -> Result<Value, Error> {
        match self.token.take() {
            Some(Event::StartArray(len)) => Ok(Value::Array(self.build_array(len)?)),
            Some(Event::StartDictionary(len)) => Ok(Value::Dictionary(self.build_dict(len)?)),

            Some(Event::BooleanValue(b)) => Ok(Value::Boolean(b)),
            Some(Event::DataValue(d)) => Ok(Value::Data(d)),
            Some(Event::DateValue(d)) => Ok(Value::Date(d)),
            Some(Event::IntegerValue(i)) => Ok(Value::Integer(i)),
            Some(Event::RealValue(f)) => Ok(Value::Real(f)),
            Some(Event::StringValue(s)) => Ok(Value::String(s)),

            Some(Event::EndArray) => Err(Error::InvalidData),
            Some(Event::EndDictionary) => Err(Error::InvalidData),

            // The stream should not have ended here
            None => Err(Error::InvalidData),
        }
    }

    fn build_array(&mut self, len: Option<u64>) -> Result<Vec<Value>, Error> {
        let len = u64_option_to_usize(len)?;
        let mut values = match len {
            Some(len) => Vec::with_capacity(len),
            None => Vec::new(),
        };

        loop {
            self.bump()?;
            if let Some(Event::EndArray) = self.token {
                self.token.take();
                return Ok(values);
            }
            values.push(self.build_value()?);
        }
    }

    fn build_dict(&mut self, _len: Option<u64>) -> Result<BTreeMap<String, Value>, Error> {
        let mut values = BTreeMap::new();

        loop {
            self.bump()?;
            match self.token.take() {
                Some(Event::EndDictionary) => return Ok(values),
                Some(Event::StringValue(s)) => {
                    self.bump()?;
                    values.insert(s, self.build_value()?);
                }
                _ => {
                    // Only string keys are supported in plists
                    return Err(Error::InvalidData);
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;
    use std::time::SystemTime;

    use super::*;
    use events::Event::*;
    use {Date, Value};

    #[test]
    fn value_accessors() {
        let vec = vec![Value::Real(0.0)];
        let mut array = Value::Array(vec.clone());
        assert_eq!(array.as_array(), Some(&vec.clone()));
        assert_eq!(array.as_array_mut(), Some(&mut vec.clone()));

        let mut map = BTreeMap::new();
        map.insert("key1".to_owned(), Value::String("value1".to_owned()));
        let mut dict = Value::Dictionary(map.clone());
        assert_eq!(dict.as_dictionary(), Some(&map.clone()));
        assert_eq!(dict.as_dictionary_mut(), Some(&mut map.clone()));

        assert_eq!(Value::Boolean(true).as_boolean(), Some(true));

        let slice: &[u8] = &[1, 2, 3];
        assert_eq!(Value::Data(slice.to_vec()).as_data(), Some(slice));
        assert_eq!(
            Value::Data(slice.to_vec()).into_data(),
            Some(slice.to_vec())
        );

        let date: Date = SystemTime::now().into();
        assert_eq!(Value::Date(date.clone()).as_date(), Some(&date));

        assert_eq!(Value::Real(0.0).as_real(), Some(0.0));
        assert_eq!(Value::Integer(1).as_integer(), Some(1));
        assert_eq!(Value::String("2".to_owned()).as_string(), Some("2"));
        assert_eq!(
            Value::String("t".to_owned()).into_string(),
            Some("t".to_owned())
        );
    }

    #[test]
    fn builder() {
        // Input
        let events = vec![
            StartDictionary(None),
            StringValue("Author".to_owned()),
            StringValue("William Shakespeare".to_owned()),
            StringValue("Lines".to_owned()),
            StartArray(None),
            StringValue("It is a tale told by an idiot,".to_owned()),
            StringValue("Full of sound and fury, signifying nothing.".to_owned()),
            EndArray,
            StringValue("Birthdate".to_owned()),
            IntegerValue(1564),
            StringValue("Height".to_owned()),
            RealValue(1.60),
            EndDictionary,
        ];

        let builder = Builder::new(events.into_iter().map(|e| Ok(e)));
        let plist = builder.build();

        // Expected output
        let mut lines = Vec::new();
        lines.push(Value::String("It is a tale told by an idiot,".to_owned()));
        lines.push(Value::String(
            "Full of sound and fury, signifying nothing.".to_owned(),
        ));

        let mut dict = BTreeMap::new();
        dict.insert(
            "Author".to_owned(),
            Value::String("William Shakespeare".to_owned()),
        );
        dict.insert("Lines".to_owned(), Value::Array(lines));
        dict.insert("Birthdate".to_owned(), Value::Integer(1564));
        dict.insert("Height".to_owned(), Value::Real(1.60));

        assert_eq!(plist.unwrap(), Value::Dictionary(dict));
    }
}
<commit_msg>Minor doc tweaks for Value type.<commit_after>use std::collections::BTreeMap;
use std::io::{Read, Seek};

use events::{Event, Reader};
use {u64_option_to_usize, Date, Error};

#[derive(Clone, Debug, PartialEq)]
pub enum Value {
    Array(Vec<Value>),
    Dictionary(BTreeMap<String, Value>),
    Boolean(bool),
    Data(Vec<u8>),
    Date(Date),
    Real(f64),
    Integer(i64),
    String(String),
}

impl Value {
    pub fn read<R: Read + Seek>(reader: R) -> Result<Value, Error> {
        let reader = Reader::new(reader);
        Value::from_events(reader)
    }

    pub fn from_events<T>(events: T) -> Result<Value, Error>
    where
        T: IntoIterator<Item = Result<Event, Error>>,
    {
        Builder::new(events.into_iter()).build()
    }

    pub fn into_events(self) -> Vec<Event> {
        let mut events = Vec::new();
        self.into_events_inner(&mut events);
        events
    }

    fn into_events_inner(self, events: &mut Vec<Event>) {
        match self {
            Value::Array(array) => {
                events.push(Event::StartArray(Some(array.len() as u64)));
                for value in array {
                    value.into_events_inner(events);
                }
                events.push(Event::EndArray);
            }
            Value::Dictionary(dict) => {
                events.push(Event::StartDictionary(Some(dict.len() as u64)));
                for (key, value) in dict {
                    events.push(Event::StringValue(key));
                    value.into_events_inner(events);
                }
                events.push(Event::EndDictionary);
            }
            Value::Boolean(value) => events.push(Event::BooleanValue(value)),
            Value::Data(value) => events.push(Event::DataValue(value)),
            Value::Date(value) => events.push(Event::DateValue(value)),
            Value::Real(value) => events.push(Event::RealValue(value)),
            Value::Integer(value) => events.push(Event::IntegerValue(value)),
            Value::String(value) => events.push(Event::StringValue(value)),
        }
    }

    /// If the `Value` is an Array, returns the associated `Vec`.
    ///
    /// Returns `None` otherwise.
    pub fn as_array(&self) -> Option<&Vec<Value>> {
        match *self {
            Value::Array(ref array) => Some(array),
            _ => None,
        }
    }

    /// If the `Value` is an Array, returns the associated mutable `Vec`.
    ///
    /// Returns `None` otherwise.
    pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value>> {
        match *self {
            Value::Array(ref mut array) => Some(array),
            _ => None,
        }
    }

    /// If the `Value` is a Dictionary, returns the associated `BTreeMap`.
    ///
    /// Returns `None` otherwise.
    pub fn as_dictionary(&self) -> Option<&BTreeMap<String, Value>> {
        match *self {
            Value::Dictionary(ref map) => Some(map),
            _ => None,
        }
    }

    /// If the `Value` is a Dictionary, returns the associated mutable `BTreeMap`.
    ///
    /// Returns `None` otherwise.
    pub fn as_dictionary_mut(&mut self) -> Option<&mut BTreeMap<String, Value>> {
        match *self {
            Value::Dictionary(ref mut map) => Some(map),
            _ => None,
        }
    }

    /// If the `Value` is a Boolean, returns the associated `bool`.
    ///
    /// Returns `None` otherwise.
    pub fn as_boolean(&self) -> Option<bool> {
        match *self {
            Value::Boolean(v) => Some(v),
            _ => None,
        }
    }

    /// If the `Value` is a Data, returns the underlying `Vec`.
    ///
    /// Returns `None` otherwise.
    ///
    /// This method consumes the `Value`. If this is not desired, please use
    /// `as_data` method.
    pub fn into_data(self) -> Option<Vec<u8>> {
        match self {
            Value::Data(data) => Some(data),
            _ => None,
        }
    }

    /// If the `Value` is a Data, returns the associated `Vec`.
    ///
    /// Returns `None` otherwise.
    pub fn as_data(&self) -> Option<&[u8]> {
        match *self {
            Value::Data(ref data) => Some(data),
            _ => None,
        }
    }

    /// If the `Value` is a Date, returns the associated `Date`.
    ///
    /// Returns `None` otherwise.
    pub fn as_date(&self) -> Option<&Date> {
        match *self {
            Value::Date(ref date) => Some(date),
            _ => None,
        }
    }

    /// If the `Value` is a Real, returns the associated `f64`.
    ///
    /// Returns `None` otherwise.
    pub fn as_real(&self) -> Option<f64> {
        match *self {
            Value::Real(v) => Some(v),
            _ => None,
        }
    }

    /// If the `Value` is an Integer, returns the associated `i64`.
    ///
    /// Returns `None` otherwise.
    pub fn as_integer(&self) -> Option<i64> {
        match *self {
            Value::Integer(v) => Some(v),
            _ => None,
        }
    }

    /// If the `Value` is a String, returns the underlying `String`.
    ///
    /// Returns `None` otherwise.
    ///
    /// This method consumes the `Value`. If this is not desired, please use
    /// `as_string` method.
    pub fn into_string(self) -> Option<String> {
        match self {
            Value::String(v) => Some(v),
            _ => None,
        }
    }

    /// If the `Value` is a String, returns the associated `str`.
    ///
    /// Returns `None` otherwise.
    pub fn as_string(&self) -> Option<&str> {
        match *self {
            Value::String(ref v) => Some(v),
            _ => None,
        }
    }
}

impl From<Vec<Value>> for Value {
    fn from(from: Vec<Value>) -> Value {
        Value::Array(from)
    }
}

impl From<BTreeMap<String, Value>> for Value {
    fn from(from: BTreeMap<String, Value>) -> Value {
        Value::Dictionary(from)
    }
}

impl From<bool> for Value {
    fn from(from: bool) -> Value {
        Value::Boolean(from)
    }
}

impl<'a> From<&'a bool> for Value {
    fn from(from: &'a bool) -> Value {
        Value::Boolean(*from)
    }
}

impl From<Date> for Value {
    fn from(from: Date) -> Value {
        Value::Date(from)
    }
}

impl<'a> From<&'a Date> for Value {
    fn from(from: &'a Date) -> Value {
        Value::Date(from.clone())
    }
}

impl From<f64> for Value {
    fn from(from: f64) -> Value {
        Value::Real(from)
    }
}

impl From<f32> for Value {
    fn from(from: f32) -> Value {
        Value::Real(from.into())
    }
}

impl From<i64> for Value {
    fn from(from: i64) -> Value {
        Value::Integer(from)
    }
}

impl From<i32> for Value {
    fn from(from: i32) -> Value {
        Value::Integer(from.into())
    }
}

impl From<i16> for Value {
    fn from(from: i16) -> Value {
        Value::Integer(from.into())
    }
}

impl From<i8> for Value {
    fn from(from: i8) -> Value {
        Value::Integer(from.into())
    }
}

impl From<u32> for Value {
    fn from(from: u32) -> Value {
        Value::Integer(from.into())
    }
}

impl From<u16> for Value {
    fn from(from: u16) -> Value {
        Value::Integer(from.into())
    }
}

impl From<u8> for Value {
    fn from(from: u8) -> Value {
        Value::Integer(from.into())
    }
}

impl<'a> From<&'a f64> for Value {
    fn from(from: &'a f64) -> Value {
        Value::Real(*from)
    }
}

impl<'a> From<&'a f32> for Value {
    fn from(from: &'a f32) -> Value {
        Value::Real((*from).into())
    }
}

impl<'a> From<&'a i64> for Value {
    fn from(from: &'a i64) -> Value {
        Value::Integer(*from)
    }
}

impl<'a> From<&'a i32> for Value {
    fn from(from: &'a i32) -> Value {
        Value::Integer((*from).into())
    }
}

impl<'a> From<&'a i16> for Value {
    fn from(from: &'a i16) -> Value {
        Value::Integer((*from).into())
    }
}

impl<'a> From<&'a i8> for Value {
    fn from(from: &'a i8) -> Value {
        Value::Integer((*from).into())
    }
}

impl<'a> From<&'a u32> for Value {
    fn from(from: &'a u32) -> Value {
        Value::Integer((*from).into())
    }
}

impl<'a> From<&'a u16> for Value {
    fn from(from: &'a u16) -> Value {
        Value::Integer((*from).into())
    }
}

impl<'a> From<&'a u8> for Value {
    fn from(from: &'a u8) -> Value {
        Value::Integer((*from).into())
    }
}

impl From<String> for Value {
    fn from(from: String) -> Value {
        Value::String(from)
    }
}

impl<'a> From<&'a str> for Value {
    fn from(from: &'a str) -> Value {
        Value::String(from.into())
    }
}

struct Builder<T> {
    stream: T,
    token: Option<Event>,
}

impl<T: Iterator<Item = Result<Event, Error>>> Builder<T> {
    fn new(stream: T) -> Builder<T> {
        Builder {
            stream,
            token: None,
        }
    }

    fn build(mut self) -> Result<Value, Error> {
        self.bump()?;
        let plist = self.build_value()?;

        // Ensure the stream has been fully consumed
        self.bump()?;
        match self.token {
            None => Ok(plist),
            _ => Err(Error::InvalidData),
        }
    }

    fn bump(&mut self) -> Result<(), Error> {
        self.token = match self.stream.next() {
            Some(Ok(token)) => Some(token),
            Some(Err(err)) => return Err(err),
            None => None,
        };
        Ok(())
    }

    fn build_value(&mut self) -> Result<Value, Error> {
        match self.token.take() {
            Some(Event::StartArray(len)) => Ok(Value::Array(self.build_array(len)?)),
            Some(Event::StartDictionary(len)) => Ok(Value::Dictionary(self.build_dict(len)?)),

            Some(Event::BooleanValue(b)) => Ok(Value::Boolean(b)),
            Some(Event::DataValue(d)) => Ok(Value::Data(d)),
            Some(Event::DateValue(d)) => Ok(Value::Date(d)),
            Some(Event::IntegerValue(i)) => Ok(Value::Integer(i)),
            Some(Event::RealValue(f)) => Ok(Value::Real(f)),
            Some(Event::StringValue(s)) => Ok(Value::String(s)),

            Some(Event::EndArray) => Err(Error::InvalidData),
            Some(Event::EndDictionary) => Err(Error::InvalidData),

            // The stream should not have ended here
            None => Err(Error::InvalidData),
        }
    }

    fn build_array(&mut self, len: Option<u64>) -> Result<Vec<Value>, Error> {
        let len = u64_option_to_usize(len)?;
        let mut values = match len {
            Some(len) => Vec::with_capacity(len),
            None => Vec::new(),
        };

        loop {
            self.bump()?;
            if let Some(Event::EndArray) = self.token {
                self.token.take();
                return Ok(values);
            }
            values.push(self.build_value()?);
        }
    }

    fn build_dict(&mut self, _len: Option<u64>) -> Result<BTreeMap<String, Value>, Error> {
        let mut values = BTreeMap::new();

        loop {
            self.bump()?;
            match self.token.take() {
                Some(Event::EndDictionary) => return Ok(values),
                Some(Event::StringValue(s)) => {
                    self.bump()?;
                    values.insert(s, self.build_value()?);
                }
                _ => {
                    // Only string keys are supported in plists
                    return Err(Error::InvalidData);
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;
    use std::time::SystemTime;

    use super::*;
    use events::Event::*;
    use {Date, Value};

    #[test]
    fn value_accessors() {
        let vec = vec![Value::Real(0.0)];
        let mut array = Value::Array(vec.clone());
        assert_eq!(array.as_array(), Some(&vec.clone()));
        assert_eq!(array.as_array_mut(), Some(&mut vec.clone()));

        let mut map = BTreeMap::new();
        map.insert("key1".to_owned(), Value::String("value1".to_owned()));
        let mut dict = Value::Dictionary(map.clone());
        assert_eq!(dict.as_dictionary(), Some(&map.clone()));
        assert_eq!(dict.as_dictionary_mut(), Some(&mut map.clone()));

        assert_eq!(Value::Boolean(true).as_boolean(), Some(true));

        let slice: &[u8] = &[1, 2, 3];
        assert_eq!(Value::Data(slice.to_vec()).as_data(), Some(slice));
        assert_eq!(
            Value::Data(slice.to_vec()).into_data(),
            Some(slice.to_vec())
        );

        let date: Date = SystemTime::now().into();
        assert_eq!(Value::Date(date.clone()).as_date(), Some(&date));

        assert_eq!(Value::Real(0.0).as_real(), Some(0.0));
        assert_eq!(Value::Integer(1).as_integer(), Some(1));
        assert_eq!(Value::String("2".to_owned()).as_string(), Some("2"));
        assert_eq!(
            Value::String("t".to_owned()).into_string(),
            Some("t".to_owned())
        );
    }

    #[test]
    fn builder() {
        // Input
        let events = vec![
            StartDictionary(None),
            StringValue("Author".to_owned()),
            StringValue("William Shakespeare".to_owned()),
            StringValue("Lines".to_owned()),
            StartArray(None),
            StringValue("It is a tale told by an idiot,".to_owned()),
            StringValue("Full of sound and fury, signifying nothing.".to_owned()),
            EndArray,
            StringValue("Birthdate".to_owned()),
            IntegerValue(1564),
            StringValue("Height".to_owned()),
            RealValue(1.60),
            EndDictionary,
        ];

        let builder = Builder::new(events.into_iter().map(|e| Ok(e)));
        let plist = builder.build();

        // Expected output
        let mut lines = Vec::new();
        lines.push(Value::String("It is a tale told by an idiot,".to_owned()));
        lines.push(Value::String(
            "Full of sound and fury, signifying nothing.".to_owned(),
        ));

        let mut dict = BTreeMap::new();
        dict.insert(
            "Author".to_owned(),
            Value::String("William Shakespeare".to_owned()),
        );
        dict.insert("Lines".to_owned(), Value::Array(lines));
        dict.insert("Birthdate".to_owned(), Value::Integer(1564));
        dict.insert("Height".to_owned(), Value::Real(1.60));

        assert_eq!(plist.unwrap(), Value::Dictionary(dict));
    }
}
<|endoftext|>


<commit_before>use std::hash;
use std::hash::Hash;
use std::int::MAX;
use std::num::Int;
use std::result::Result;

// The idea of a "balanced fixed-point" computation is to do two
// things simultaneously:
//
// (1) compute the fixed-point value of a function by running an
// (abstracted) iterative algorithm.
//
// (2) structure the evaluation of this algorithm as a balanced binary
// tree of Adapton thunks, where each thunk in the tree stores an
// intermediate state of the algorithm.
//
// The second goal is motivated by Adapton's need for a shallow
// call-graph.  If one were to write a loop naively, the call-graph
// may not be shallow.  By using this fixed-point combinator in place
// of a while loop (or some tail-recursive loop), we can guarantee
// (probabilistically) that the call-graph is shallow.

trait FpFn {
    // Fixed-point Function.
    //
    /// The Self type need not be stateful at all.
    ///
    /// Instead, a FpFn exposes its state (abstractly) to the loop
    /// that contains it.  There are two parts:
    //
    ///  - The loop iteration's current state (type `St`)
    //
    ///  - Any "meta-state" needed to explore the space of states
    ///  (type `Sys`).  This meta state may consist of nothing, or it
    ///  may consist of queues, stacks, and/or sets of
    ///  previously-visited states.
    //
    /// Our fixed-point loop below needs a way of hashing the "current
    /// state" (type `St`).  It builds a binary tree of stepped states
    /// (type `St_stepped`).

    type St : Hash ;
    type St_stepped ;
    type Sys ;
    fn step (self:& Self, st:Self::St, sys:Self::Sys) -> (Self::St_stepped, Self::Sys) ;
    fn next (self:& Self, sys:Self::Sys) -> Result<(Self::St, Self::Sys), Self::Sys> ;
}

trait BinTree<T> {
    // Our fixed-point loop builds a balanced binary tree of stepped states.
    type Tree;
    fn leaf(self:& Self) -> Self::Tree;
    fn bin(self:& Self, left:Self::Tree, T, right:Self::Tree) -> Self::Tree;
}

trait FpLp<F:FpFn, BT:BinTree<F::St_stepped>> {

    // We leave this abstract here.
    // It can either be a simple wrapper around work_tree, or
    // something that uses memoization.
    fn work_recur (self:&Self, f:&F, bt:&BT,
                  left:BT::Tree, left_lev:int,
                  sys:F::Sys, parent_lev:int) -> (F::Sys, BT::Tree) ;

    // Our fixed-point loop.  It uses a hashing and probabilistic
    // reasoning to build a balanced binary tree of stepped states.
    //
    // Key assumption: Each state (of type `F::St`) has a distinct hash.
    fn work_tree (self:&Self, f:&F, bt:&BT,
                  left:BT::Tree, left_lev:int,
                  sys:F::Sys, parent_lev:int) -> (F::Sys, BT::Tree)
    {
        let nxt = f.next(sys) ;
        match nxt {
            Err(sys) => (sys, left),
            Ok((st,sys)) => {
                let st_lev = Int::trailing_zeros(hash::hash(&st)) as int ;
                if left_lev <= st_lev &&
                    st_lev  <= parent_lev
                {
                    let (st, sys) = f.step(st, sys) ;
                    let (sys,right) = self.work_recur (f, bt, bt.leaf(), -1, sys, st_lev );
                    let tree = bt.bin(left,st,right) ;
                    let (sys,tree) = self.work_recur (f, bt, tree, st_lev, sys, parent_lev );
                    (sys,tree)
                }
                else {
                    (sys,left)
                }
            }
        }
    }
    fn compute (self:&Self, f:&F, bt:&BT, sys:F::Sys) -> (F::Sys,BT::Tree) {
        self.work_recur (f, bt, bt.leaf(), -1, sys, MAX )
    }
}

impl<F:FpFn, BT:BinTree<F::St_stepped>> FpLp<F,BT> for () {
    fn work_recur (self:&Self, f:&F, bt:&BT,
                   left:BT::Tree, left_lev:int,
                   sys:F::Sys, parent_lev:int) -> (F::Sys, BT::Tree) {
        self.work_tree (f, bt, left, left_lev, sys, parent_lev )
    }
}
<commit_msg>playing with balfp abstractions<commit_after>use std::hash;
use std::hash::Hash;
use std::int::MAX;
use std::num::Int;
use std::result::Result;

use art::*;

// The idea of a "balanced fixed-point" computation is to do two
// things simultaneously:
//
// (1) compute the fixed-point value of a function by running an
// (abstracted) iterative algorithm.
//
// (2) structure the evaluation of this algorithm as a balanced binary
// tree of Adapton thunks, where each thunk in the tree stores an
// intermediate state of the algorithm.
//
// The second goal is motivated by Adapton's need for a shallow
// call-graph.  If one were to write a loop naively, the call-graph
// may not be shallow.  By using this fixed-point combinator in place
// of a while loop (or some tail-recursive loop), we can guarantee
// (probabilistically) that the call-graph is shallow.

trait FpFn {
    // Fixed-point Function.
    //
    /// The Self type need not be stateful at all.
    ///
    /// Instead, a FpFn exposes its state (abstractly) to the loop
    /// that contains it.  There are two parts:
    //
    ///  - The loop iteration's current state (type `St`)
    //
    ///  - Any "meta-state" needed to explore the space of states
    ///  (type `Sys`).  This meta state may consist of nothing, or it
    ///  may consist of queues, stacks, and/or sets of
    ///  previously-visited states.
    //
    /// Our fixed-point loop below needs a way of hashing the "current
    /// state" (type `St`).  It builds a binary tree of stepped states
    /// (type `St_stepped`).

    type St : Hash ;
    type St_stepped ;
    type Sys ;
    fn step (self:& Self, st:Self::St, sys:Self::Sys) -> (Self::St_stepped, Self::Sys) ;
    fn next (self:& Self, sys:Self::Sys) -> Result<(Self::St, Self::Sys), Self::Sys> ;
}

trait BinTree<T> {
    // Our fixed-point loop builds a balanced binary tree of stepped states.
    type Tree;
    fn leaf(self:& Self) -> Self::Tree;
    fn bin(self:& Self, left:Self::Tree, T, right:Self::Tree) -> Self::Tree;
}

trait FpLp<F:FpFn, BT:BinTree<F::St_stepped>> {

    // We leave this abstract here.
    // It can either be a simple wrapper around work_tree, or
    // something that uses memoization.
    fn work_recur (self:&Self, f:&F, bt:&BT,
                  left:BT::Tree, left_lev:int,
                  sys:F::Sys, parent_lev:int) -> (F::Sys, BT::Tree) ;

    // Our fixed-point loop.  It uses a hashing and probabilistic
    // reasoning to build a balanced binary tree of stepped states.
    //
    // Key assumption: Each state (of type `F::St`) has a distinct hash.
    fn work_tree (self:&Self, f:&F, bt:&BT,
                  left:BT::Tree, left_lev:int,
                  sys:F::Sys, parent_lev:int) -> (F::Sys, BT::Tree)
    {
        let nxt = f.next(sys) ;
        match nxt {
            Err(sys) => (sys, left),
            Ok((st,sys)) => {
                let st_lev = Int::trailing_zeros(hash::hash(&st)) as int ;
                if left_lev <= st_lev &&
                    st_lev  <= parent_lev
                {
                    let (st, sys) = f.step(st, sys) ;
                    let (sys,right) = self.work_recur (f, bt, bt.leaf(), -1, sys, st_lev );
                    let tree = bt.bin(left,st,right) ;
                    let (sys,tree) = self.work_recur (f, bt, tree, st_lev, sys, parent_lev );
                    (sys,tree)
                }
                else {
                    (sys,left)
                }
            }
        }
    }
    fn compute (self:&Self, f:&F, bt:&BT, sys:F::Sys) -> (F::Sys,BT::Tree) {
        self.work_recur (f, bt, bt.leaf(), -1, sys, MAX )
    }
}

struct Fp_direct ;
impl<F:FpFn, BT:BinTree<F::St_stepped>> FpLp<F,BT> for Fp_direct {
    fn work_recur (self:&Self, f:&F, bt:&BT,
                   left:BT::Tree, left_lev:int,
                   sys:F::Sys, parent_lev:int) -> (F::Sys, BT::Tree) {
        self.work_tree (f, bt, left, left_lev, sys, parent_lev )
    }
}

struct Fp_art ;
impl<F:FpFn, BT:BinTree<F::St_stepped>> FpLp<F,BT> for Fp_art {
    fn work_recur (self:&Self, f:&F, bt:&BT,
                   left:BT::Tree, left_lev:int,
                   sys:F::Sys, parent_lev:int) -> (F::Sys, BT::Tree) {
        let n = panic!("");
        let a = nart!(n, self.work_tree (f, bt, left, left_lev, sys, parent_lev));
        force( a )
    }
}

<|endoftext|>


<commit_before>
use std::rc::Rc;
use std::cell::RefCell;
use std::mem::replace;

pub const BCSIZE: usize = 4;
pub const BCSIZEP4: usize = BCSIZE+4;

pub mod bc{
  pub const HALT: u8 = 0;
  pub const INT:  u8 = 1;
  pub const NEG:  u8 = 2;
  pub const ADD:  u8 = 3;
  pub const SUB:  u8 = 4;
  pub const MPY:  u8 = 5;
  pub const DIV:  u8 = 6;
  pub const IDIV: u8 = 7;
  pub const LIST: u8 = 8;
}

pub struct List{
  v: Vec<Object>
}

impl List{
  pub fn new_object(v: Vec<Object>) -> Object{
    return Object::List(Rc::new(RefCell::new(List{v: v})));
  }
}

pub enum Object{
  Null, Bool(bool), Int(i32), Float(f64),
  List(Rc<RefCell<List>>)
}

fn list_to_string(a: &[Object]) -> String{
  let mut s = String::from("[");
  for i in 0..a.len() {
    if i!=0 {s.push_str(", ");}
    s.push_str(&object_to_string(&a[i]));
  }
  s.push_str("]");
  return s;
}

fn object_to_string(x: &Object) -> String{
  match x {
    &Object::Null => String::from("null"),
    &Object::Bool(b) => String::from(if b {"true"} else {"false"}),
    &Object::Int(i) => format!("{}",i),
    &Object::List(ref a) => {
      list_to_string(&a.borrow().v)
    }
    _ => panic!()
  }
}

fn operator_plus(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-1] = Object::Int(x+y);
          return sp;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_minus(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-1] = Object::Int(x-y);
          return sp;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_list(sp: usize, stack: &mut Vec<Object>, size: usize) -> usize{
  let mut sp = sp;
  let mut v: Vec<Object> = Vec::new();
  for i in 0..size {
    v.push(replace(&mut stack[sp-size+i],Object::Null));
  }
  sp-=size;
  stack[sp] = List::new_object(v);
  sp+=1;
  return sp;
}

fn compose_i32(b1: u8, b2: u8, b3: u8, b4: u8) -> i32{
  return (b4 as i32)<<24 | (b3 as i32)<<16 | (b2 as i32)<<8 | (b1 as i32);
}

pub fn eval(a: &[u8]){
  let mut ip=0;
  let mut stack: Vec<Object> = Vec::new();
  for _ in 0..100 {
    stack.push(Object::Null);
  }
  let mut sp=0;
  loop{
    match a[ip] {
      bc::INT => {
        ip+=BCSIZEP4;
        stack[sp] = Object::Int(compose_i32(a[ip-4],a[ip-3],a[ip-2],a[ip-1]));
        sp+=1;
      },
      bc::ADD => {
        sp = operator_plus(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::SUB => {
        sp = operator_minus(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::LIST => {
        ip+=BCSIZEP4;
        let size = compose_i32(a[ip-4],a[ip-3],a[ip-2],a[ip-1]) as usize;
        sp = operator_list(sp,&mut stack,size);
      },
      bc::HALT => {
        break;
      },
      _ => {panic!()}
    }
  }
  if sp>0 {
    println!("{}",object_to_string(&stack[sp-1]));
  }
}
<commit_msg>update<commit_after>
use std::rc::Rc;
use std::cell::RefCell;
use std::mem::replace;

pub const BCSIZE: usize = 4;
pub const BCSIZEP4: usize = BCSIZE+4;

pub mod bc{
  pub const HALT: u8 = 0;
  pub const INT:  u8 = 1;
  pub const NEG:  u8 = 2;
  pub const ADD:  u8 = 3;
  pub const SUB:  u8 = 4;
  pub const MPY:  u8 = 5;
  pub const DIV:  u8 = 6;
  pub const IDIV: u8 = 7;
  pub const LIST: u8 = 8;
}

pub struct List{
  v: Vec<Object>
}

impl List{
  pub fn new_object(v: Vec<Object>) -> Object{
    return Object::List(Rc::new(RefCell::new(List{v: v})));
  }
}

pub enum Object{
  Null, Bool(bool), Int(i32), Float(f64),
  List(Rc<RefCell<List>>)
}

fn list_to_string(a: &[Object]) -> String{
  let mut s = String::from("[");
  for i in 0..a.len() {
    if i!=0 {s.push_str(", ");}
    s.push_str(&object_to_string(&a[i]));
  }
  s.push_str("]");
  return s;
}

fn object_to_string(x: &Object) -> String{
  match x {
    &Object::Null => String::from("null"),
    &Object::Bool(b) => String::from(if b {"true"} else {"false"}),
    &Object::Int(i) => format!("{}",i),
    &Object::Float(f) => format!("{}",f),
    &Object::List(ref a) => {
      list_to_string(&a.borrow().v)
    }
  }
}

fn operator_plus(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-2] = Object::Int(x+y);
          return sp-1;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_minus(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-2] = Object::Int(x-y);
          return sp-1;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_mpy(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-2] = Object::Int(x*y);
          return sp-1;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_div(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-2] = Object::Float((x as f64)/(y as f64));
          return sp-1;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_idiv(sp: usize, stack: &mut Vec<Object>) -> usize{
  match stack[sp-2] {
    Object::Int(x) => {
      match stack[sp-1] {
        Object::Int(y) => {
          stack[sp-2] = Object::Int(x/y);
          return sp-1;
        },
        _ => panic!()
      }
    },
    _ => panic!()
  }
}

fn operator_list(sp: usize, stack: &mut Vec<Object>, size: usize) -> usize{
  let mut sp = sp;
  let mut v: Vec<Object> = Vec::new();
  for i in 0..size {
    v.push(replace(&mut stack[sp-size+i],Object::Null));
  }
  sp-=size;
  stack[sp] = List::new_object(v);
  sp+=1;
  return sp;
}

fn compose_i32(b1: u8, b2: u8, b3: u8, b4: u8) -> i32{
  return (b4 as i32)<<24 | (b3 as i32)<<16 | (b2 as i32)<<8 | (b1 as i32);
}

pub fn eval(a: &[u8]){
  let mut ip=0;
  let mut stack: Vec<Object> = Vec::new();
  for _ in 0..100 {
    stack.push(Object::Null);
  }
  let mut sp=0;
  loop{
    match a[ip] {
      bc::INT => {
        ip+=BCSIZEP4;
        stack[sp] = Object::Int(compose_i32(a[ip-4],a[ip-3],a[ip-2],a[ip-1]));
        sp+=1;
      },
      bc::ADD => {
        sp = operator_plus(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::SUB => {
        sp = operator_minus(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::MPY => {
        sp = operator_mpy(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::DIV => {
        sp = operator_div(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::IDIV => {
        sp = operator_idiv(sp, &mut stack);
        ip+=BCSIZE;
      },
      bc::LIST => {
        ip+=BCSIZEP4;
        let size = compose_i32(a[ip-4],a[ip-3],a[ip-2],a[ip-1]) as usize;
        sp = operator_list(sp,&mut stack,size);
      },
      bc::HALT => {
        break;
      },
      _ => {panic!()}
    }
  }
  if sp>0 {
    println!("{}",object_to_string(&stack[sp-1]));
  }
}
<|endoftext|>


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

extern crate burst;

use std::fmt;
use super::address::Address;
use super::instruction::Instruction;

/// A representation of a Burst instruction.
#[derive(Debug)]
pub struct BurstInstruction {
    insn: burst::x86::Instruction,
}

impl Instruction for BurstInstruction {
    fn address(&self) -> Address {
        unimplemented!();
    }

    fn comment(&self) -> Option<String> {
        None
    }

    fn mnemonic(&self) -> &str {
        self.insn.operation.mnemonic()
    }

    fn cycle_count(&self) -> Option<u32> {
        None
    }

    fn is_call(&self) -> bool {
        use self::burst::x86::InstructionOperation::*;

        match self.insn.operation {
            CALL | CALLF => true,
            _ => false,
        }
    }

    fn is_local_conditional_jump(&self) -> bool {
        use self::burst::x86::InstructionOperation::*;

        match self.insn.operation {
            JCXZ | JECXZ | JO | JNO | JB | JAE | JE | JNE | JBE | JA | JS | JNS | JPE | JPO |
            JL | JGE | JLE | JG | LOOP | LOOPE | LOOPNE => true,
            _ => false,
        }
    }

    fn is_local_jump(&self) -> bool {
        use self::burst::x86::InstructionOperation::*;

        self.is_local_conditional_jump() ||
            match self.insn.operation {
                JMPF | JMP => true,
                _ => false,
            }
    }

    fn is_return(&self) -> bool {
        use self::burst::x86::InstructionOperation::*;

        match self.insn.operation {
            RETF | RETN => true,
            _ => false,
        }
    }

    fn target_address(&self) -> Option<Address> {
        let first_operand = &self.insn.operands[0];
        if first_operand.operand == burst::x86::OperandType::IMM {
            Some(Address::new(first_operand.immediate as u64))
        } else {
            None
        }
    }
}

impl fmt::Display for BurstInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let data: [u8; 0] = [];
        let mut out = String::new();
        try!(burst::x86::format_instruction_string(
            &mut out,
            "%i %o",
            &data,
            0,
            &self.insn,
        ));
        out.fmt(f)
    }
}

#[cfg(test)]
mod tests {
    use super::burst;
    use super::BurstInstruction;
    use super::super::{Address, Function, Symbol};

    #[test]
    fn test() {
        let code = &[0x55, 0x48, 0x8b, 0x05, 0xb8, 0x13, 0x00, 0x00];

        let buf = burst::x86::disassemble_64(code, 0, 0);
        let is = buf.iter()
            .map(|insn| BurstInstruction { insn })
            .collect::<Vec<_>>();
        let f = Function::new(Symbol::new(Address::new(100000), Some("test")), is);

        assert!(f.control_flow_graph.entry_block.is_some());
    }
}
<commit_msg>Add working Burst test for now.<commit_after>// 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.

extern crate burst;

use std::fmt;
use super::address::Address;
use super::instruction::Instruction;

/// A representation of a Burst instruction.
#[derive(Debug)]
pub struct BurstInstruction {
    insn: burst::x86::Instruction,
}

impl Instruction for BurstInstruction {
    fn address(&self) -> Address {
        unimplemented!();
    }

    fn comment(&self) -> Option<String> {
        None
    }

    fn mnemonic(&self) -> &str {
        self.insn.operation.mnemonic()
    }

    fn cycle_count(&self) -> Option<u32> {
        None
    }

    fn is_call(&self) -> bool {
        use self::burst::x86::InstructionOperation::*;

        match self.insn.operation {
            CALL | CALLF => true,
            _ => false,
        }
    }

    fn is_local_conditional_jump(&self) -> bool {
        use self::burst::x86::InstructionOperation::*;

        match self.insn.operation {
            JCXZ | JECXZ | JO | JNO | JB | JAE | JE | JNE | JBE | JA | JS | JNS | JPE | JPO |
            JL | JGE | JLE | JG | LOOP | LOOPE | LOOPNE => true,
            _ => false,
        }
    }

    fn is_local_jump(&self) -> bool {
        use self::burst::x86::InstructionOperation::*;

        self.is_local_conditional_jump() ||
            match self.insn.operation {
                JMPF | JMP => true,
                _ => false,
            }
    }

    fn is_return(&self) -> bool {
        use self::burst::x86::InstructionOperation::*;

        match self.insn.operation {
            RETF | RETN => true,
            _ => false,
        }
    }

    fn target_address(&self) -> Option<Address> {
        let first_operand = &self.insn.operands[0];
        if first_operand.operand == burst::x86::OperandType::IMM {
            Some(Address::new(first_operand.immediate as u64))
        } else {
            None
        }
    }
}

impl fmt::Display for BurstInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let data: [u8; 0] = [];
        let mut out = String::new();
        try!(burst::x86::format_instruction_string(
            &mut out,
            "%i %o",
            &data,
            0,
            &self.insn,
        ));
        out.fmt(f)
    }
}

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

    #[test]
    fn test() {
        let code = &[0x55, 0x48, 0x8b, 0x05, 0xb8, 0x13, 0x00, 0x00];

        if let Ok(insn) = burst::x86::disassemble_64(code, 0, code.len()) {
            let bi = BurstInstruction { insn };
            assert_eq!("push rbp", format!("{}", bi));
        }
    }
}
<|endoftext|>


<commit_before>//! This module represents a basic, rule-agnostic 32-cards system.

use ::rand::{
    thread_rng,
    Rng,
    IsaacRng,
    SeedableRng
};
use std::num::Wrapping;
use std::string::ToString;
use rustc_serialize;

/// One of the four Suits: Heart, Spade, Diamond, Club
#[derive(PartialEq,Clone,Copy)]
pub struct Suit(u32);

// TODO: Make these associated const when it's stable

/// The Heart suit
pub const HEART: Suit = Suit(1 << 0);
/// The Spade suit
pub const SPADE: Suit = Suit(1 << 8);
/// The Diamond suit
pub const DIAMOND: Suit = Suit(1 << 16);
/// The Club suit
pub const CLUB: Suit = Suit(1 << 24);

impl rustc_serialize::Encodable for Suit {
    fn encode<S: rustc_serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        match *self {
            HEART | SPADE | DIAMOND | CLUB => self.0.encode(s),
            _ => "??".encode(s),
        }
    }
}

impl Suit {
    /// Returns the suit corresponding to the number:
    ///
    /// * `0`: Heart
    /// * `1`: Spade
    /// * `2`: Diamond
    /// * `3`: Club
    /// * `>=4`: panics
    pub fn from_n(n: u32) -> Self {
        if n >= 4 { panic!("Bad suit number"); }
        Suit(1 << 8*n)
    }

    /// Returns a UTF-8 character representing the suit.
    pub fn to_string(self) -> String {
        match self {
            HEART => "♥",
            SPADE => "♠",
            DIAMOND => "♦",
            CLUB => "♣",
            _ => "?",
        }.to_string()
    }
}

/// Rank of a card in a suit
#[derive(PartialEq,Clone,Copy)]
pub struct Rank(u32);
/// 7
pub const RANK_7: Rank = Rank(1 << 0);
/// 8
pub const RANK_8: Rank = Rank(1 << 1);
/// 9
pub const RANK_9: Rank = Rank(1 << 2);
/// Jack
pub const RANK_J: Rank = Rank(1 << 3);
/// Queen
pub const RANK_Q: Rank = Rank(1 << 4);
/// King
pub const RANK_K: Rank = Rank(1 << 5);
/// 10
pub const RANK_X: Rank = Rank(1 << 6);
/// Ace
pub const RANK_A: Rank = Rank(1 << 7);
/// Bit mask over all ranks
pub const RANK_MASK: Rank = Rank(255);

impl Rank {

    /// Returns the rank corresponding to the given number:
    ///
    /// * `0`: 7
    /// * `1`: 8
    /// * `2`: 9
    /// * `3`: J
    /// * `4`: Q
    /// * `5`: K
    /// * `6`: X
    /// * `7`: A
    /// * `>=8`: panics
    pub fn from_n(n: u32) -> Self {
        if n >= 8 { panic!("Invalid rank number: {}", n); }
        Rank(1 << n)
    }

    /// Returns a character representing the given rank
    pub fn to_string(self) -> String {
        match self {
            RANK_7 => "7",
            RANK_8 => "8",
            RANK_9 => "9",
            RANK_J => "J",
            RANK_Q => "Q",
            RANK_K => "K",
            RANK_X => "X",
            RANK_A => "A",
            _ => "?",
        }.to_string()
    }
}

/// Represents a single card
#[derive(PartialEq,Clone,Copy,Debug)]
pub struct Card(u32);

// TODO: Add card constants? (8 of heart, Queen of spades, ...?)

impl rustc_serialize::Encodable for Card {
    fn encode<S: rustc_serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.0.encode(s)
    }
}

impl Card {
    /// Returns the card number (from 0 to 31)
    pub fn id(self) -> u32 {
        let mut i = 0;
        let Card(mut v) = self;
        while v != 0 {
            i+=1;
            v = v>>1;
        }

        i-1
    }

    /// Returns an invalid card
    pub fn null() -> Self {
        Card(0)
    }

    /// Returns the card corresponding to the given number
    pub fn from_id(id: u32) -> Self {
        if id > 31 { panic!("invalid card id"); }
        Card(1 << id)
    }

    /// Returns the card's rank
    pub fn rank(self) -> Rank {
        let Card(mut v) = self;
        let mut r: u32 = 0;
        let Rank(mask) = RANK_MASK;

        r |= mask & v;
        v = v >> 8;
        r |= mask & v;
        v = v >> 8;
        r |= mask & v;
        v = v >> 8;
        r |= v;

        Rank(r)
    }

    /// Returns the card's suit
    pub fn suit(self) -> Suit {
        let Card(v) = self;
        let Rank(r) = self.rank();
        Suit(v / r)
    }

    /// Returns a string representation of the card
    pub fn to_string(self) -> String {
        let r = self.rank();
        let s = self.suit();
        r.to_string() + &s.to_string()
    }

    /// Creates a card from the given suit and rank
    pub fn new(suit: Suit, rank: Rank) -> Self {
        let Suit(s) = suit;
        let Rank(r) = rank;

        Card(s * r)
    }
}

/// Represents an unordered set of cards
#[derive(PartialEq,Clone,Copy)]
pub struct Hand(u32);

impl rustc_serialize::Encodable for Hand {
    fn encode<S: rustc_serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.0.encode(s)
    }
}

impl Hand {
    /// Returns an empty hand.
    pub fn new() -> Self {
        Hand(0)
    }

    /// Add `card` to `self`.
    ///
    /// No effect if `self` already contains `card`.
    pub fn add(&mut self, card: Card) -> &mut Hand {
        self.0 |= card.0;
        self
    }

    /// Removes `card` from `self`.
    ///
    /// No effect if `self` does not contains `card`.
    pub fn remove(&mut self, card: Card) {
        self.0 &= !card.0;
    }

    /// Remove all cards from `self`.
    pub fn clean(&mut self) {
        *self = Hand::new();
    }

    /// Returns `true` if `self` contains `card`.
    pub fn has(self, card: Card) -> bool {
        (self.0 & card.0) != 0
    }

    /// Returns `true` if the hand contains any card of the given suit.
    pub fn has_any(self, suit: Suit) -> bool {
        (self.0 & (RANK_MASK.0 * suit.0)) != 0
    }

    /// Returns `true` if `self` contains no card.
    pub fn is_empty(self) -> bool {
        self.0 == 0
    }

    /// Returns a card from `self`.
    ///
    /// Returns an invalid card if `self` is empty.
    pub fn get_card(self) -> Card {
        if self.is_empty() {
            return Card(0);
        }

        let Hand(h) = self;
        // Finds the rightmost bit, shifted to the left by 1.
        // let n = 1 << (h.trailing_zeroes());
        let n = Wrapping(h ^ (h - 1)) + Wrapping(1);
        if n.0 == 0 {
            // We got an overflow. This means the desired bit it the leftmost one.
            Card::from_id(31)
        } else {
            // We just need to shift it back.
            Card(n.0 >> 1)
        }
    }

    /// Returns the cards contained in `self` as a `Vec`.
    pub fn list(self) -> Vec<Card> {
        let mut cards = Vec::new();
        let mut h = self;

        while !h.is_empty() {
            let c = h.get_card();
            h.remove(c);
            cards.push(c);
        }

        cards
    }

    /// Returns the number of cards in `self`.
    pub fn size(self) -> usize {
        self.list().len()
    }
}

impl ToString for Hand {
    /// Returns a string representation of `self`.
    fn to_string(&self) -> String {
        let mut s = "[".to_string();

        for c in (*self).list().iter() {
            s = s + &c.to_string();
            s = s +",";
        }

        s + "]"
    }
}

/// A deck of cards.
pub struct Deck{
    cards: Vec<Card>,
}

impl Deck {
    /// Returns a full, sorted deck of 32 cards.
    pub fn new() -> Self {
        let mut d = Deck{cards:Vec::with_capacity(32)};

        for i in 0..32 {
            d.cards.push(Card::from_id(i));
        }

        d
    }

    /// Shuffle this deck.
    pub fn shuffle(&mut self) {
        self.shuffle_from(thread_rng());
    }

    /// Shuffle this deck with the given random seed.
    ///
    /// Result is determined by the seed.
    pub fn shuffle_seeded(&mut self, seed: &[u32]) {
        let mut rng = IsaacRng::new_unseeded();
        rng.reseed(seed);
        self.shuffle_from(rng);
    }

    fn shuffle_from<RNG: Rng>(&mut self, mut rng: RNG) {
        rng.shuffle(&mut self.cards[..]);
    }

    /// Draw the top card from the deck.
    ///
    /// # Panics
    /// If `self` is empty.
    pub fn draw(&mut self) -> Card {
        self.cards.pop().expect("deck is empty")
    }

    /// Returns `true` if this deck is empty.
    pub fn is_empty(&self) -> bool {
        self.cards.is_empty()
    }

    /// Returns the number of cards left in this deck.
    pub fn len(&self) -> usize {
        self.cards.len()
    }

    /// Deal `n` cards to each hand.
    ///
    /// # Panics
    /// If `self.len() < 4 * n`
    pub fn deal_each(&mut self, hands: &mut [Hand; 4], n: usize) {
        if self.len() < 4*n {
            panic!("Deck has too few cards!");
        }

        for hand in hands.iter_mut() {
            for _ in 0..n {
                hand.add(self.draw());
            }
        }
    }
}

impl ToString for Deck {
    fn to_string(&self) -> String {
        let mut s = "[".to_string();

        for c in self.cards.iter() {
            s = s + &c.to_string();
            s = s +",";
        }

        s + "]"
    }
}

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

    #[test]
    fn test_cards() {
        for i in 0..32 {
            let card = Card::from_id(i);
            assert!(i == card.id());
        }

        for s in 0..4 {
            let suit = Suit::from_n(s);
            for r in 0..8 {
                let rank = Rank::from_n(r);
                let card = Card::new(suit, rank);
                assert!(card.rank() == rank);
                assert!(card.suit() == suit);
            }
        }
    }

    #[test]
    fn test_hand() {
        let mut hand = Hand::new();

        let cards: Vec<Card> = vec![
            Card::new(HEART, RANK_7),
            Card::new(HEART, RANK_8),
            Card::new(SPADE, RANK_9),
            Card::new(SPADE, RANK_J),
            Card::new(CLUB, RANK_Q),
            Card::new(CLUB, RANK_K),
            Card::new(DIAMOND, RANK_X),
            Card::new(DIAMOND, RANK_A),
        ];

        assert!(hand.is_empty());

        for card in cards.iter() {
            assert!(!hand.has(*card));
            hand.add(*card);
            assert!(hand.has(*card));
        }

        assert!(hand.size() == cards.len());

        for card in cards.iter() {
            assert!(hand.has(*card));
            hand.remove(*card);
            assert!(!hand.has(*card));
        }
    }

    #[test]
    fn test_deck() {
        let mut deck = Deck::new();
        deck.shuffle();

        assert!(deck.len() == 32);

        let mut count = [0; 32];
        while !deck.is_empty() {
            let card = deck.draw();
            count[card.id() as usize] += 1;
        }

        for c in count.iter() {
            assert!(*c == 1);
        }
    }
}

#[cfg(feature="use_bench")]
mod benchs {
    use ::test::Bencher;
    use ::deal_seeded_hands;

    #[bench]
    fn bench_deal(b: &mut Bencher) {
        let seed = &[1,2,3,4,5];
        b.iter(|| {
            deal_seeded_hands(seed);
        });
    }

    #[bench]
    fn bench_add(b: &mut Bencher) {
        let seed = &[1,2,3,4,5];
        let hands = deal_seeded_hands(seed);
        b.iter(|| {
            let mut hands = hands.clone();
            for hand in hands.iter_mut() {
                for c in hand.list() {
                    hand.remove(c);
                }
            }
        });
    }
}
<commit_msg>Update doc<commit_after>//! This module represents a basic, rule-agnostic 32-cards system.

use ::rand::{
    thread_rng,
    Rng,
    IsaacRng,
    SeedableRng
};
use std::num::Wrapping;
use std::string::ToString;
use rustc_serialize;

/// One of the four Suits: Heart, Spade, Diamond, Club
#[derive(PartialEq,Clone,Copy)]
pub struct Suit(u32);

// TODO: Make these associated const when it's stable

/// The Heart suit
pub const HEART: Suit = Suit(1 << 0);
/// The Spade suit
pub const SPADE: Suit = Suit(1 << 8);
/// The Diamond suit
pub const DIAMOND: Suit = Suit(1 << 16);
/// The Club suit
pub const CLUB: Suit = Suit(1 << 24);

impl rustc_serialize::Encodable for Suit {
    fn encode<S: rustc_serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        match *self {
            HEART | SPADE | DIAMOND | CLUB => self.0.encode(s),
            _ => "??".encode(s),
        }
    }
}

impl Suit {
    /// Returns the suit corresponding to the number:
    ///
    /// * `0`: Heart
    /// * `1`: Spade
    /// * `2`: Diamond
    /// * `3`: Club
    /// * `>=4`: panics
    pub fn from_n(n: u32) -> Self {
        if n >= 4 { panic!("Bad suit number"); }
        Suit(1 << 8*n)
    }

    /// Returns a UTF-8 character representing the suit.
    pub fn to_string(self) -> String {
        match self {
            HEART => "♥",
            SPADE => "♠",
            DIAMOND => "♦",
            CLUB => "♣",
            _ => "?",
        }.to_string()
    }
}

/// Rank of a card in a suit
#[derive(PartialEq,Clone,Copy)]
pub struct Rank(u32);
/// 7
pub const RANK_7: Rank = Rank(1 << 0);
/// 8
pub const RANK_8: Rank = Rank(1 << 1);
/// 9
pub const RANK_9: Rank = Rank(1 << 2);
/// Jack
pub const RANK_J: Rank = Rank(1 << 3);
/// Queen
pub const RANK_Q: Rank = Rank(1 << 4);
/// King
pub const RANK_K: Rank = Rank(1 << 5);
/// 10
pub const RANK_X: Rank = Rank(1 << 6);
/// Ace
pub const RANK_A: Rank = Rank(1 << 7);
/// Bit mask over all ranks
pub const RANK_MASK: Rank = Rank(255);

impl Rank {

    /// Returns the rank corresponding to the given number:
    ///
    /// * `0`: 7
    /// * `1`: 8
    /// * `2`: 9
    /// * `3`: Jack
    /// * `4`: Queen
    /// * `5`: King
    /// * `6`: 10
    /// * `7`: Ace
    /// * `>=8`: panics
    pub fn from_n(n: u32) -> Self {
        if n >= 8 { panic!("Invalid rank number: {}", n); }
        Rank(1 << n)
    }

    /// Returns a character representing the given rank
    pub fn to_string(self) -> String {
        match self {
            RANK_7 => "7",
            RANK_8 => "8",
            RANK_9 => "9",
            RANK_J => "J",
            RANK_Q => "Q",
            RANK_K => "K",
            RANK_X => "X",
            RANK_A => "A",
            _ => "?",
        }.to_string()
    }
}

/// Represents a single card
#[derive(PartialEq,Clone,Copy,Debug)]
pub struct Card(u32);

// TODO: Add card constants? (8 of heart, Queen of spades, ...?)

impl rustc_serialize::Encodable for Card {
    fn encode<S: rustc_serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.0.encode(s)
    }
}

impl Card {
    /// Returns the card number (from 0 to 31)
    pub fn id(self) -> u32 {
        let mut i = 0;
        let Card(mut v) = self;
        while v != 0 {
            i+=1;
            v = v>>1;
        }

        i-1
    }

    /// Returns an invalid card
    pub fn null() -> Self {
        Card(0)
    }

    /// Returns the card corresponding to the given number
    pub fn from_id(id: u32) -> Self {
        if id > 31 { panic!("invalid card id"); }
        Card(1 << id)
    }

    /// Returns the card's rank
    pub fn rank(self) -> Rank {
        let Card(mut v) = self;
        let mut r: u32 = 0;
        let Rank(mask) = RANK_MASK;

        r |= mask & v;
        v = v >> 8;
        r |= mask & v;
        v = v >> 8;
        r |= mask & v;
        v = v >> 8;
        r |= v;

        Rank(r)
    }

    /// Returns the card's suit
    pub fn suit(self) -> Suit {
        let Card(v) = self;
        let Rank(r) = self.rank();
        Suit(v / r)
    }

    /// Returns a string representation of the card
    pub fn to_string(self) -> String {
        let r = self.rank();
        let s = self.suit();
        r.to_string() + &s.to_string()
    }

    /// Creates a card from the given suit and rank
    pub fn new(suit: Suit, rank: Rank) -> Self {
        let Suit(s) = suit;
        let Rank(r) = rank;

        Card(s * r)
    }
}

/// Represents an unordered set of cards
#[derive(PartialEq,Clone,Copy)]
pub struct Hand(u32);

impl rustc_serialize::Encodable for Hand {
    fn encode<S: rustc_serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.0.encode(s)
    }
}

impl Hand {
    /// Returns an empty hand.
    pub fn new() -> Self {
        Hand(0)
    }

    /// Add `card` to `self`.
    ///
    /// No effect if `self` already contains `card`.
    pub fn add(&mut self, card: Card) -> &mut Hand {
        self.0 |= card.0;
        self
    }

    /// Removes `card` from `self`.
    ///
    /// No effect if `self` does not contains `card`.
    pub fn remove(&mut self, card: Card) {
        self.0 &= !card.0;
    }

    /// Remove all cards from `self`.
    pub fn clean(&mut self) {
        *self = Hand::new();
    }

    /// Returns `true` if `self` contains `card`.
    pub fn has(self, card: Card) -> bool {
        (self.0 & card.0) != 0
    }

    /// Returns `true` if the hand contains any card of the given suit.
    pub fn has_any(self, suit: Suit) -> bool {
        (self.0 & (RANK_MASK.0 * suit.0)) != 0
    }

    /// Returns `true` if `self` contains no card.
    pub fn is_empty(self) -> bool {
        self.0 == 0
    }

    /// Returns a card from `self`.
    ///
    /// Returns an invalid card if `self` is empty.
    pub fn get_card(self) -> Card {
        if self.is_empty() {
            return Card(0);
        }

        let Hand(h) = self;
        // Finds the rightmost bit, shifted to the left by 1.
        // let n = 1 << (h.trailing_zeroes());
        let n = Wrapping(h ^ (h - 1)) + Wrapping(1);
        if n.0 == 0 {
            // We got an overflow. This means the desired bit it the leftmost one.
            Card::from_id(31)
        } else {
            // We just need to shift it back.
            Card(n.0 >> 1)
        }
    }

    /// Returns the cards contained in `self` as a `Vec`.
    pub fn list(self) -> Vec<Card> {
        let mut cards = Vec::new();
        let mut h = self;

        while !h.is_empty() {
            let c = h.get_card();
            h.remove(c);
            cards.push(c);
        }

        cards
    }

    /// Returns the number of cards in `self`.
    pub fn size(self) -> usize {
        self.list().len()
    }
}

impl ToString for Hand {
    /// Returns a string representation of `self`.
    fn to_string(&self) -> String {
        let mut s = "[".to_string();

        for c in (*self).list().iter() {
            s = s + &c.to_string();
            s = s +",";
        }

        s + "]"
    }
}

/// A deck of cards.
pub struct Deck{
    cards: Vec<Card>,
}

impl Deck {
    /// Returns a full, sorted deck of 32 cards.
    pub fn new() -> Self {
        let mut d = Deck{cards:Vec::with_capacity(32)};

        for i in 0..32 {
            d.cards.push(Card::from_id(i));
        }

        d
    }

    /// Shuffle this deck.
    pub fn shuffle(&mut self) {
        self.shuffle_from(thread_rng());
    }

    /// Shuffle this deck with the given random seed.
    ///
    /// Result is determined by the seed.
    pub fn shuffle_seeded(&mut self, seed: &[u32]) {
        let mut rng = IsaacRng::new_unseeded();
        rng.reseed(seed);
        self.shuffle_from(rng);
    }

    fn shuffle_from<RNG: Rng>(&mut self, mut rng: RNG) {
        rng.shuffle(&mut self.cards[..]);
    }

    /// Draw the top card from the deck.
    ///
    /// # Panics
    /// If `self` is empty.
    pub fn draw(&mut self) -> Card {
        self.cards.pop().expect("deck is empty")
    }

    /// Returns `true` if this deck is empty.
    pub fn is_empty(&self) -> bool {
        self.cards.is_empty()
    }

    /// Returns the number of cards left in this deck.
    pub fn len(&self) -> usize {
        self.cards.len()
    }

    /// Deal `n` cards to each hand.
    ///
    /// # Panics
    /// If `self.len() < 4 * n`
    pub fn deal_each(&mut self, hands: &mut [Hand; 4], n: usize) {
        if self.len() < 4*n {
            panic!("Deck has too few cards!");
        }

        for hand in hands.iter_mut() {
            for _ in 0..n {
                hand.add(self.draw());
            }
        }
    }
}

impl ToString for Deck {
    fn to_string(&self) -> String {
        let mut s = "[".to_string();

        for c in self.cards.iter() {
            s = s + &c.to_string();
            s = s +",";
        }

        s + "]"
    }
}

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

    #[test]
    fn test_cards() {
        for i in 0..32 {
            let card = Card::from_id(i);
            assert!(i == card.id());
        }

        for s in 0..4 {
            let suit = Suit::from_n(s);
            for r in 0..8 {
                let rank = Rank::from_n(r);
                let card = Card::new(suit, rank);
                assert!(card.rank() == rank);
                assert!(card.suit() == suit);
            }
        }
    }

    #[test]
    fn test_hand() {
        let mut hand = Hand::new();

        let cards: Vec<Card> = vec![
            Card::new(HEART, RANK_7),
            Card::new(HEART, RANK_8),
            Card::new(SPADE, RANK_9),
            Card::new(SPADE, RANK_J),
            Card::new(CLUB, RANK_Q),
            Card::new(CLUB, RANK_K),
            Card::new(DIAMOND, RANK_X),
            Card::new(DIAMOND, RANK_A),
        ];

        assert!(hand.is_empty());

        for card in cards.iter() {
            assert!(!hand.has(*card));
            hand.add(*card);
            assert!(hand.has(*card));
        }

        assert!(hand.size() == cards.len());

        for card in cards.iter() {
            assert!(hand.has(*card));
            hand.remove(*card);
            assert!(!hand.has(*card));
        }
    }

    #[test]
    fn test_deck() {
        let mut deck = Deck::new();
        deck.shuffle();

        assert!(deck.len() == 32);

        let mut count = [0; 32];
        while !deck.is_empty() {
            let card = deck.draw();
            count[card.id() as usize] += 1;
        }

        for c in count.iter() {
            assert!(*c == 1);
        }
    }
}

#[cfg(feature="use_bench")]
mod benchs {
    use ::test::Bencher;
    use ::deal_seeded_hands;

    #[bench]
    fn bench_deal(b: &mut Bencher) {
        let seed = &[1,2,3,4,5];
        b.iter(|| {
            deal_seeded_hands(seed);
        });
    }

    #[bench]
    fn bench_add(b: &mut Bencher) {
        let seed = &[1,2,3,4,5];
        let hands = deal_seeded_hands(seed);
        b.iter(|| {
            let mut hands = hands.clone();
            for hand in hands.iter_mut() {
                for c in hand.list() {
                    hand.remove(c);
                }
            }
        });
    }
}
<|endoftext|>


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

use app_units::Au;
#[cfg(target_os = "macos")]
use core_foundation::string::CFString;
#[cfg(target_os = "macos")]
use core_graphics::font::CGFont;
#[cfg(target_os = "windows")]
pub use dwrote::FontDescriptor as NativeFontHandle;
#[cfg(target_os = "macos")]
use serde::de::{self, Deserialize, Deserializer};
#[cfg(target_os = "macos")]
use serde::ser::{Serialize, Serializer};
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use {ColorU, IdNamespace, LayoutPoint};

#[cfg(not(any(target_os = "macos", target_os = "windows")))]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NativeFontHandle {
    pub pathname: String,
    pub index: u32,
}

#[cfg(target_os = "macos")]
#[derive(Clone)]
pub struct NativeFontHandle(pub CGFont);

#[cfg(target_os = "macos")]
impl Serialize for NativeFontHandle {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        self.0
            .postscript_name()
            .to_string()
            .serialize(serializer)
    }
}

#[cfg(target_os = "macos")]
impl<'de> Deserialize<'de> for NativeFontHandle {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let postscript_name: String = Deserialize::deserialize(deserializer)?;

        match CGFont::from_name(&CFString::new(&*postscript_name)) {
            Ok(font) => Ok(NativeFontHandle(font)),
            Err(_) => Err(de::Error::custom(
                "Couldn't find a font with that PostScript name!",
            )),
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone, Deserialize, Serialize, Debug)]
pub struct GlyphDimensions {
    pub left: i32,
    pub top: i32,
    pub width: u32,
    pub height: u32,
    pub advance: f32,
}

#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Ord, PartialOrd)]
pub struct FontKey(pub IdNamespace, pub u32);

impl FontKey {
    pub fn new(namespace: IdNamespace, key: u32) -> FontKey {
        FontKey(namespace, key)
    }
}

/// Container for the raw data describing a font. This might be a stream of
/// bytes corresponding to a downloaded font, or a handle to a native font from
/// the operating system.
///
/// Note that fonts need to be instantiated before being used, which involves
/// assigning size and various other options. The word 'template' here is
/// intended to distinguish this data from instance-specific data.
#[derive(Clone)]
pub enum FontTemplate {
    Raw(Arc<Vec<u8>>, u32),
    Native(NativeFontHandle),
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
pub enum FontRenderMode {
    Mono = 0,
    Alpha,
    Subpixel,
}

impl FontRenderMode {
    // Combine two font render modes such that the lesser amount of AA limits the AA of the result.
    pub fn limit_by(self, other: FontRenderMode) -> FontRenderMode {
        match (self, other) {
            (FontRenderMode::Subpixel, _) | (_, FontRenderMode::Mono) => other,
            _ => self,
        }
    }
}

#[repr(C)]
#[derive(Clone, Copy, Debug, PartialOrd, Deserialize, Serialize)]
pub struct FontVariation {
    pub tag: u32,
    pub value: f32,
}

impl Ord for FontVariation {
    fn cmp(&self, other: &FontVariation) -> Ordering {
        self.tag.cmp(&other.tag)
            .then(self.value.to_bits().cmp(&other.value.to_bits()))
    }
}

impl PartialEq for FontVariation {
    fn eq(&self, other: &FontVariation) -> bool {
        self.tag == other.tag &&
        self.value.to_bits() == other.value.to_bits()
    }
}

impl Eq for FontVariation {}

impl Hash for FontVariation {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.tag.hash(state);
        self.value.to_bits().hash(state);
    }
}

#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
pub struct GlyphOptions {
    pub render_mode: FontRenderMode,
    pub flags: FontInstanceFlags,
}

impl Default for GlyphOptions {
    fn default() -> Self {
        GlyphOptions {
            render_mode: FontRenderMode::Subpixel,
            flags: FontInstanceFlags::empty(),
        }
    }
}

bitflags! {
    #[repr(C)]
    #[derive(Deserialize, Serialize)]
    pub struct FontInstanceFlags: u32 {
        // Common flags
        const SYNTHETIC_BOLD    = 1 << 1;
        const EMBEDDED_BITMAPS  = 1 << 2;
        const SUBPIXEL_BGR      = 1 << 3;
        const TRANSPOSE         = 1 << 4;
        const FLIP_X            = 1 << 5;
        const FLIP_Y            = 1 << 6;
        const SUBPIXEL_POSITION = 1 << 7;

        // Windows flags
        const FORCE_GDI         = 1 << 16;

        // Mac flags
        const FONT_SMOOTHING    = 1 << 16;

        // FreeType flags
        const FORCE_AUTOHINT    = 1 << 16;
        const NO_AUTOHINT       = 1 << 17;
        const VERTICAL_LAYOUT   = 1 << 18;
        const LCD_VERTICAL      = 1 << 19;
    }
}

impl Default for FontInstanceFlags {
    #[cfg(target_os = "windows")]
    fn default() -> FontInstanceFlags {
        FontInstanceFlags::SUBPIXEL_POSITION
    }

    #[cfg(target_os = "macos")]
    fn default() -> FontInstanceFlags {
        FontInstanceFlags::SUBPIXEL_POSITION |
        FontInstanceFlags::FONT_SMOOTHING
    }

    #[cfg(not(any(target_os = "macos", target_os = "windows")))]
    fn default() -> FontInstanceFlags {
        FontInstanceFlags::SUBPIXEL_POSITION
    }
}

#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
pub struct SyntheticItalics {
    // Angle in degrees (-90..90) for synthetic italics in 8.8 fixed-point.
    pub angle: i16,
}

impl SyntheticItalics {
    pub const ANGLE_SCALE: f32 = 256.0;

    pub fn from_degrees(degrees: f32) -> Self {
        SyntheticItalics { angle: (degrees.max(-89.0).min(89.0) * Self::ANGLE_SCALE) as i16 }
    }

    pub fn to_degrees(&self) -> f32 {
        self.angle as f32 / Self::ANGLE_SCALE
    }

    pub fn to_radians(&self) -> f32 {
        self.to_degrees().to_radians()
    }

    pub fn to_skew(&self) -> f32 {
        self.to_radians().tan()
    }

    pub fn enabled() -> Self {
        Self::from_degrees(14.0)
    }

    pub fn disabled() -> Self {
        SyntheticItalics { angle: 0 }
    }

    pub fn is_enabled(&self) -> bool {
        self.angle != 0
    }
}

impl Default for SyntheticItalics {
    fn default() -> Self {
        SyntheticItalics::disabled()
    }
}

#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
pub struct FontInstanceOptions {
    pub render_mode: FontRenderMode,
    pub flags: FontInstanceFlags,
    /// When bg_color.a is != 0 and render_mode is FontRenderMode::Subpixel,
    /// the text will be rendered with bg_color.r/g/b as an opaque estimated
    /// background color.
    pub bg_color: ColorU,
    pub synthetic_italics: SyntheticItalics,
}

impl Default for FontInstanceOptions {
    fn default() -> FontInstanceOptions {
        FontInstanceOptions {
            render_mode: FontRenderMode::Subpixel,
            flags: Default::default(),
            bg_color: ColorU::new(0, 0, 0, 0),
            synthetic_italics: SyntheticItalics::disabled(),
        }
    }
}

#[cfg(target_os = "windows")]
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
pub struct FontInstancePlatformOptions {
    pub gamma: u16, // percent
    pub contrast: u16, // percent
}

#[cfg(target_os = "windows")]
impl Default for FontInstancePlatformOptions {
    fn default() -> FontInstancePlatformOptions {
        FontInstancePlatformOptions {
            gamma: 180, // Default DWrite gamma
            contrast: 100,
        }
    }
}

#[cfg(target_os = "macos")]
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
pub struct FontInstancePlatformOptions {
    pub unused: u32,
}

#[cfg(target_os = "macos")]
impl Default for FontInstancePlatformOptions {
    fn default() -> FontInstancePlatformOptions {
        FontInstancePlatformOptions {
            unused: 0,
        }
    }
}

#[cfg(not(any(target_os = "macos", target_os = "windows")))]
#[repr(u8)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub enum FontLCDFilter {
    None,
    Default,
    Light,
    Legacy,
}

#[cfg(not(any(target_os = "macos", target_os = "windows")))]
#[repr(u8)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub enum FontHinting {
    None,
    Mono,
    Light,
    Normal,
    LCD,
}

#[cfg(not(any(target_os = "macos", target_os = "windows")))]
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
pub struct FontInstancePlatformOptions {
    pub lcd_filter: FontLCDFilter,
    pub hinting: FontHinting,
}

#[cfg(not(any(target_os = "macos", target_os = "windows")))]
impl Default for FontInstancePlatformOptions {
    fn default() -> FontInstancePlatformOptions {
        FontInstancePlatformOptions {
            lcd_filter: FontLCDFilter::Default,
            hinting: FontHinting::LCD,
        }
    }
}

#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Ord, PartialOrd)]
pub struct FontInstanceKey(pub IdNamespace, pub u32);

impl FontInstanceKey {
    pub fn new(namespace: IdNamespace, key: u32) -> FontInstanceKey {
        FontInstanceKey(namespace, key)
    }
}

/// Data corresponding to an instantiation of a font, with size and
/// other options specified.
///
/// Note that the actual font is stored out-of-band in `FontTemplate`.
#[derive(Clone)]
pub struct FontInstanceData {
    pub font_key: FontKey,
    pub size: Au,
    pub options: Option<FontInstanceOptions>,
    pub platform_options: Option<FontInstancePlatformOptions>,
    pub variations: Vec<FontVariation>,
}

pub type GlyphIndex = u32;

#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct GlyphInstance {
    pub index: GlyphIndex,
    pub point: LayoutPoint,
}

<commit_msg>clippy: SyntheticItalics is faster to pass by value than reference.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use app_units::Au;
#[cfg(target_os = "macos")]
use core_foundation::string::CFString;
#[cfg(target_os = "macos")]
use core_graphics::font::CGFont;
#[cfg(target_os = "windows")]
pub use dwrote::FontDescriptor as NativeFontHandle;
#[cfg(target_os = "macos")]
use serde::de::{self, Deserialize, Deserializer};
#[cfg(target_os = "macos")]
use serde::ser::{Serialize, Serializer};
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use {ColorU, IdNamespace, LayoutPoint};

#[cfg(not(any(target_os = "macos", target_os = "windows")))]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NativeFontHandle {
    pub pathname: String,
    pub index: u32,
}

#[cfg(target_os = "macos")]
#[derive(Clone)]
pub struct NativeFontHandle(pub CGFont);

#[cfg(target_os = "macos")]
impl Serialize for NativeFontHandle {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        self.0
            .postscript_name()
            .to_string()
            .serialize(serializer)
    }
}

#[cfg(target_os = "macos")]
impl<'de> Deserialize<'de> for NativeFontHandle {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let postscript_name: String = Deserialize::deserialize(deserializer)?;

        match CGFont::from_name(&CFString::new(&*postscript_name)) {
            Ok(font) => Ok(NativeFontHandle(font)),
            Err(_) => Err(de::Error::custom(
                "Couldn't find a font with that PostScript name!",
            )),
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone, Deserialize, Serialize, Debug)]
pub struct GlyphDimensions {
    pub left: i32,
    pub top: i32,
    pub width: u32,
    pub height: u32,
    pub advance: f32,
}

#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Ord, PartialOrd)]
pub struct FontKey(pub IdNamespace, pub u32);

impl FontKey {
    pub fn new(namespace: IdNamespace, key: u32) -> FontKey {
        FontKey(namespace, key)
    }
}

/// Container for the raw data describing a font. This might be a stream of
/// bytes corresponding to a downloaded font, or a handle to a native font from
/// the operating system.
///
/// Note that fonts need to be instantiated before being used, which involves
/// assigning size and various other options. The word 'template' here is
/// intended to distinguish this data from instance-specific data.
#[derive(Clone)]
pub enum FontTemplate {
    Raw(Arc<Vec<u8>>, u32),
    Native(NativeFontHandle),
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
pub enum FontRenderMode {
    Mono = 0,
    Alpha,
    Subpixel,
}

impl FontRenderMode {
    // Combine two font render modes such that the lesser amount of AA limits the AA of the result.
    pub fn limit_by(self, other: FontRenderMode) -> FontRenderMode {
        match (self, other) {
            (FontRenderMode::Subpixel, _) | (_, FontRenderMode::Mono) => other,
            _ => self,
        }
    }
}

#[repr(C)]
#[derive(Clone, Copy, Debug, PartialOrd, Deserialize, Serialize)]
pub struct FontVariation {
    pub tag: u32,
    pub value: f32,
}

impl Ord for FontVariation {
    fn cmp(&self, other: &FontVariation) -> Ordering {
        self.tag.cmp(&other.tag)
            .then(self.value.to_bits().cmp(&other.value.to_bits()))
    }
}

impl PartialEq for FontVariation {
    fn eq(&self, other: &FontVariation) -> bool {
        self.tag == other.tag &&
        self.value.to_bits() == other.value.to_bits()
    }
}

impl Eq for FontVariation {}

impl Hash for FontVariation {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.tag.hash(state);
        self.value.to_bits().hash(state);
    }
}

#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
pub struct GlyphOptions {
    pub render_mode: FontRenderMode,
    pub flags: FontInstanceFlags,
}

impl Default for GlyphOptions {
    fn default() -> Self {
        GlyphOptions {
            render_mode: FontRenderMode::Subpixel,
            flags: FontInstanceFlags::empty(),
        }
    }
}

bitflags! {
    #[repr(C)]
    #[derive(Deserialize, Serialize)]
    pub struct FontInstanceFlags: u32 {
        // Common flags
        const SYNTHETIC_BOLD    = 1 << 1;
        const EMBEDDED_BITMAPS  = 1 << 2;
        const SUBPIXEL_BGR      = 1 << 3;
        const TRANSPOSE         = 1 << 4;
        const FLIP_X            = 1 << 5;
        const FLIP_Y            = 1 << 6;
        const SUBPIXEL_POSITION = 1 << 7;

        // Windows flags
        const FORCE_GDI         = 1 << 16;

        // Mac flags
        const FONT_SMOOTHING    = 1 << 16;

        // FreeType flags
        const FORCE_AUTOHINT    = 1 << 16;
        const NO_AUTOHINT       = 1 << 17;
        const VERTICAL_LAYOUT   = 1 << 18;
        const LCD_VERTICAL      = 1 << 19;
    }
}

impl Default for FontInstanceFlags {
    #[cfg(target_os = "windows")]
    fn default() -> FontInstanceFlags {
        FontInstanceFlags::SUBPIXEL_POSITION
    }

    #[cfg(target_os = "macos")]
    fn default() -> FontInstanceFlags {
        FontInstanceFlags::SUBPIXEL_POSITION |
        FontInstanceFlags::FONT_SMOOTHING
    }

    #[cfg(not(any(target_os = "macos", target_os = "windows")))]
    fn default() -> FontInstanceFlags {
        FontInstanceFlags::SUBPIXEL_POSITION
    }
}

#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
pub struct SyntheticItalics {
    // Angle in degrees (-90..90) for synthetic italics in 8.8 fixed-point.
    pub angle: i16,
}

impl SyntheticItalics {
    pub const ANGLE_SCALE: f32 = 256.0;

    pub fn from_degrees(degrees: f32) -> Self {
        SyntheticItalics { angle: (degrees.max(-89.0).min(89.0) * Self::ANGLE_SCALE) as i16 }
    }

    pub fn to_degrees(self) -> f32 {
        self.angle as f32 / Self::ANGLE_SCALE
    }

    pub fn to_radians(self) -> f32 {
        self.to_degrees().to_radians()
    }

    pub fn to_skew(self) -> f32 {
        self.to_radians().tan()
    }

    pub fn enabled() -> Self {
        Self::from_degrees(14.0)
    }

    pub fn disabled() -> Self {
        SyntheticItalics { angle: 0 }
    }

    pub fn is_enabled(self) -> bool {
        self.angle != 0
    }
}

impl Default for SyntheticItalics {
    fn default() -> Self {
        SyntheticItalics::disabled()
    }
}

#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
pub struct FontInstanceOptions {
    pub render_mode: FontRenderMode,
    pub flags: FontInstanceFlags,
    /// When bg_color.a is != 0 and render_mode is FontRenderMode::Subpixel,
    /// the text will be rendered with bg_color.r/g/b as an opaque estimated
    /// background color.
    pub bg_color: ColorU,
    pub synthetic_italics: SyntheticItalics,
}

impl Default for FontInstanceOptions {
    fn default() -> FontInstanceOptions {
        FontInstanceOptions {
            render_mode: FontRenderMode::Subpixel,
            flags: Default::default(),
            bg_color: ColorU::new(0, 0, 0, 0),
            synthetic_italics: SyntheticItalics::disabled(),
        }
    }
}

#[cfg(target_os = "windows")]
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
pub struct FontInstancePlatformOptions {
    pub gamma: u16, // percent
    pub contrast: u16, // percent
}

#[cfg(target_os = "windows")]
impl Default for FontInstancePlatformOptions {
    fn default() -> FontInstancePlatformOptions {
        FontInstancePlatformOptions {
            gamma: 180, // Default DWrite gamma
            contrast: 100,
        }
    }
}

#[cfg(target_os = "macos")]
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
pub struct FontInstancePlatformOptions {
    pub unused: u32,
}

#[cfg(target_os = "macos")]
impl Default for FontInstancePlatformOptions {
    fn default() -> FontInstancePlatformOptions {
        FontInstancePlatformOptions {
            unused: 0,
        }
    }
}

#[cfg(not(any(target_os = "macos", target_os = "windows")))]
#[repr(u8)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub enum FontLCDFilter {
    None,
    Default,
    Light,
    Legacy,
}

#[cfg(not(any(target_os = "macos", target_os = "windows")))]
#[repr(u8)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub enum FontHinting {
    None,
    Mono,
    Light,
    Normal,
    LCD,
}

#[cfg(not(any(target_os = "macos", target_os = "windows")))]
#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
pub struct FontInstancePlatformOptions {
    pub lcd_filter: FontLCDFilter,
    pub hinting: FontHinting,
}

#[cfg(not(any(target_os = "macos", target_os = "windows")))]
impl Default for FontInstancePlatformOptions {
    fn default() -> FontInstancePlatformOptions {
        FontInstancePlatformOptions {
            lcd_filter: FontLCDFilter::Default,
            hinting: FontHinting::LCD,
        }
    }
}

#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Ord, PartialOrd)]
pub struct FontInstanceKey(pub IdNamespace, pub u32);

impl FontInstanceKey {
    pub fn new(namespace: IdNamespace, key: u32) -> FontInstanceKey {
        FontInstanceKey(namespace, key)
    }
}

/// Data corresponding to an instantiation of a font, with size and
/// other options specified.
///
/// Note that the actual font is stored out-of-band in `FontTemplate`.
#[derive(Clone)]
pub struct FontInstanceData {
    pub font_key: FontKey,
    pub size: Au,
    pub options: Option<FontInstanceOptions>,
    pub platform_options: Option<FontInstancePlatformOptions>,
    pub variations: Vec<FontVariation>,
}

pub type GlyphIndex = u32;

#[repr(C)]
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct GlyphInstance {
    pub index: GlyphIndex,
    pub point: LayoutPoint,
}

<|endoftext|>


<commit_before>use base64;
use crypto_mac::Mac;
use digest::generic_array::ArrayLength;
use digest::*;
use hmac::Hmac;

pub fn sign<D>(data: &str, key: &[u8], _digest: D) -> String
where
    D: Input + BlockInput + FixedOutput + Reset + Default + Clone,
    D::BlockSize: ArrayLength<u8>,
    D::OutputSize: ArrayLength<u8>,
{
    // This will panic for bad key sizes. Returning an error
    // would probably be better, but for now, I want to keep the
    // API as stable as possible
    let mut hmac = Hmac::<D>::new_varkey(key).unwrap();
    hmac.input(data.as_bytes());

    let mac = hmac.result();
    let code = mac.code();
    base64::encode_config(&code, base64::URL_SAFE_NO_PAD)
}

pub fn verify<D>(target: &str, data: &str, key: &[u8], _digest: D) -> bool
where
    D: Input + BlockInput + FixedOutput + Reset + Default + Clone,
    D::BlockSize: ArrayLength<u8>,
    D::OutputSize: ArrayLength<u8>,
{
    let target_bytes = match base64::decode_config(target, base64::URL_SAFE_NO_PAD) {
        Ok(x) => x,
        Err(_) => return false,
    };

    // This will panic for bad key sizes. Returning an error
    // would probably be better, but for now, I want to keep the
    // API as stable as possible
    let mut hmac = Hmac::<D>::new_varkey(key).unwrap();
    hmac.input(data.as_bytes());
    hmac.verify(&target_bytes).is_ok()
}
<commit_msg>Replace crypt implementations<commit_after>use crate::algorithm::rust_crypto::TypeLevelAlgorithmType;
use crate::algorithm::{SigningAlgorithm, VerifyingAlgorithm};
use crate::SEPARATOR;
use crypto_mac::Mac;
use digest::generic_array::ArrayLength;
use digest::*;
use hmac::Hmac;

#[deprecated(
    note = "Please use Hmac type with the SigningAlgorithm trait directly. See the source of this function for an example."
)]
pub fn sign<D>(data: &str, key: &[u8], _digest: D) -> String
where
    D: Input + BlockInput + FixedOutput + Reset + Default + Clone + TypeLevelAlgorithmType,
    D::BlockSize: ArrayLength<u8>,
    D::OutputSize: ArrayLength<u8>,
{
    // This will panic for bad key sizes. Returning an error
    // would probably be better, but for now, I want to keep the
    // API as stable as possible
    let hmac = Hmac::<D>::new_varkey(key).unwrap();
    let mut components = data.split(SEPARATOR);
    let header = components.next().unwrap();
    let claims = components.next().unwrap();
    SigningAlgorithm::sign(&hmac, header, claims).unwrap()
}

#[deprecated(
    note = "Please use Hmac type with the VerifyingAlgorithm trait directly. See the source of this function for an example."
)]
pub fn verify<D>(signature: &str, data: &str, key: &[u8], _digest: D) -> bool
where
    D: Input + BlockInput + FixedOutput + Reset + Default + Clone + TypeLevelAlgorithmType,
    D::BlockSize: ArrayLength<u8>,
    D::OutputSize: ArrayLength<u8>,
{
    // This will panic for bad key sizes. Returning an error
    // would probably be better, but for now, I want to keep the
    // API as stable as possible
    let hmac = Hmac::<D>::new_varkey(key).unwrap();

    let mut components = data.split(SEPARATOR);
    let header = components.next().unwrap();
    let claims = components.next().unwrap();

    VerifyingAlgorithm::verify(&hmac, &header, &claims, &signature).unwrap_or(false)
}
<|endoftext|>


<commit_before>extern crate tau;

use std::num::FloatMath;

fn main() {
    println!("24 days of Rust - tau (day 9)");
    println!("τ = {}", tau::TAU);
    println!("cos(τ) = {}", tau::TAU.cos());
}
<commit_msg>Math, math is good<commit_after>extern crate num;
extern crate tau;

use std::num::FloatMath;
use num::complex::{Complex, Complex64};

fn main() {
    println!("24 days of Rust - tau (day 9)");
    println!("τ = {}", tau::TAU);
    let radius: f64 = 15.0;
    println!("circle circumference = τ * r = {}", tau::TAU * radius);
    let c: Complex64 = Complex::from_polar(&1.0, &tau::TAU);
    println!("Euler's identity: exp(i * τ) = {}", c);
    println!("Trigonometry: sin(τ) = {}, cos(τ) = {}", tau::TAU.sin(), tau::TAU.cos());
    println!("That other constant = {}", tau::TAU / 2.0);
}
<|endoftext|>