<commit_before>// Copyright 2016 Serde YAML Developers
//
// 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.

//! YAML Deserialization
//!
//! This module provides YAML deserialization with the type `Deserializer`.

use std::collections::BTreeMap;
use std::io;
use std::str;

use yaml_rust::parser::{Parser, MarkedEventReceiver, Event as YamlEvent};
use yaml_rust::scanner::{Marker, TokenType, TScalarStyle};

use serde::de::{self, Deserialize, DeserializeSeed, Unexpected};

use super::error::{Error, Result};

pub struct Loader {
    events: Vec<(Event, Marker)>,
    /// Map from alias id to index in events.
    aliases: BTreeMap<usize, usize>,
}

impl MarkedEventReceiver for Loader {
    fn on_event(&mut self, event: &YamlEvent, marker: Marker) {
        let event = match *event {
            YamlEvent::Nothing
                | YamlEvent::StreamStart
                | YamlEvent::StreamEnd
                | YamlEvent::DocumentStart
                | YamlEvent::DocumentEnd => return,

            YamlEvent::Alias(id) => Event::Alias(id),
            YamlEvent::Scalar(ref value, style, id, ref tag) => {
                self.aliases.insert(id, self.events.len());
                Event::Scalar(value.clone(), style, tag.clone())
            }
            YamlEvent::SequenceStart(id) => {
                self.aliases.insert(id, self.events.len());
                Event::SequenceStart
            }
            YamlEvent::SequenceEnd => Event::SequenceEnd,
            YamlEvent::MappingStart(id) => {
                self.aliases.insert(id, self.events.len());
                Event::MappingStart
            }
            YamlEvent::MappingEnd => Event::MappingEnd,
        };
        self.events.push((event, marker));
    }
}

#[derive(Debug)]
enum Event {
    Alias(usize),
    Scalar(String, TScalarStyle, Option<TokenType>),
    SequenceStart,
    SequenceEnd,
    MappingStart,
    MappingEnd,
}

struct Deserializer<'a> {
    events: &'a [(Event, Marker)],
    /// Map from alias id to index in events.
    aliases: &'a BTreeMap<usize, usize>,
    pos: usize,
}

impl<'a> Deserializer<'a> {
    fn peek(&self) -> Result<&'a Event> {
        match self.events.get(self.pos) {
            Some(event) => Ok(&event.0),
            None => Err(Error::EndOfStream),
        }
    }

    fn next(&mut self) -> Result<&'a Event> {
        match self.events.get(self.pos) {
            Some(event) => {
                self.pos += 1;
                Ok(&event.0)
            }
            None => Err(Error::EndOfStream),
        }
    }

    fn jump(&self, id: usize) -> Result<Deserializer<'a>> {
        match self.aliases.get(&id) {
            Some(&pos) => {
                Ok(Deserializer {
                    events: self.events,
                    aliases: self.aliases,
                    pos: pos,
                })
            }
            None => Err(Error::AliasNotFound),
        }
    }
}

impl<'a> de::SeqVisitor for Deserializer<'a> {
    type Error = Error;

    fn visit_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
        where T: DeserializeSeed
    {
        match *self.peek()? {
            Event::SequenceEnd => Ok(None),
            _ => seed.deserialize(self).map(Some),
        }
    }
}

impl<'a> de::MapVisitor for Deserializer<'a> {
    type Error = Error;

    fn visit_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
        where K: DeserializeSeed
    {
        match *self.peek()? {
            Event::MappingEnd => Ok(None),
            _ => seed.deserialize(self).map(Some),
        }
    }

    fn visit_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
        where V: DeserializeSeed
    {
        seed.deserialize(self)
    }
}

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

impl<'a, 'r> de::EnumVisitor for VariantVisitor<'a, 'r> {
    type Error = Error;
    type Variant = VariantVisitor<'a, 'r>;

    fn visit_variant_seed<V>(
        self,
        seed: V,
    ) -> Result<(V::Value, Self::Variant)>
        where V: DeserializeSeed
    {
        Ok((seed.deserialize(&mut *self.de)?, self))
    }
}

impl<'a, 'r> de::VariantVisitor for VariantVisitor<'a, 'r> {
    type Error = Error;

    fn visit_unit(self) -> Result<()> {
        Deserialize::deserialize(self.de)
    }

    fn visit_newtype_seed<T>(self, seed: T) -> Result<T::Value>
        where T: DeserializeSeed
    {
        seed.deserialize(self.de)
    }

    fn visit_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>
        where V: de::Visitor
    {
        de::Deserializer::deserialize(self.de, visitor)
    }

    fn visit_struct<V>(
        self,
        _fields: &'static [&'static str],
        visitor: V
    ) -> Result<V::Value>
        where V: de::Visitor
    {
        de::Deserializer::deserialize(self.de, visitor)
    }
}

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

impl<'a, 'r> de::EnumVisitor for UnitVariantVisitor<'a, 'r> {
    type Error = Error;
    type Variant = Self;

    fn visit_variant_seed<V>(
        self,
        seed: V,
    ) -> Result<(V::Value, Self::Variant)>
        where V: DeserializeSeed
    {
        Ok((seed.deserialize(&mut *self.de)?, self))
    }
}

impl<'a, 'r> de::VariantVisitor for UnitVariantVisitor<'a, 'r> {
    type Error = Error;

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

    fn visit_newtype_seed<T>(self, _seed: T) -> Result<T::Value>
        where T: DeserializeSeed
    {
        Err(de::Error::invalid_type(Unexpected::UnitVariant, &"newtype variant"))
    }

    fn visit_tuple<V>(self, _len: usize, _visitor: V) -> Result<V::Value>
        where V: de::Visitor
    {
        Err(de::Error::invalid_type(Unexpected::UnitVariant, &"tuple variant"))
    }

    fn visit_struct<V>(
        self,
        _fields: &'static [&'static str],
        _visitor: V
    ) -> Result<V::Value>
        where V: de::Visitor
    {
        Err(de::Error::invalid_type(Unexpected::UnitVariant, &"struct variant"))
    }
}

fn visit_untagged_str<V>(visitor: V, v: &str) -> Result<V::Value>
    where V: de::Visitor
{
    if v == "~" || v == "null" {
        return visitor.visit_unit();
    }
    if v == "true" {
        return visitor.visit_bool(true);
    }
    if v == "false" {
        return visitor.visit_bool(false);
    }
    if v.starts_with("0x") {
        if let Ok(n) = i64::from_str_radix(&v[2..], 16) {
            return visitor.visit_i64(n);
        }
    }
    if v.starts_with("0o") {
        if let Ok(n) = i64::from_str_radix(&v[2..], 8) {
            return visitor.visit_i64(n);
        }
    }
    if v.starts_with('+') {
        if let Ok(n) = v[1..].parse() {
            return visitor.visit_i64(n);
        }
    }
    if let Ok(n) = v.parse() {
        return visitor.visit_i64(n);
    }
    if let Ok(n) = v.parse() {
        return visitor.visit_f64(n);
    }
    visitor.visit_str(v)
}

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

    fn deserialize<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor
    {
        match *self.next()? {
            Event::Alias(i) => self.jump(i)?.deserialize(visitor),
            Event::Scalar(ref v, style, ref tag) => {
                if style != TScalarStyle::Plain {
                    visitor.visit_str(v)
                } else if let Some(TokenType::Tag(ref handle, ref suffix)) = *tag {
                    if handle == "!!" {
                        match suffix.as_ref() {
                            "bool" => {
                                match v.parse::<bool>() {
                                    Ok(v) => visitor.visit_bool(v),
                                    Err(_) => Err(de::Error::invalid_value(Unexpected::Str(v), &"a boolean")),
                                }
                            },
                            "int" => {
                                match v.parse::<i64>() {
                                    Ok(v) => visitor.visit_i64(v),
                                    Err(_) => Err(de::Error::invalid_value(Unexpected::Str(v), &"an integer")),
                                }
                            },
                            "float" => {
                                match v.parse::<f64>() {
                                    Ok(v) => visitor.visit_f64(v),
                                    Err(_) => Err(de::Error::invalid_value(Unexpected::Str(v), &"a float")),
                                }
                            },
                            "null" => {
                                match v.as_ref() {
                                    "~" | "null" => visitor.visit_unit(),
                                    _ => Err(de::Error::invalid_value(Unexpected::Str(v), &"null")),
                                }
                            }
                            _  => visitor.visit_str(v),
                        }
                    } else {
                        visitor.visit_str(v)
                    }
                } else {
                    visit_untagged_str(visitor, v)
                }
            }
            Event::SequenceStart => {
                let value = visitor.visit_seq(&mut *self)?;
                match *self.next()? {
                    Event::SequenceEnd => Ok(value),
                    _ => Err(de::Error::custom("remaining elements in sequence")), // FIXME
                }
            }
            Event::MappingStart => {
                let value = visitor.visit_map(&mut *self)?;
                match *self.next()? {
                    Event::MappingEnd => Ok(value),
                    _ => Err(de::Error::custom("remaining elements in map")), // FIXME
                }
            }
            Event::SequenceEnd | Event::MappingEnd => Err(Error::EndOfStream), // FIXME
        }
    }

    /// Parses `null` as None and any other values as `Some(...)`.
    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor
    {
        let is_some = match *self.peek()? {
            Event::Alias(i) => return self.jump(i)?.deserialize_option(visitor),
            Event::Scalar(ref v, style, ref tag) => {
                if style != TScalarStyle::Plain {
                    true
                } else if let Some(TokenType::Tag(ref handle, ref suffix)) = *tag {
                    if handle == "!!" && suffix == "null" {
                        if v == "~" || v == "null" {
                            false
                        } else {
                            return Err(de::Error::custom("failed to parse null")); // FIXME
                        }
                    } else {
                        true
                    }
                } else {
                    v != "~" && v != "null"
                }
            }
            Event::SequenceStart | Event::MappingStart => true,
            Event::SequenceEnd | Event::MappingEnd => return Err(Error::EndOfStream), // FIXME
        };
        if is_some {
            visitor.visit_some(self)
        } else {
            self.pos += 1;
            visitor.visit_none()
        }
    }

    /// Parses a newtype struct as the underlying value.
    fn deserialize_newtype_struct<V>(
        self,
        _name: &str,
        visitor: V
    ) -> Result<V::Value>
        where V: de::Visitor
    {
        visitor.visit_newtype_struct(self)
    }

    /// Parses an enum as a single key:value pair where the key identifies the
    /// variant and the value gives the content. A String will also parse correctly
    /// to a unit enum value.
    fn deserialize_enum<V>(
        self,
        name: &str,
        _variants: &'static [&'static str],
        visitor: V
    ) -> Result<V::Value>
        where V: de::Visitor
    {
        match *self.peek()? {
            Event::MappingStart => {
                self.pos += 1;
                let value = visitor.visit_enum(VariantVisitor { de: self })?;
                match *self.next()? {
                    Event::MappingEnd => Ok(value),
                    _ => Err(Error::VariantMapWrongSize(name.to_owned(), 2)), // FIXME
                }
            }
            Event::Scalar(_, _, _) => {
                visitor.visit_enum(UnitVariantVisitor { de: self })
            }
            _ => Err(Error::VariantNotAMapOrString(name.to_owned())),
        }
    }

    forward_to_deserialize!{
        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit seq
        seq_fixed_size bytes byte_buf map unit_struct tuple_struct struct
        struct_field tuple ignored_any
    }
}

/// Decodes a YAML value from a `&str`.
pub fn from_str<T>(s: &str) -> Result<T>
    where T: Deserialize
{
    let mut parser = Parser::new(s.chars());
    let mut loader = Loader {
        events: Vec::new(),
        aliases: BTreeMap::new(),
    };
    parser.load(&mut loader, true)?;
    if loader.events.is_empty() {
        Err(Error::EndOfStream)
    } else {
        let mut deserializer = Deserializer {
            events: &loader.events,
            aliases: &loader.aliases,
            pos: 0,
        };
        let t = Deserialize::deserialize(&mut deserializer)?;
        if deserializer.pos == loader.events.len() {
            Ok(t)
        } else {
            Err(Error::MoreThanOneDocument)
        }
    }
}

pub fn from_iter<I, T>(iter: I) -> Result<T>
    where I: Iterator<Item = io::Result<u8>>,
          T: Deserialize
{
    let bytes: Vec<u8> = try!(iter.collect());
    from_str(str::from_utf8(&bytes)?)
}

pub fn from_reader<R, T>(rdr: R) -> Result<T>
    where R: io::Read,
          T: Deserialize
{
    from_iter(rdr.bytes())
}

pub fn from_slice<T>(v: &[u8]) -> Result<T>
    where T: Deserialize
{
    from_iter(v.iter().map(|byte| Ok(*byte)))
}
<commit_msg>Improve seq and map invalid length errors<commit_after>// Copyright 2016 Serde YAML Developers
//
// 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.

//! YAML Deserialization
//!
//! This module provides YAML deserialization with the type `Deserializer`.

use std::collections::BTreeMap;
use std::fmt;
use std::io;
use std::str;

use yaml_rust::parser::{Parser, MarkedEventReceiver, Event as YamlEvent};
use yaml_rust::scanner::{Marker, TokenType, TScalarStyle};

use serde::de::{self, Deserialize, DeserializeSeed, Expected, Unexpected};
use serde::de::impls::IgnoredAny as Ignore;

use super::error::{Error, Result};

pub struct Loader {
    events: Vec<(Event, Marker)>,
    /// Map from alias id to index in events.
    aliases: BTreeMap<usize, usize>,
}

impl MarkedEventReceiver for Loader {
    fn on_event(&mut self, event: &YamlEvent, marker: Marker) {
        let event = match *event {
            YamlEvent::Nothing
                | YamlEvent::StreamStart
                | YamlEvent::StreamEnd
                | YamlEvent::DocumentStart
                | YamlEvent::DocumentEnd => return,

            YamlEvent::Alias(id) => Event::Alias(id),
            YamlEvent::Scalar(ref value, style, id, ref tag) => {
                self.aliases.insert(id, self.events.len());
                Event::Scalar(value.clone(), style, tag.clone())
            }
            YamlEvent::SequenceStart(id) => {
                self.aliases.insert(id, self.events.len());
                Event::SequenceStart
            }
            YamlEvent::SequenceEnd => Event::SequenceEnd,
            YamlEvent::MappingStart(id) => {
                self.aliases.insert(id, self.events.len());
                Event::MappingStart
            }
            YamlEvent::MappingEnd => Event::MappingEnd,
        };
        self.events.push((event, marker));
    }
}

#[derive(Debug, PartialEq)]
enum Event {
    Alias(usize),
    Scalar(String, TScalarStyle, Option<TokenType>),
    SequenceStart,
    SequenceEnd,
    MappingStart,
    MappingEnd,
}

struct Deserializer<'a> {
    events: &'a [(Event, Marker)],
    /// Map from alias id to index in events.
    aliases: &'a BTreeMap<usize, usize>,
    pos: usize,
}

impl<'a> Deserializer<'a> {
    fn peek(&self) -> Result<&'a Event> {
        match self.events.get(self.pos) {
            Some(event) => Ok(&event.0),
            None => Err(Error::EndOfStream),
        }
    }

    fn next(&mut self) -> Result<&'a Event> {
        match self.events.get(self.pos) {
            Some(event) => {
                self.pos += 1;
                Ok(&event.0)
            }
            None => Err(Error::EndOfStream),
        }
    }

    fn jump(&self, id: usize) -> Result<Deserializer<'a>> {
        match self.aliases.get(&id) {
            Some(&pos) => {
                Ok(Deserializer {
                    events: self.events,
                    aliases: self.aliases,
                    pos: pos,
                })
            }
            None => Err(Error::AliasNotFound),
        }
    }
}

struct CollectionVisitor<'a: 'r, 'r> {
    de: &'r mut Deserializer<'a>,
    len: usize,
}

impl<'a, 'r> de::SeqVisitor for CollectionVisitor<'a, 'r> {
    type Error = Error;

    fn visit_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
        where T: DeserializeSeed
    {
        match *self.de.peek()? {
            Event::SequenceEnd => Ok(None),
            _ => {
                self.len += 1;
                seed.deserialize(&mut *self.de).map(Some)
            }
        }
    }
}

impl<'a, 'r> de::MapVisitor for CollectionVisitor<'a, 'r> {
    type Error = Error;

    fn visit_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
        where K: DeserializeSeed
    {
        match *self.de.peek()? {
            Event::MappingEnd => Ok(None),
            _ => {
                self.len += 1;
                seed.deserialize(&mut *self.de).map(Some)
            }
        }
    }

    fn visit_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
        where V: DeserializeSeed
    {
        seed.deserialize(&mut *self.de)
    }
}

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

impl<'a, 'r> de::EnumVisitor for VariantVisitor<'a, 'r> {
    type Error = Error;
    type Variant = VariantVisitor<'a, 'r>;

    fn visit_variant_seed<V>(
        self,
        seed: V,
    ) -> Result<(V::Value, Self::Variant)>
        where V: DeserializeSeed
    {
        Ok((seed.deserialize(&mut *self.de)?, self))
    }
}

impl<'a, 'r> de::VariantVisitor for VariantVisitor<'a, 'r> {
    type Error = Error;

    fn visit_unit(self) -> Result<()> {
        Deserialize::deserialize(self.de)
    }

    fn visit_newtype_seed<T>(self, seed: T) -> Result<T::Value>
        where T: DeserializeSeed
    {
        seed.deserialize(self.de)
    }

    fn visit_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>
        where V: de::Visitor
    {
        de::Deserializer::deserialize(self.de, visitor)
    }

    fn visit_struct<V>(
        self,
        _fields: &'static [&'static str],
        visitor: V
    ) -> Result<V::Value>
        where V: de::Visitor
    {
        de::Deserializer::deserialize(self.de, visitor)
    }
}

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

impl<'a, 'r> de::EnumVisitor for UnitVariantVisitor<'a, 'r> {
    type Error = Error;
    type Variant = Self;

    fn visit_variant_seed<V>(
        self,
        seed: V,
    ) -> Result<(V::Value, Self::Variant)>
        where V: DeserializeSeed
    {
        Ok((seed.deserialize(&mut *self.de)?, self))
    }
}

impl<'a, 'r> de::VariantVisitor for UnitVariantVisitor<'a, 'r> {
    type Error = Error;

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

    fn visit_newtype_seed<T>(self, _seed: T) -> Result<T::Value>
        where T: DeserializeSeed
    {
        Err(de::Error::invalid_type(Unexpected::UnitVariant, &"newtype variant"))
    }

    fn visit_tuple<V>(self, _len: usize, _visitor: V) -> Result<V::Value>
        where V: de::Visitor
    {
        Err(de::Error::invalid_type(Unexpected::UnitVariant, &"tuple variant"))
    }

    fn visit_struct<V>(
        self,
        _fields: &'static [&'static str],
        _visitor: V
    ) -> Result<V::Value>
        where V: de::Visitor
    {
        Err(de::Error::invalid_type(Unexpected::UnitVariant, &"struct variant"))
    }
}

fn visit_untagged_str<V>(visitor: V, v: &str) -> Result<V::Value>
    where V: de::Visitor
{
    if v == "~" || v == "null" {
        return visitor.visit_unit();
    }
    if v == "true" {
        return visitor.visit_bool(true);
    }
    if v == "false" {
        return visitor.visit_bool(false);
    }
    if v.starts_with("0x") {
        if let Ok(n) = i64::from_str_radix(&v[2..], 16) {
            return visitor.visit_i64(n);
        }
    }
    if v.starts_with("0o") {
        if let Ok(n) = i64::from_str_radix(&v[2..], 8) {
            return visitor.visit_i64(n);
        }
    }
    if v.starts_with('+') {
        if let Ok(n) = v[1..].parse() {
            return visitor.visit_i64(n);
        }
    }
    if let Ok(n) = v.parse() {
        return visitor.visit_i64(n);
    }
    if let Ok(n) = v.parse() {
        return visitor.visit_f64(n);
    }
    visitor.visit_str(v)
}

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

    fn deserialize<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor
    {
        match *self.next()? {
            Event::Alias(i) => self.jump(i)?.deserialize(visitor),
            Event::Scalar(ref v, style, ref tag) => {
                if style != TScalarStyle::Plain {
                    visitor.visit_str(v)
                } else if let Some(TokenType::Tag(ref handle, ref suffix)) = *tag {
                    if handle == "!!" {
                        match suffix.as_ref() {
                            "bool" => {
                                match v.parse::<bool>() {
                                    Ok(v) => visitor.visit_bool(v),
                                    Err(_) => Err(de::Error::invalid_value(Unexpected::Str(v), &"a boolean")),
                                }
                            },
                            "int" => {
                                match v.parse::<i64>() {
                                    Ok(v) => visitor.visit_i64(v),
                                    Err(_) => Err(de::Error::invalid_value(Unexpected::Str(v), &"an integer")),
                                }
                            },
                            "float" => {
                                match v.parse::<f64>() {
                                    Ok(v) => visitor.visit_f64(v),
                                    Err(_) => Err(de::Error::invalid_value(Unexpected::Str(v), &"a float")),
                                }
                            },
                            "null" => {
                                match v.as_ref() {
                                    "~" | "null" => visitor.visit_unit(),
                                    _ => Err(de::Error::invalid_value(Unexpected::Str(v), &"null")),
                                }
                            }
                            _  => visitor.visit_str(v),
                        }
                    } else {
                        visitor.visit_str(v)
                    }
                } else {
                    visit_untagged_str(visitor, v)
                }
            }
            Event::SequenceStart => {
                let (value, len, remaining) = {
                    let mut seq = CollectionVisitor { de: self, len: 0 };
                    let value = visitor.visit_seq(&mut seq)?;
                    let mut remaining = 0;
                    while de::SeqVisitor::visit::<Ignore>(&mut seq)?.is_some() {
                        remaining += 1;
                    }
                    (value, seq.len, remaining)
                };
                assert_eq!(Event::SequenceEnd, *self.next()?);
                if remaining == 0 {
                    Ok(value)
                } else {
                    struct ExpectedSeq(usize);
                    impl Expected for ExpectedSeq {
                        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                            write!(formatter, "sequence of {} elements", self.0)
                        }
                    }
                    Err(de::Error::invalid_length(len + remaining, &ExpectedSeq(len)))
                }
            }
            Event::MappingStart => {
                let (value, len, remaining) = {
                    let mut map = CollectionVisitor { de: self, len: 0 };
                    let value = visitor.visit_map(&mut map)?;
                    let mut remaining = 0;
                    while de::MapVisitor::visit::<Ignore, Ignore>(&mut map)?.is_some() {
                        remaining += 1;
                    }
                    (value, map.len, remaining)
                };
                assert_eq!(Event::MappingEnd, *self.next()?);
                if remaining == 0 {
                    Ok(value)
                } else {
                    struct ExpectedMap(usize);
                    impl Expected for ExpectedMap {
                        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                            write!(formatter, "map containing {} entries", self.0)
                        }
                    }
                    Err(de::Error::invalid_length(len + remaining, &ExpectedMap(len)))
                }
            }
            Event::SequenceEnd | Event::MappingEnd => Err(Error::EndOfStream), // FIXME
        }
    }

    /// Parses `null` as None and any other values as `Some(...)`.
    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor
    {
        let is_some = match *self.peek()? {
            Event::Alias(i) => return self.jump(i)?.deserialize_option(visitor),
            Event::Scalar(ref v, style, ref tag) => {
                if style != TScalarStyle::Plain {
                    true
                } else if let Some(TokenType::Tag(ref handle, ref suffix)) = *tag {
                    if handle == "!!" && suffix == "null" {
                        if v == "~" || v == "null" {
                            false
                        } else {
                            return Err(de::Error::custom("failed to parse null")); // FIXME
                        }
                    } else {
                        true
                    }
                } else {
                    v != "~" && v != "null"
                }
            }
            Event::SequenceStart | Event::MappingStart => true,
            Event::SequenceEnd | Event::MappingEnd => return Err(Error::EndOfStream), // FIXME
        };
        if is_some {
            visitor.visit_some(self)
        } else {
            self.pos += 1;
            visitor.visit_none()
        }
    }

    /// Parses a newtype struct as the underlying value.
    fn deserialize_newtype_struct<V>(
        self,
        _name: &str,
        visitor: V
    ) -> Result<V::Value>
        where V: de::Visitor
    {
        visitor.visit_newtype_struct(self)
    }

    /// Parses an enum as a single key:value pair where the key identifies the
    /// variant and the value gives the content. A String will also parse correctly
    /// to a unit enum value.
    fn deserialize_enum<V>(
        self,
        name: &str,
        _variants: &'static [&'static str],
        visitor: V
    ) -> Result<V::Value>
        where V: de::Visitor
    {
        match *self.peek()? {
            Event::MappingStart => {
                self.pos += 1;
                let value = visitor.visit_enum(VariantVisitor { de: self })?;
                match *self.next()? {
                    Event::MappingEnd => Ok(value),
                    _ => Err(Error::VariantMapWrongSize(name.to_owned(), 2)), // FIXME
                }
            }
            Event::Scalar(_, _, _) => {
                visitor.visit_enum(UnitVariantVisitor { de: self })
            }
            _ => Err(Error::VariantNotAMapOrString(name.to_owned())),
        }
    }

    forward_to_deserialize!{
        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit seq
        seq_fixed_size bytes byte_buf map unit_struct tuple_struct struct
        struct_field tuple ignored_any
    }
}

/// Decodes a YAML value from a `&str`.
pub fn from_str<T>(s: &str) -> Result<T>
    where T: Deserialize
{
    let mut parser = Parser::new(s.chars());
    let mut loader = Loader {
        events: Vec::new(),
        aliases: BTreeMap::new(),
    };
    parser.load(&mut loader, true)?;
    if loader.events.is_empty() {
        Err(Error::EndOfStream)
    } else {
        let mut deserializer = Deserializer {
            events: &loader.events,
            aliases: &loader.aliases,
            pos: 0,
        };
        let t = Deserialize::deserialize(&mut deserializer)?;
        if deserializer.pos == loader.events.len() {
            Ok(t)
        } else {
            Err(Error::MoreThanOneDocument)
        }
    }
}

pub fn from_iter<I, T>(iter: I) -> Result<T>
    where I: Iterator<Item = io::Result<u8>>,
          T: Deserialize
{
    let bytes: Vec<u8> = try!(iter.collect());
    from_str(str::from_utf8(&bytes)?)
}

pub fn from_reader<R, T>(rdr: R) -> Result<T>
    where R: io::Read,
          T: Deserialize
{
    from_iter(rdr.bytes())
}

pub fn from_slice<T>(v: &[u8]) -> Result<T>
    where T: Deserialize
{
    from_iter(v.iter().map(|byte| Ok(*byte)))
}
<|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/. */

/// Implementation of Quartz (CoreGraphics) fonts.

extern crate core_foundation;
extern crate core_graphics;
extern crate core_text;

use app_units::Au;
use byteorder::{BigEndian, ByteOrder};
use core_foundation::base::CFIndex;
use core_foundation::data::CFData;
use core_foundation::string::UniChar;
use core_graphics::font::CGGlyph;
use core_graphics::geometry::CGRect;
use core_text::font::CTFont;
use core_text::font_descriptor::kCTFontDefaultOrientation;
use core_text::font_descriptor::{SymbolicTraitAccessors, TraitAccessors};
use font::{FontHandleMethods, FontMetrics, FontTableTag, FontTableMethods, FractionalPixel};
use font::{GPOS, GSUB, KERN};
use platform::font_template::FontTemplateData;
use platform::macos::font_context::FontContextHandle;
use std::ops::Range;
use std::sync::Arc;
use std::{fmt, ptr};
use style::computed_values::{font_stretch, font_weight};
use text::glyph::GlyphId;

const KERN_PAIR_LEN: usize = 6;

pub struct FontTable {
    data: CFData,
}

// assumes 72 points per inch, and 96 px per inch
fn px_to_pt(px: f64) -> f64 {
    px / 96. * 72.
}

// assumes 72 points per inch, and 96 px per inch
fn pt_to_px(pt: f64) -> f64 {
    pt / 72. * 96.
}

fn au_from_pt(pt: f64) -> Au {
    Au::from_f64_px(pt_to_px(pt))
}

impl FontTable {
    pub fn wrap(data: CFData) -> FontTable {
        FontTable { data: data }
    }
}

impl FontTableMethods for FontTable {
    fn buffer(&self) -> &[u8] {
        self.data.bytes()
    }
}

#[derive(Debug)]
pub struct FontHandle {
    font_data: Arc<FontTemplateData>,
    ctfont: CTFont,
    h_kern_subtable: Option<CachedKernTable>,
    can_do_fast_shaping: bool,
}

impl FontHandle {
    /// Cache all the data needed for basic horizontal kerning. This is used only as a fallback or
    /// fast path (when the GPOS table is missing or unnecessary) so it needn't handle every case.
    fn find_h_kern_subtable(&self) -> Option<CachedKernTable> {
        let font_table = match self.table_for_tag(KERN) {
            Some(table) => table,
            None => return None
        };

        let mut result = CachedKernTable {
            font_table: font_table,
            pair_data_range: 0..0,
            px_per_font_unit: 0.0,
        };

        // Look for a subtable with horizontal kerning in format 0.
        // https://www.microsoft.com/typography/otspec/kern.htm
        const KERN_COVERAGE_HORIZONTAL_FORMAT_0: u16 = 1;
        const SUBTABLE_HEADER_LEN: usize = 6;
        const FORMAT_0_HEADER_LEN: usize = 8;
        {
            let table = result.font_table.buffer();
            let version = BigEndian::read_u16(table);
            if version != 0 {
                return None;
            }
            let num_subtables = BigEndian::read_u16(&table[2..]);
            let mut start = 4;
            for _ in 0..num_subtables {
                // TODO: Check the subtable version number?
                let len = BigEndian::read_u16(&table[start + 2..]) as usize;
                let cov = BigEndian::read_u16(&table[start + 4..]);
                let end = start + len;
                if cov == KERN_COVERAGE_HORIZONTAL_FORMAT_0 {
                    // Found a matching subtable.
                    if result.pair_data_range.len() > 0 {
                        debug!("Found multiple horizontal kern tables. Disable fast path.");
                        return None;
                    }
                    // Read the subtable header.
                    let subtable_start = start + SUBTABLE_HEADER_LEN;
                    let n_pairs = BigEndian::read_u16(&table[subtable_start..]) as usize;
                    let pair_data_start = subtable_start + FORMAT_0_HEADER_LEN;

                    result.pair_data_range = pair_data_start..end;
                    let pt_per_font_unit = self.ctfont.pt_size() as f64 /
                                           self.ctfont.units_per_em() as f64;
                    result.px_per_font_unit = pt_to_px(pt_per_font_unit);

                    debug_assert_eq!(n_pairs * KERN_PAIR_LEN, result.pair_data_range.len());
                }
                start = end;
            }
        }
        if result.pair_data_range.len() > 0 {
            Some(result)
        } else {
            None
        }
    }
}

struct CachedKernTable {
    font_table: FontTable,
    pair_data_range: Range<usize>,
    px_per_font_unit: f64,
}

impl CachedKernTable {
    /// Search for a glyph pair in the kern table and return the corresponding value.
    fn binary_search(&self, first_glyph: GlyphId, second_glyph: GlyphId) -> Option<i16> {
        let pairs = &self.font_table.buffer()[self.pair_data_range.clone()];

        let query = first_glyph << 16 | second_glyph;
        let (mut start, mut end) = (0, pairs.len() / KERN_PAIR_LEN);
        while start < end {
            let i = (start + end) / 2;
            let key = BigEndian::read_u32(&pairs[i * KERN_PAIR_LEN..]);
            if key > query {
                end = i;
            } else if key < query {
                start = i + 1;
            } else {
                return Some(BigEndian::read_i16(&pairs[i * KERN_PAIR_LEN + 4..]));
            }
        }
        None
    }
}

impl fmt::Debug for CachedKernTable {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "CachedKernTable")
    }
}

impl FontHandleMethods for FontHandle {
    fn new_from_template(_fctx: &FontContextHandle,
                         template: Arc<FontTemplateData>,
                         pt_size: Option<Au>)
                         -> Result<FontHandle, ()> {
        let size = match pt_size {
            Some(s) => s.to_f64_px(),
            None => 0.0
        };
        match template.ctfont(size) {
            Some(ref ctfont) => {
                let mut handle = FontHandle {
                    font_data: template.clone(),
                    ctfont: ctfont.clone_with_font_size(size),
                    h_kern_subtable: None,
                    can_do_fast_shaping: false,
                };
                handle.h_kern_subtable = handle.find_h_kern_subtable();
                // TODO (#11310): Implement basic support for GPOS and GSUB.
                handle.can_do_fast_shaping = handle.h_kern_subtable.is_some() &&
                                             handle.table_for_tag(GPOS).is_none() &&
                                             handle.table_for_tag(GSUB).is_none();
                Ok(handle)
            }
            None => {
                Err(())
            }
        }
    }

    fn template(&self) -> Arc<FontTemplateData> {
        self.font_data.clone()
    }

    fn family_name(&self) -> String {
        self.ctfont.family_name()
    }

    fn face_name(&self) -> String {
        self.ctfont.face_name()
    }

    fn is_italic(&self) -> bool {
        self.ctfont.symbolic_traits().is_italic()
    }

    fn boldness(&self) -> font_weight::T {
        let normalized = self.ctfont.all_traits().normalized_weight();  // [-1.0, 1.0]
        let normalized = if normalized <= 0.0 {
            4.0 + normalized * 3.0  // [1.0, 4.0]
        } else {
            4.0 + normalized * 5.0  // [4.0, 9.0]
        }; // [1.0, 9.0], centered on 4.0
        match normalized.round() as u32 {
            1 => font_weight::T::Weight100,
            2 => font_weight::T::Weight200,
            3 => font_weight::T::Weight300,
            4 => font_weight::T::Weight400,
            5 => font_weight::T::Weight500,
            6 => font_weight::T::Weight600,
            7 => font_weight::T::Weight700,
            8 => font_weight::T::Weight800,
            _ => font_weight::T::Weight900,
        }
    }

    fn stretchiness(&self) -> font_stretch::T {
        let normalized = self.ctfont.all_traits().normalized_width();  // [-1.0, 1.0]
        let normalized = (normalized + 1.0) / 2.0 * 9.0;  // [0.0, 9.0]
        match normalized {
            v if v < 1.0 => font_stretch::T::ultra_condensed,
            v if v < 2.0 => font_stretch::T::extra_condensed,
            v if v < 3.0 => font_stretch::T::condensed,
            v if v < 4.0 => font_stretch::T::semi_condensed,
            v if v < 5.0 => font_stretch::T::normal,
            v if v < 6.0 => font_stretch::T::semi_expanded,
            v if v < 7.0 => font_stretch::T::expanded,
            v if v < 8.0 => font_stretch::T::extra_expanded,
            _ => font_stretch::T::ultra_expanded,
        }
    }

    fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
        let characters: [UniChar; 1] = [codepoint as UniChar];
        let mut glyphs: [CGGlyph; 1] = [0 as CGGlyph];
        let count: CFIndex = 1;

        let result = self.ctfont.get_glyphs_for_characters(&characters[0],
                                                           &mut glyphs[0],
                                                           count);

        if !result {
            // No glyph for this character
            return None;
        }

        assert!(glyphs[0] != 0); // FIXME: error handling
        return Some(glyphs[0] as GlyphId);
    }

    fn glyph_h_kerning(&self, first_glyph: GlyphId, second_glyph: GlyphId) -> FractionalPixel {
        if let Some(ref table) = self.h_kern_subtable {
            if let Some(font_units) = table.binary_search(first_glyph, second_glyph) {
                return font_units as f64 * table.px_per_font_unit;
            }
        }
        0.0
    }

    fn can_do_fast_shaping(&self) -> bool {
        self.can_do_fast_shaping
    }

    fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
        let glyphs = [glyph as CGGlyph];
        let advance = self.ctfont.get_advances_for_glyphs(kCTFontDefaultOrientation,
                                                          &glyphs[0],
                                                          ptr::null_mut(),
                                                          1);
        Some(advance as FractionalPixel)
    }

    fn metrics(&self) -> FontMetrics {
        let bounding_rect: CGRect = self.ctfont.bounding_box();
        let ascent = self.ctfont.ascent() as f64;
        let descent = self.ctfont.descent() as f64;
        let em_size = Au::from_f64_px(self.ctfont.pt_size() as f64);
        let leading = self.ctfont.leading() as f64;

        let scale = px_to_pt(self.ctfont.pt_size() as f64) / (ascent + descent);
        let line_gap = (ascent + descent + leading + 0.5).floor();

        let max_advance_width = au_from_pt(bounding_rect.size.width as f64);
        let average_advance = self.glyph_index('0')
                                  .and_then(|idx| self.glyph_h_advance(idx))
                                  .map(Au::from_f64_px)
                                  .unwrap_or(max_advance_width);

        let metrics =  FontMetrics {
            underline_size:   au_from_pt(self.ctfont.underline_thickness() as f64),
            // TODO(Issue #201): underline metrics are not reliable. Have to pull out of font table
            // directly.
            //
            // see also: https://bugs.webkit.org/show_bug.cgi?id=16768
            // see also: https://bugreports.qt-project.org/browse/QTBUG-13364
            underline_offset: au_from_pt(self.ctfont.underline_position() as f64),
            strikeout_size:   Au(0), // FIXME(Issue #942)
            strikeout_offset: Au(0), // FIXME(Issue #942)
            leading:          au_from_pt(leading),
            x_height:         au_from_pt(self.ctfont.x_height() as f64),
            em_size:          em_size,
            ascent:           au_from_pt(ascent * scale),
            descent:          au_from_pt(descent * scale),
            max_advance:      max_advance_width,
            average_advance:  average_advance,
            line_gap:         Au::from_f64_px(line_gap),
        };
        debug!("Font metrics (@{} pt): {:?}", self.ctfont.pt_size() as f64, metrics);
        metrics
    }

    fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
        let result: Option<CFData> = self.ctfont.get_font_table(tag);
        result.and_then(|data| {
            Some(FontTable::wrap(data))
        })
    }
}
<commit_msg>Auto merge of #12291 - mbrubeck:font-panic, r=Wafflespeanut<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/. */

/// Implementation of Quartz (CoreGraphics) fonts.

extern crate core_foundation;
extern crate core_graphics;
extern crate core_text;

use app_units::Au;
use byteorder::{BigEndian, ByteOrder};
use core_foundation::base::CFIndex;
use core_foundation::data::CFData;
use core_foundation::string::UniChar;
use core_graphics::font::CGGlyph;
use core_graphics::geometry::CGRect;
use core_text::font::CTFont;
use core_text::font_descriptor::kCTFontDefaultOrientation;
use core_text::font_descriptor::{SymbolicTraitAccessors, TraitAccessors};
use font::{FontHandleMethods, FontMetrics, FontTableTag, FontTableMethods, FractionalPixel};
use font::{GPOS, GSUB, KERN};
use platform::font_template::FontTemplateData;
use platform::macos::font_context::FontContextHandle;
use std::ops::Range;
use std::sync::Arc;
use std::{fmt, ptr};
use style::computed_values::{font_stretch, font_weight};
use text::glyph::GlyphId;

const KERN_PAIR_LEN: usize = 6;

pub struct FontTable {
    data: CFData,
}

// assumes 72 points per inch, and 96 px per inch
fn px_to_pt(px: f64) -> f64 {
    px / 96. * 72.
}

// assumes 72 points per inch, and 96 px per inch
fn pt_to_px(pt: f64) -> f64 {
    pt / 72. * 96.
}

fn au_from_pt(pt: f64) -> Au {
    Au::from_f64_px(pt_to_px(pt))
}

impl FontTable {
    pub fn wrap(data: CFData) -> FontTable {
        FontTable { data: data }
    }
}

impl FontTableMethods for FontTable {
    fn buffer(&self) -> &[u8] {
        self.data.bytes()
    }
}

#[derive(Debug)]
pub struct FontHandle {
    font_data: Arc<FontTemplateData>,
    ctfont: CTFont,
    h_kern_subtable: Option<CachedKernTable>,
    can_do_fast_shaping: bool,
}

impl FontHandle {
    /// Cache all the data needed for basic horizontal kerning. This is used only as a fallback or
    /// fast path (when the GPOS table is missing or unnecessary) so it needn't handle every case.
    fn find_h_kern_subtable(&self) -> Option<CachedKernTable> {
        let font_table = match self.table_for_tag(KERN) {
            Some(table) => table,
            None => return None
        };

        let mut result = CachedKernTable {
            font_table: font_table,
            pair_data_range: 0..0,
            px_per_font_unit: 0.0,
        };

        // Look for a subtable with horizontal kerning in format 0.
        // https://www.microsoft.com/typography/otspec/kern.htm
        const KERN_COVERAGE_HORIZONTAL_FORMAT_0: u16 = 1;
        const SUBTABLE_HEADER_LEN: usize = 6;
        const FORMAT_0_HEADER_LEN: usize = 8;
        {
            let table = result.font_table.buffer();
            let version = BigEndian::read_u16(table);
            if version != 0 {
                return None;
            }
            let num_subtables = BigEndian::read_u16(&table[2..]);
            let mut start = 4;
            for _ in 0..num_subtables {
                // TODO: Check the subtable version number?
                let len = BigEndian::read_u16(&table[start + 2..]) as usize;
                let cov = BigEndian::read_u16(&table[start + 4..]);
                let end = start + len;
                if cov == KERN_COVERAGE_HORIZONTAL_FORMAT_0 {
                    // Found a matching subtable.
                    if result.pair_data_range.len() > 0 {
                        debug!("Found multiple horizontal kern tables. Disable fast path.");
                        return None;
                    }
                    // Read the subtable header.
                    let subtable_start = start + SUBTABLE_HEADER_LEN;
                    let n_pairs = BigEndian::read_u16(&table[subtable_start..]) as usize;
                    let pair_data_start = subtable_start + FORMAT_0_HEADER_LEN;

                    result.pair_data_range = pair_data_start..end;
                    if result.pair_data_range.len() != n_pairs * KERN_PAIR_LEN {
                        debug!("Bad data in kern header. Disable fast path.");
                        return None;
                    }

                    let pt_per_font_unit = self.ctfont.pt_size() as f64 /
                                           self.ctfont.units_per_em() as f64;
                    result.px_per_font_unit = pt_to_px(pt_per_font_unit);
                }
                start = end;
            }
        }
        if result.pair_data_range.len() > 0 {
            Some(result)
        } else {
            None
        }
    }
}

struct CachedKernTable {
    font_table: FontTable,
    pair_data_range: Range<usize>,
    px_per_font_unit: f64,
}

impl CachedKernTable {
    /// Search for a glyph pair in the kern table and return the corresponding value.
    fn binary_search(&self, first_glyph: GlyphId, second_glyph: GlyphId) -> Option<i16> {
        let pairs = &self.font_table.buffer()[self.pair_data_range.clone()];

        let query = first_glyph << 16 | second_glyph;
        let (mut start, mut end) = (0, pairs.len() / KERN_PAIR_LEN);
        while start < end {
            let i = (start + end) / 2;
            let key = BigEndian::read_u32(&pairs[i * KERN_PAIR_LEN..]);
            if key > query {
                end = i;
            } else if key < query {
                start = i + 1;
            } else {
                return Some(BigEndian::read_i16(&pairs[i * KERN_PAIR_LEN + 4..]));
            }
        }
        None
    }
}

impl fmt::Debug for CachedKernTable {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "CachedKernTable")
    }
}

impl FontHandleMethods for FontHandle {
    fn new_from_template(_fctx: &FontContextHandle,
                         template: Arc<FontTemplateData>,
                         pt_size: Option<Au>)
                         -> Result<FontHandle, ()> {
        let size = match pt_size {
            Some(s) => s.to_f64_px(),
            None => 0.0
        };
        match template.ctfont(size) {
            Some(ref ctfont) => {
                let mut handle = FontHandle {
                    font_data: template.clone(),
                    ctfont: ctfont.clone_with_font_size(size),
                    h_kern_subtable: None,
                    can_do_fast_shaping: false,
                };
                handle.h_kern_subtable = handle.find_h_kern_subtable();
                // TODO (#11310): Implement basic support for GPOS and GSUB.
                handle.can_do_fast_shaping = handle.h_kern_subtable.is_some() &&
                                             handle.table_for_tag(GPOS).is_none() &&
                                             handle.table_for_tag(GSUB).is_none();
                Ok(handle)
            }
            None => {
                Err(())
            }
        }
    }

    fn template(&self) -> Arc<FontTemplateData> {
        self.font_data.clone()
    }

    fn family_name(&self) -> String {
        self.ctfont.family_name()
    }

    fn face_name(&self) -> String {
        self.ctfont.face_name()
    }

    fn is_italic(&self) -> bool {
        self.ctfont.symbolic_traits().is_italic()
    }

    fn boldness(&self) -> font_weight::T {
        let normalized = self.ctfont.all_traits().normalized_weight();  // [-1.0, 1.0]
        let normalized = if normalized <= 0.0 {
            4.0 + normalized * 3.0  // [1.0, 4.0]
        } else {
            4.0 + normalized * 5.0  // [4.0, 9.0]
        }; // [1.0, 9.0], centered on 4.0
        match normalized.round() as u32 {
            1 => font_weight::T::Weight100,
            2 => font_weight::T::Weight200,
            3 => font_weight::T::Weight300,
            4 => font_weight::T::Weight400,
            5 => font_weight::T::Weight500,
            6 => font_weight::T::Weight600,
            7 => font_weight::T::Weight700,
            8 => font_weight::T::Weight800,
            _ => font_weight::T::Weight900,
        }
    }

    fn stretchiness(&self) -> font_stretch::T {
        let normalized = self.ctfont.all_traits().normalized_width();  // [-1.0, 1.0]
        let normalized = (normalized + 1.0) / 2.0 * 9.0;  // [0.0, 9.0]
        match normalized {
            v if v < 1.0 => font_stretch::T::ultra_condensed,
            v if v < 2.0 => font_stretch::T::extra_condensed,
            v if v < 3.0 => font_stretch::T::condensed,
            v if v < 4.0 => font_stretch::T::semi_condensed,
            v if v < 5.0 => font_stretch::T::normal,
            v if v < 6.0 => font_stretch::T::semi_expanded,
            v if v < 7.0 => font_stretch::T::expanded,
            v if v < 8.0 => font_stretch::T::extra_expanded,
            _ => font_stretch::T::ultra_expanded,
        }
    }

    fn glyph_index(&self, codepoint: char) -> Option<GlyphId> {
        let characters: [UniChar; 1] = [codepoint as UniChar];
        let mut glyphs: [CGGlyph; 1] = [0 as CGGlyph];
        let count: CFIndex = 1;

        let result = self.ctfont.get_glyphs_for_characters(&characters[0],
                                                           &mut glyphs[0],
                                                           count);

        if !result {
            // No glyph for this character
            return None;
        }

        assert!(glyphs[0] != 0); // FIXME: error handling
        return Some(glyphs[0] as GlyphId);
    }

    fn glyph_h_kerning(&self, first_glyph: GlyphId, second_glyph: GlyphId) -> FractionalPixel {
        if let Some(ref table) = self.h_kern_subtable {
            if let Some(font_units) = table.binary_search(first_glyph, second_glyph) {
                return font_units as f64 * table.px_per_font_unit;
            }
        }
        0.0
    }

    fn can_do_fast_shaping(&self) -> bool {
        self.can_do_fast_shaping
    }

    fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
        let glyphs = [glyph as CGGlyph];
        let advance = self.ctfont.get_advances_for_glyphs(kCTFontDefaultOrientation,
                                                          &glyphs[0],
                                                          ptr::null_mut(),
                                                          1);
        Some(advance as FractionalPixel)
    }

    fn metrics(&self) -> FontMetrics {
        let bounding_rect: CGRect = self.ctfont.bounding_box();
        let ascent = self.ctfont.ascent() as f64;
        let descent = self.ctfont.descent() as f64;
        let em_size = Au::from_f64_px(self.ctfont.pt_size() as f64);
        let leading = self.ctfont.leading() as f64;

        let scale = px_to_pt(self.ctfont.pt_size() as f64) / (ascent + descent);
        let line_gap = (ascent + descent + leading + 0.5).floor();

        let max_advance_width = au_from_pt(bounding_rect.size.width as f64);
        let average_advance = self.glyph_index('0')
                                  .and_then(|idx| self.glyph_h_advance(idx))
                                  .map(Au::from_f64_px)
                                  .unwrap_or(max_advance_width);

        let metrics =  FontMetrics {
            underline_size:   au_from_pt(self.ctfont.underline_thickness() as f64),
            // TODO(Issue #201): underline metrics are not reliable. Have to pull out of font table
            // directly.
            //
            // see also: https://bugs.webkit.org/show_bug.cgi?id=16768
            // see also: https://bugreports.qt-project.org/browse/QTBUG-13364
            underline_offset: au_from_pt(self.ctfont.underline_position() as f64),
            strikeout_size:   Au(0), // FIXME(Issue #942)
            strikeout_offset: Au(0), // FIXME(Issue #942)
            leading:          au_from_pt(leading),
            x_height:         au_from_pt(self.ctfont.x_height() as f64),
            em_size:          em_size,
            ascent:           au_from_pt(ascent * scale),
            descent:          au_from_pt(descent * scale),
            max_advance:      max_advance_width,
            average_advance:  average_advance,
            line_gap:         Au::from_f64_px(line_gap),
        };
        debug!("Font metrics (@{} pt): {:?}", self.ctfont.pt_size() as f64, metrics);
        metrics
    }

    fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
        let result: Option<CFData> = self.ctfont.get_font_table(tag);
        result.and_then(|data| {
            Some(FontTable::wrap(data))
        })
    }
}
<|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/. */

//! The code to expose the DOM to JavaScript through IDL bindings.
//!
//! Exposing a DOM object to JavaScript
//! ===================================
//!
//! As [explained earlier](../index.html#a-dom-object-and-its-reflector), the
//! implementation of an interface `Foo` involves two objects: the DOM object
//! (implemented in Rust) and the reflector (a `JSObject`).
//!
//! In order to expose the interface's members to the web, properties
//! corresponding to the operations and attributes are defined on an object in
//! the reflector's prototype chain or on the reflector itself.
//!
//! Typically, these properties are either value properties whose value is a
//! function (for operations) or accessor properties that have a getter and
//! optionally a setter function (for attributes, depending on whether they are
//! marked `readonly`).
//!
//! All these JavaScript functions are set up such that, when they're called,
//! they call a Rust function in the generated glue code. This glue code does
//! some sanity checks and [argument conversions](conversions/index.html), and
//! calls into API implementation for the DOM object.
//!
//! Rust reflections of WebIDL constructs
//! =====================================
//!
//! WebIDL members are turned into methods on the DOM object (static methods
//! for a static members and instance methods for regular members).
//!
//! The instance methods for an interface `Foo` are defined on a
//! `dom::bindings::codegen::Bindings::FooBindings::FooMethods` trait. This
//! trait is then implemented for `JSRef<'a, Foo>`.
//!
//! The return type and argument types are determined [as described below]
//! (#rust-reflections-of-webidl-types).
//! In addition to those, all methods that are [allowed to throw]
//! (#throwing-exceptions) will have the return value wrapped in
//! [`Fallible<T>`](error/type.Fallible.html).
//! Methods that use certain WebIDL types like `any` or `object` will get a
//! `*mut JSContext` argument prepended to the argument list. Static methods
//! will be passed a [`GlobalRef`](global/enum.GlobalRef.html) for the relevant
//! global. This argument comes before the `*mut JSContext` argument, if any.
//!
//! Rust reflections of WebIDL operations (methods)
//! -----------------------------------------------
//!
//! A WebIDL operation is turned into one method for every overload.
//! The first overload gets the base name, and consecutive overloads have an
//! underscore appended to the name.
//!
//! The base name of the Rust method is simply the name of the WebIDL operation
//! with the first letter converted to uppercase.
//!
//! Rust reflections of WebIDL attributes
//! -------------------------------------
//!
//! A WebIDL attribute is turned into a pair of methods: one for the getter and
//! one for the setter. A readonly attribute only has a getter and no setter.
//!
//! The getter's name is the name of the attribute with the first letter
//! converted to uppercase. It has `Get` prepended to it if the type of the
//! attribute is nullable or if the getter can throw.
//!
//! The method signature for the getter looks just like an operation with no
//! arguments and the attribute's type as the return type.
//!
//! The setter's name is `Set` followed by the name of the attribute with the
//! first letter converted to uppercase. The method signature looks just like
//! an operation with a void return value and a single argument whose type is
//! the attribute's type.
//!
//! Rust reflections of WebIDL constructors
//! ---------------------------------------
//!
//! A WebIDL constructor is turned into a static class method named
//! `Constructor`. The arguments of this method will be the arguments of the
//! WebIDL constructor, with a `GlobalRef` for the relevant global prepended.
//! The return value of the constructor for MyInterface is exactly the same as
//! that of a method returning an instance of MyInterface. Constructors are
//! always [allowed to throw](#throwing-exceptions).
//!
//! Rust reflections of WebIDL types
//! --------------------------------
//!
//! The exact Rust representation for WebIDL types can depend on the precise
//! way that they're being used (e.g., return values and arguments might have
//! different representations).
//!
//! Optional arguments which do not have a default value are represented by
//! wrapping `Option<T>` around the representation of the argument type.
//! Optional arguments which do have a default value are represented by the
//! argument type itself, set to the default value if the argument was not in
//! fact passed in.
//!
//! Variadic WebIDL arguments are represented by wrapping a `Vec<T>` around the
//! representation of the argument type.
//!
//! See [the type mapping for particular types](conversions/index.html).
//!
//! Rust reflections of stringifiers
//! --------------------------------
//!
//! *To be written.*
//!
//! Rust reflections of legacy callers
//! ---------------------------------
//!
//! Legacy callers are not yet implemented.
//!
//! Rust reflections of getters and setters
//! ---------------------------------------
//!
//! *To be written.*
//!
//! Throwing exceptions
//! ===================
//!
//! WebIDL methods, getters, and setters that need to throw exceptions need to
//! be explicitly marked as such with the `[Throws]`, `[GetterThrows]` and
//! `[SetterThrows]` custom attributes.
//!
//! `[Throws]` applies to both methods and attributes; for attributes it means
//! both the getter and the setter (if any) can throw. `[GetterThrows]` applies
//! only to attributes. `[SetterThrows]` applies only to writable attributes.
//!
//! The corresponding Rust methods will have the return value wrapped in
//! [`Fallible<T>`](error/type.Fallible.html). To throw an exception, simply
//! return `Err()` from the method with the appropriate [error value]
//! (error/enum.Error.html).

pub mod callback;
pub mod cell;
pub mod conversions;
pub mod error;
pub mod global;
pub mod js;
pub mod num;
pub mod proxyhandler;
pub mod refcounted;
pub mod str;
pub mod structuredclone;
pub mod trace;
pub mod utils;

/// Generated JS-Rust bindings.
#[allow(missing_docs, non_snake_case)]
pub mod codegen {
    // FIXME(#5853) we shouldn't need to
    // allow moved_no_move here
    #[allow(unrooted_must_root, moved_no_move)]
    pub mod Bindings {
        include!(concat!(env!("OUT_DIR"), "/Bindings/mod.rs"));
    }
    pub mod InterfaceTypes {
        include!(concat!(env!("OUT_DIR"), "/InterfaceTypes.rs"));
    }
    #[allow(unused_imports)]
    pub mod InheritTypes {
        include!(concat!(env!("OUT_DIR"), "/InheritTypes.rs"));
    }
    pub mod PrototypeList {
        include!(concat!(env!("OUT_DIR"), "/PrototypeList.rs"));
    }
    #[allow(non_camel_case_types, non_upper_case_globals,
            unused_imports, unused_variables, unused_assignments)]
    pub mod RegisterBindings {
        include!(concat!(env!("OUT_DIR"), "/RegisterBindings.rs"));
    }
    #[allow(non_camel_case_types, non_upper_case_globals,
            unused_imports, unused_variables, unused_assignments)]
    pub mod UnionTypes {
        include!(concat!(env!("OUT_DIR"), "/UnionTypes.rs"));
    }
}
<commit_msg>Auto merge of #8049 - Ms2ger:warnings, r=nox<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/. */

//! The code to expose the DOM to JavaScript through IDL bindings.
//!
//! Exposing a DOM object to JavaScript
//! ===================================
//!
//! As [explained earlier](../index.html#a-dom-object-and-its-reflector), the
//! implementation of an interface `Foo` involves two objects: the DOM object
//! (implemented in Rust) and the reflector (a `JSObject`).
//!
//! In order to expose the interface's members to the web, properties
//! corresponding to the operations and attributes are defined on an object in
//! the reflector's prototype chain or on the reflector itself.
//!
//! Typically, these properties are either value properties whose value is a
//! function (for operations) or accessor properties that have a getter and
//! optionally a setter function (for attributes, depending on whether they are
//! marked `readonly`).
//!
//! All these JavaScript functions are set up such that, when they're called,
//! they call a Rust function in the generated glue code. This glue code does
//! some sanity checks and [argument conversions](conversions/index.html), and
//! calls into API implementation for the DOM object.
//!
//! Rust reflections of WebIDL constructs
//! =====================================
//!
//! WebIDL members are turned into methods on the DOM object (static methods
//! for a static members and instance methods for regular members).
//!
//! The instance methods for an interface `Foo` are defined on a
//! `dom::bindings::codegen::Bindings::FooBindings::FooMethods` trait. This
//! trait is then implemented for `JSRef<'a, Foo>`.
//!
//! The return type and argument types are determined [as described below]
//! (#rust-reflections-of-webidl-types).
//! In addition to those, all methods that are [allowed to throw]
//! (#throwing-exceptions) will have the return value wrapped in
//! [`Fallible<T>`](error/type.Fallible.html).
//! Methods that use certain WebIDL types like `any` or `object` will get a
//! `*mut JSContext` argument prepended to the argument list. Static methods
//! will be passed a [`GlobalRef`](global/enum.GlobalRef.html) for the relevant
//! global. This argument comes before the `*mut JSContext` argument, if any.
//!
//! Rust reflections of WebIDL operations (methods)
//! -----------------------------------------------
//!
//! A WebIDL operation is turned into one method for every overload.
//! The first overload gets the base name, and consecutive overloads have an
//! underscore appended to the name.
//!
//! The base name of the Rust method is simply the name of the WebIDL operation
//! with the first letter converted to uppercase.
//!
//! Rust reflections of WebIDL attributes
//! -------------------------------------
//!
//! A WebIDL attribute is turned into a pair of methods: one for the getter and
//! one for the setter. A readonly attribute only has a getter and no setter.
//!
//! The getter's name is the name of the attribute with the first letter
//! converted to uppercase. It has `Get` prepended to it if the type of the
//! attribute is nullable or if the getter can throw.
//!
//! The method signature for the getter looks just like an operation with no
//! arguments and the attribute's type as the return type.
//!
//! The setter's name is `Set` followed by the name of the attribute with the
//! first letter converted to uppercase. The method signature looks just like
//! an operation with a void return value and a single argument whose type is
//! the attribute's type.
//!
//! Rust reflections of WebIDL constructors
//! ---------------------------------------
//!
//! A WebIDL constructor is turned into a static class method named
//! `Constructor`. The arguments of this method will be the arguments of the
//! WebIDL constructor, with a `GlobalRef` for the relevant global prepended.
//! The return value of the constructor for MyInterface is exactly the same as
//! that of a method returning an instance of MyInterface. Constructors are
//! always [allowed to throw](#throwing-exceptions).
//!
//! Rust reflections of WebIDL types
//! --------------------------------
//!
//! The exact Rust representation for WebIDL types can depend on the precise
//! way that they're being used (e.g., return values and arguments might have
//! different representations).
//!
//! Optional arguments which do not have a default value are represented by
//! wrapping `Option<T>` around the representation of the argument type.
//! Optional arguments which do have a default value are represented by the
//! argument type itself, set to the default value if the argument was not in
//! fact passed in.
//!
//! Variadic WebIDL arguments are represented by wrapping a `Vec<T>` around the
//! representation of the argument type.
//!
//! See [the type mapping for particular types](conversions/index.html).
//!
//! Rust reflections of stringifiers
//! --------------------------------
//!
//! *To be written.*
//!
//! Rust reflections of legacy callers
//! ---------------------------------
//!
//! Legacy callers are not yet implemented.
//!
//! Rust reflections of getters and setters
//! ---------------------------------------
//!
//! *To be written.*
//!
//! Throwing exceptions
//! ===================
//!
//! WebIDL methods, getters, and setters that need to throw exceptions need to
//! be explicitly marked as such with the `[Throws]`, `[GetterThrows]` and
//! `[SetterThrows]` custom attributes.
//!
//! `[Throws]` applies to both methods and attributes; for attributes it means
//! both the getter and the setter (if any) can throw. `[GetterThrows]` applies
//! only to attributes. `[SetterThrows]` applies only to writable attributes.
//!
//! The corresponding Rust methods will have the return value wrapped in
//! [`Fallible<T>`](error/type.Fallible.html). To throw an exception, simply
//! return `Err()` from the method with the appropriate [error value]
//! (error/enum.Error.html).

pub mod callback;
pub mod cell;
pub mod conversions;
pub mod error;
pub mod global;
pub mod js;
pub mod num;
pub mod proxyhandler;
pub mod refcounted;
pub mod str;
pub mod structuredclone;
pub mod trace;
pub mod utils;

/// Generated JS-Rust bindings.
#[allow(missing_docs, non_snake_case)]
pub mod codegen {
    // FIXME(#5853) we shouldn't need to
    // allow moved_no_move here
    #[allow(unrooted_must_root, moved_no_move)]
    pub mod Bindings {
        include!(concat!(env!("OUT_DIR"), "/Bindings/mod.rs"));
    }
    pub mod InterfaceTypes {
        include!(concat!(env!("OUT_DIR"), "/InterfaceTypes.rs"));
    }
    #[allow(unused_imports)]
    pub mod InheritTypes {
        include!(concat!(env!("OUT_DIR"), "/InheritTypes.rs"));
    }
    pub mod PrototypeList {
        include!(concat!(env!("OUT_DIR"), "/PrototypeList.rs"));
    }
    pub mod RegisterBindings {
        include!(concat!(env!("OUT_DIR"), "/RegisterBindings.rs"));
    }
    #[allow(non_camel_case_types, unused_imports, unused_variables)]
    pub mod UnionTypes {
        include!(concat!(env!("OUT_DIR"), "/UnionTypes.rs"));
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub use compile_error::*;
pub use syntax::parse::token::InternedString;
pub use syntax::ast::*;

use syntax::codemap::DUMMY_SP;
use std::rc::Rc;

pub struct AttributeValue<T>
{
  value: Option<T>,
  duplicate: DuplicateAttribute,
  span: Span
}

impl<T: Clone> AttributeValue<T>
{
  pub fn new(duplicate: DuplicateAttribute) -> AttributeValue<T>
  {
    AttributeValue {
      value: None,
      duplicate: duplicate,
      span: DUMMY_SP
    }
  }

  pub fn simple() -> AttributeValue<T>
  {
    AttributeValue::new(DuplicateAttribute::simple(Warn))
  }

  pub fn update(self, cx: &ExtCtxt, value: T, span: Span) -> AttributeValue<T>
  {
    let mut this = self;
    if this.value.is_some() {
      this.duplicate.issue(cx, this.span, span);
    } else {
      this.value = Some(value);
      this.span = span;
    }
    this
  }

  pub fn value_or(&self, default: T) -> T
  {
    match self.value {
      None => default,
      Some(ref value) => value.clone()
    }
  }
}

pub struct AttributeInfo
{
  pub name: InternedString,
  pub desc: &'static str,
  pub model: AttributeModel
}

impl AttributeInfo
{
  pub fn new(name: &'static str, desc: &'static str,
    model: AttributeModel) -> AttributeInfo
  {
    AttributeInfo {
      name: InternedString::new(name),
      desc: desc,
      model: model
    }
  }

  pub fn simple(name: &'static str, desc: &'static str) -> AttributeInfo
  {
    AttributeInfo::new(name, desc, NoProperty(AttributeValue::simple()))
  }

  pub fn update(self, model: AttributeModel) -> AttributeInfo
  {
    let mut this = self;
    this.model = model;
    this
  }
}

pub enum AttributeModel
{
  NoProperty(AttributeValue<bool>),
  KeyValue(AttributeLitModel),
  SubAttribute(AttributeDict)
}

pub enum AttributeLitModel
{
  MLitStr(AttributeValue<(InternedString, StrStyle)>),
  MLitBinary(AttributeValue<Rc<Vec<u8>>>),
  MLitByte(AttributeValue<u8>),
  MLitChar(AttributeValue<char>),
  MLitInt(AttributeValue<(u64, LitIntType)>),
  MLitFloat(AttributeValue<(InternedString, FloatTy)>),
  MLitFloatUnsuffixed(AttributeValue<InternedString>),
  MLitNil(AttributeValue<()>),
  MLitBool(AttributeValue<bool>)
}

pub struct AttributeDict
{
  dict: Vec<AttributeInfo>
}

impl AttributeDict
{
  pub fn new(dict: Vec<AttributeInfo>) -> AttributeDict
  {
    AttributeDict {
      dict: dict
    }
  }

  pub fn move_map(self, f: |AttributeInfo| -> AttributeInfo) -> AttributeDict
  {
    let mut this = self;
    this.dict = this.dict.move_iter().map(f).collect();
    this
  }

  pub fn push(&mut self, attr: AttributeInfo)
  {
    self.dict.push(attr);
  }

  // fn attribute_doc(&self)
  // {
  //   let mut doc = format!("Attribute `#[{}(<attribute list>)]`: {}\n",
  //       self.root_name.get(), self.root_desc);
  //   for info in self.infos.iter() {
  //     doc.add(format!("  * `#[{}({})]`: {}\n",
  //       self.root_name.get(), info.name, info.desc));
  //   }
  //   self.cx.parse_sess.span_diagnostic.handler.note(doc.as_slice());
  // }
}

impl AttributeLitModel
{
  pub fn to_lit_printer(&self) -> LitTypePrinter
  {
    match *self {
      MLitStr(_) => PLitStr,
      MLitBinary(_) => PLitBinary,
      MLitByte(_) => PLitByte,
      MLitChar(_) => PLitChar,
      MLitInt(_) => PLitInt,
      MLitFloat(_) => PLitFloat,
      MLitFloatUnsuffixed(_) => PLitFloatUnsuffixed,
      MLitNil(_) => PLitNil,
      MLitBool(_) => PLitBool
    }
  }
}

pub fn lit_to_lit_printer(lit: &Lit_) -> LitTypePrinter
{
  match *lit {
    LitStr(_, _) => PLitStr,
    LitBinary(_) => PLitBinary,
    LitByte(_) => PLitByte,
    LitChar(_) => PLitChar,
    LitInt(_, _) => PLitInt,
    LitFloat(_, _) => PLitFloat,
    LitFloatUnsuffixed(_) => PLitFloatUnsuffixed,
    LitNil => PLitNil,
    LitBool(_) => PLitBool
  }
}

pub enum LitTypePrinter
{
  PLitStr,
  PLitBinary,
  PLitByte,
  PLitChar,
  PLitInt,
  PLitFloat,
  PLitFloatUnsuffixed,
  PLitNil,
  PLitBool
}

impl LitTypePrinter
{
  pub fn type_to_str(&self) -> &'static str
  {
    match *self {
      PLitStr => "string",
      PLitBinary => "binary",
      PLitByte => "byte",
      PLitChar => "char",
      PLitInt => "int",
      PLitFloat => "float",
      PLitFloatUnsuffixed => "unsuffixed float",
      PLitNil => "nil",
      PLitBool => "boolean"
    }
  }

  pub fn type_example_to_str(&self) -> &'static str
  {
    match *self {
      PLitStr => "\"hello world\"",
      PLitBinary => "0b01010101",
      PLitByte => "b'9'",
      PLitChar => "'a'",
      PLitInt => "38",
      PLitFloat => "0.01f32",
      PLitFloatUnsuffixed => "0.1",
      PLitNil => "()",
      PLitBool => "true"
    }
  }
}
<commit_msg>[Model] Add way to access the underlying value of the model.<commit_after>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

pub use compile_error::*;
pub use syntax::parse::token::InternedString;
pub use syntax::ast::*;

use syntax::codemap::DUMMY_SP;
use std::rc::Rc;

pub struct AttributeValue<T>
{
  value: Option<T>,
  duplicate: DuplicateAttribute,
  span: Span
}

impl<T: Clone> AttributeValue<T>
{
  pub fn new(duplicate: DuplicateAttribute) -> AttributeValue<T>
  {
    AttributeValue {
      value: None,
      duplicate: duplicate,
      span: DUMMY_SP
    }
  }

  pub fn simple() -> AttributeValue<T>
  {
    AttributeValue::new(DuplicateAttribute::simple(Warn))
  }

  pub fn update(self, cx: &ExtCtxt, value: T, span: Span) -> AttributeValue<T>
  {
    let mut this = self;
    if this.value.is_some() {
      this.duplicate.issue(cx, this.span, span);
    } else {
      this.value = Some(value);
      this.span = span;
    }
    this
  }

  pub fn value_or(&self, default: T) -> T
  {
    match self.value {
      None => default,
      Some(ref value) => value.clone()
    }
  }
}

pub struct AttributeInfo
{
  pub name: InternedString,
  pub desc: &'static str,
  pub model: AttributeModel
}

impl AttributeInfo
{
  pub fn new(name: &'static str, desc: &'static str,
    model: AttributeModel) -> AttributeInfo
  {
    AttributeInfo {
      name: InternedString::new(name),
      desc: desc,
      model: model
    }
  }

  pub fn simple(name: &'static str, desc: &'static str) -> AttributeInfo
  {
    AttributeInfo::new(name, desc, NoProperty(AttributeValue::simple()))
  }

  pub fn update(self, model: AttributeModel) -> AttributeInfo
  {
    let mut this = self;
    this.model = model;
    this
  }

  pub fn plain_value<'a>(&'a self) -> &'a AttributeValue<bool>
  {
    match self.model {
      NoProperty(ref v) => v,
      _ => fail!("No plain value for the current attribute.")
    }
  }

  pub fn sub_model<'a>(&'a self) -> &'a AttributeDict
  {
    match self.model {
      SubAttribute(ref dict) => dict,
      _ => fail!("No sub value for the attribute.")
    }
  }
}

pub enum AttributeModel
{
  NoProperty(AttributeValue<bool>),
  KeyValue(AttributeLitModel),
  SubAttribute(AttributeDict)
}

pub enum AttributeLitModel
{
  MLitStr(AttributeValue<(InternedString, StrStyle)>),
  MLitBinary(AttributeValue<Rc<Vec<u8>>>),
  MLitByte(AttributeValue<u8>),
  MLitChar(AttributeValue<char>),
  MLitInt(AttributeValue<(u64, LitIntType)>),
  MLitFloat(AttributeValue<(InternedString, FloatTy)>),
  MLitFloatUnsuffixed(AttributeValue<InternedString>),
  MLitNil(AttributeValue<()>),
  MLitBool(AttributeValue<bool>)
}

pub struct AttributeDict
{
  dict: Vec<AttributeInfo>
}

impl AttributeDict
{
  pub fn new(dict: Vec<AttributeInfo>) -> AttributeDict
  {
    AttributeDict {
      dict: dict
    }
  }

  pub fn move_map(self, f: |AttributeInfo| -> AttributeInfo) -> AttributeDict
  {
    let mut this = self;
    this.dict = this.dict.move_iter().map(f).collect();
    this
  }

  pub fn push(&mut self, attr: AttributeInfo)
  {
    self.dict.push(attr);
  }

  pub fn get<'a>(&'a self, name: &'static str) -> &'a AttributeInfo
  {
    let interned = InternedString::new(name);
    for info in self.dict.iter() {
      if info.name == interned {
        return info;
      }
    }
    fail!("Try to get an attribute that doesn't exist.")
  }

  pub fn plain_value<'a>(&'a self, name: &'static str) -> &'a AttributeValue<bool>
  {
    self.get(name).plain_value()
  }

  pub fn sub_model<'a>(&'a self, name: &'static str) -> &'a AttributeDict
  {
    self.get(name).sub_model()
  }

  pub fn plain_value_or(&self, name: &'static str, def: bool) -> bool
  {
    self.plain_value(name).value_or(def)
  }

  // fn attribute_doc(&self)
  // {
  //   let mut doc = format!("Attribute `#[{}(<attribute list>)]`: {}\n",
  //       self.root_name.get(), self.root_desc);
  //   for info in self.infos.iter() {
  //     doc.add(format!("  * `#[{}({})]`: {}\n",
  //       self.root_name.get(), info.name, info.desc));
  //   }
  //   self.cx.parse_sess.span_diagnostic.handler.note(doc.as_slice());
  // }
}

impl AttributeLitModel
{
  pub fn to_lit_printer(&self) -> LitTypePrinter
  {
    match *self {
      MLitStr(_) => PLitStr,
      MLitBinary(_) => PLitBinary,
      MLitByte(_) => PLitByte,
      MLitChar(_) => PLitChar,
      MLitInt(_) => PLitInt,
      MLitFloat(_) => PLitFloat,
      MLitFloatUnsuffixed(_) => PLitFloatUnsuffixed,
      MLitNil(_) => PLitNil,
      MLitBool(_) => PLitBool
    }
  }
}

pub fn lit_to_lit_printer(lit: &Lit_) -> LitTypePrinter
{
  match *lit {
    LitStr(_, _) => PLitStr,
    LitBinary(_) => PLitBinary,
    LitByte(_) => PLitByte,
    LitChar(_) => PLitChar,
    LitInt(_, _) => PLitInt,
    LitFloat(_, _) => PLitFloat,
    LitFloatUnsuffixed(_) => PLitFloatUnsuffixed,
    LitNil => PLitNil,
    LitBool(_) => PLitBool
  }
}

pub enum LitTypePrinter
{
  PLitStr,
  PLitBinary,
  PLitByte,
  PLitChar,
  PLitInt,
  PLitFloat,
  PLitFloatUnsuffixed,
  PLitNil,
  PLitBool
}

impl LitTypePrinter
{
  pub fn type_to_str(&self) -> &'static str
  {
    match *self {
      PLitStr => "string",
      PLitBinary => "binary",
      PLitByte => "byte",
      PLitChar => "char",
      PLitInt => "int",
      PLitFloat => "float",
      PLitFloatUnsuffixed => "unsuffixed float",
      PLitNil => "nil",
      PLitBool => "boolean"
    }
  }

  pub fn type_example_to_str(&self) -> &'static str
  {
    match *self {
      PLitStr => "\"hello world\"",
      PLitBinary => "0b01010101",
      PLitByte => "b'9'",
      PLitChar => "'a'",
      PLitInt => "38",
      PLitFloat => "0.01f32",
      PLitFloatUnsuffixed => "0.1",
      PLitNil => "()",
      PLitBool => "true"
    }
  }
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/MD5/Implementation
/*
 * Ported from C - Simple MD5 implementation
* on Wikipedia https://en.wikipedia.org/wiki/MD5
*/
use std::iter::range_step;
use std::vec::Vec;
use std::fmt::{Show, Formatter, Result};

#[cfg(not(test))]
fn main() {
    let inputs=
    [bytes!("a"),
    bytes!("abc"),
    bytes!("message digest"),
    bytes!("abcdefghijklmnopqrstuvwxyz"),
    bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),
    bytes!("12345678901234567890123456789012345678901234567890123456789012345678901234567890")];

    for &input in inputs.iter() {
        println!("{}", md5(input));
    }
}

// Constants are the integer part of the sines of integers (in radians) * 2^32.
static k:[u32,..64] = [
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee ,
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501 ,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be ,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821 ,
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa ,
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8 ,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed ,
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a ,
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c ,
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70 ,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05 ,
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665 ,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039 ,
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1 ,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1 ,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 ];

// r specifies the per-round shift amounts
static r:[u32,..64] = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
                      5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20,
                      4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
                      6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21];

// "newtype" for [u8,..16] to specify it's a MD5 hash
struct MD5([u8,..16]);
impl Show for MD5 {
    fn fmt(&self, f: &mut Formatter) -> Result {
        let MD5(md5)=*self;
        for b in md5.iter() {
            try!(write!(f, "{:02x}", *b));
        }
        Ok(())
    }
}

// leftrotate function definition
#[inline]
fn left_rotate(x: u32, c: u32) -> u32 {
    (x << c) | (x >> (32 - c))
}

fn to_bytes(val: u64) -> [u8,..8]
{
    let mut tmp:[u8,..8] = [0u8,..8];
    for i in range (0u, 8) {
        tmp[i] = (val >> (8*i)) as u8;
    }
    tmp
}

fn md5(initial_msg: &[u8]) -> MD5
{
    let initial_len=initial_msg.len() as u64;

    // These vars will contain the hash
    let mut h:[u32,..4]=[0x67452301u32, 0xefcdab89, 0x98badcfe, 0x10325476];

     //Pre-processing:
    //append "1" bit to message
    //append "0" bits until message length in bits ≡ 448 (mod 512)
    //append length mod (2^64) to message
    let mut new_len=initial_len;
    while new_len % (512/8) != 448/8 {
        new_len+=1;
    }

    { // new block (so msg is freed as soon as not needed any longer)
        let mut msg = Vec::<u8>::from_slice(initial_msg);
        msg.push(0x80u8); // append the "1" bit; most significant bit is "first"

        for _ in range (initial_len + 1, new_len) {
            msg.push(0); // append "0" bits
        }

        // append the len in bits at the end of the buffer.
        let msg=msg.append(to_bytes(initial_len << 3));

        assert_eq!(msg.len() % 64, 0);

        let mut w:[u32,..16] = [0u32,..16];
        // Process the message in successive 512-bit chunks:
        //for each 512-bit chunk of message:
        for offset in range_step(0u64, new_len, (512/8)) {
            // break chunk into sixteen 32-bit words w[j], 0 ≤ j ≤ 15
            for i in range(0u32, 16) {
                let j = i as uint * 4 + offset as uint;
                w[i as uint] =
                        (*msg.get(j)   as u32)      |
                        (*msg.get(j+1) as u32) <<8  |
                        (*msg.get(j+2) as u32) <<16 |
                         *msg.get(j+3) as u32  <<24;
            }
            //println!("chunk {}", w);
            // Initialize hash value for this chunk:
            let (mut a, mut b, mut c, mut d) = (h[0], h[1], h[2], h[3]);

            // Main loop:
            for ind in range(0u, 64) {
                let (f,g) = match ind {
                    i @ 0..15   => ( (b & c) | ((!b) & d), //f
                                    i ),                   //g
                    i @ 16..31  => ( (d & b) | ((!d) & c),
                                    (5*i + 1) % 16 ),
                    i @ 32..47  => ( b ^ c ^ d,
                                    (3*i + 5) % 16 ),
                    i @ _       => ( c ^ (b | (!d)),
                                    (7*i) % 16 )
                };

                let temp = d;
                d = c;
                c = b;
                b = b + left_rotate((a + f + k[ind] + w[g]), r[ind]);
                a = temp;
            }

            // Add this chunk's hash to result so far:
            h[0] += a;
            h[1] += b;
            h[2] += c;
            h[3] += d;
        }
    } // cleanup (end block, msg is freed)

    //var char digest[16] := h0 append h1 append h2 append h3 //(Output is in little-endian)
    let mut digest: [u8,..16]=[0u8,..16];
    for (i, s) in h.iter().enumerate() {
        digest[i*4] = (*s ) as u8;
        digest[i*4+1] = (*s >> 8) as u8;
        digest[i*4+2] = (*s >> 16) as u8;
        digest[i*4+3] = (*s >> 24) as u8;
    }
    MD5(digest)
}

#[test]
fn helper_fns() {
    assert_eq!(64, left_rotate(8, 3));

    let exp:[u8,..8] = [64u8, 226, 1, 0, 0, 0, 0, 0];
    assert!(to_bytes(123456) == exp);
}

#[test]
fn known_hashes() {
    let in_out=
    [(bytes!(""),
        "d41d8cd98f00b204e9800998ecf8427e"),
    (bytes!("a"),
        "0cc175b9c0f1b6a831c399e269772661"),
    (bytes!("abc"),
        "900150983cd24fb0d6963f7d28e17f72"),
    (bytes!("message digest"),
        "f96b697d7cb7938d525a2f31aaf161d0"),
    (bytes!("abcdefghijklmnopqrstuvwxyz"),
        "c3fcd3d76192e4007dfb496cca67e13b"),
    (bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),
        "d174ab98d277d9f5a5611c2c9f419d9f"),
    (bytes!("12345678901234567890123456789012345678901234567890123456789012345678901234567890"),
        "57edf4a22be3c955ac49da2e2107b67a")];

    for &(i,o) in in_out.iter() {
        let m=md5(i);
        assert_eq!(format!("{}", m), o.to_string());
    }
}<commit_msg>removed reduntant types<commit_after>// Implements http://rosettacode.org/wiki/MD5/Implementation
/*
 * Ported from C - Simple MD5 implementation
* on Wikipedia https://en.wikipedia.org/wiki/MD5
*/
use std::iter::range_step;
use std::vec::Vec;
use std::fmt::{Show, Formatter, Result};

#[cfg(not(test))]
fn main() {
    let inputs=
    [bytes!("a"),
    bytes!("abc"),
    bytes!("message digest"),
    bytes!("abcdefghijklmnopqrstuvwxyz"),
    bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),
    bytes!("12345678901234567890123456789012345678901234567890123456789012345678901234567890")];

    for &input in inputs.iter() {
        println!("{}", md5(input));
    }
}

// Constants are the integer part of the sines of integers (in radians) * 2^32.
static k:[u32,..64] = [
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee ,
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501 ,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be ,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821 ,
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa ,
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8 ,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed ,
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a ,
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c ,
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70 ,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05 ,
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665 ,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039 ,
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1 ,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1 ,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 ];

// r specifies the per-round shift amounts
static r:[u32,..64] = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
                      5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20,
                      4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
                      6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21];

// "newtype" for [u8,..16] to specify it's a MD5 hash
struct MD5([u8,..16]);
impl Show for MD5 {
    fn fmt(&self, f: &mut Formatter) -> Result {
        let MD5(md5)=*self;
        for b in md5.iter() {
            try!(write!(f, "{:02x}", *b));
        }
        Ok(())
    }
}

// leftrotate function definition
#[inline]
fn left_rotate(x: u32, c: u32) -> u32 {
    (x << c) | (x >> (32 - c))
}

fn to_bytes(val: u64) -> [u8,..8]
{
    let mut tmp:[u8,..8] = [0u8,..8];
    for i in range (0u, 8) {
        tmp[i] = (val >> (8*i)) as u8;
    }
    tmp
}

fn md5(initial_msg: &[u8]) -> MD5
{
    let initial_len=initial_msg.len() as u64;

    // These vars will contain the hash
    let mut h:[u32,..4]=[0x67452301u32, 0xefcdab89, 0x98badcfe, 0x10325476];

     //Pre-processing:
    //append "1" bit to message
    //append "0" bits until message length in bits ≡ 448 (mod 512)
    //append length mod (2^64) to message
    let mut new_len=initial_len;
    while new_len % (512/8) != 448/8 {
        new_len+=1;
    }

    { // new block (so msg is freed as soon as not needed any longer)
        let mut msg = Vec::<u8>::from_slice(initial_msg);
        msg.push(0x80u8); // append the "1" bit; most significant bit is "first"

        for _ in range (initial_len + 1, new_len) {
            msg.push(0); // append "0" bits
        }

        // append the len in bits at the end of the buffer.
        let msg=msg.append(to_bytes(initial_len << 3));

        assert_eq!(msg.len() % 64, 0);

        let mut w:[u32,..16] = [0u32,..16];
        // Process the message in successive 512-bit chunks:
        //for each 512-bit chunk of message:
        for offset in range_step(0u64, new_len, (512/8)) {
            // break chunk into sixteen 32-bit words w[j], 0 ≤ j ≤ 15
            for i in range(0u32, 16) {
                let j = i as uint * 4 + offset as uint;
                w[i as uint] =
                        (*msg.get(j)   as u32)      |
                        (*msg.get(j+1) as u32) <<8  |
                        (*msg.get(j+2) as u32) <<16 |
                         *msg.get(j+3) as u32  <<24;
            }
            //println!("chunk {}", w);
            // Initialize hash value for this chunk:
            let (mut a, mut b, mut c, mut d) = (h[0], h[1], h[2], h[3]);

            // Main loop:
            for ind in range(0u, 64) {
                let (f,g) = match ind {
                    i @ 0..15   => ( (b & c) | ((!b) & d), //f
                                    i ),                   //g
                    i @ 16..31  => ( (d & b) | ((!d) & c),
                                    (5*i + 1) % 16 ),
                    i @ 32..47  => ( b ^ c ^ d,
                                    (3*i + 5) % 16 ),
                    i @ _       => ( c ^ (b | (!d)),
                                    (7*i) % 16 )
                };

                let temp = d;
                d = c;
                c = b;
                b = b + left_rotate((a + f + k[ind] + w[g]), r[ind]);
                a = temp;
            }

            // Add this chunk's hash to result so far:
            h[0] += a;
            h[1] += b;
            h[2] += c;
            h[3] += d;
        }
    } // cleanup (end block, msg is freed)

    //var char digest[16] := h0 append h1 append h2 append h3 //(Output is in little-endian)
    let mut digest = [0u8,..16];
    for (i, s) in h.iter().enumerate() {
        digest[i*4] = (*s ) as u8;
        digest[i*4+1] = (*s >> 8) as u8;
        digest[i*4+2] = (*s >> 16) as u8;
        digest[i*4+3] = (*s >> 24) as u8;
    }
    MD5(digest)
}

#[test]
fn helper_fns() {
    assert_eq!(64, left_rotate(8, 3));

    let exp:[u8,..8] = [64u8, 226, 1, 0, 0, 0, 0, 0];
    assert!(to_bytes(123456) == exp);
}

#[test]
fn known_hashes() {
    let in_out=
    [(bytes!(""),
        "d41d8cd98f00b204e9800998ecf8427e"),
    (bytes!("a"),
        "0cc175b9c0f1b6a831c399e269772661"),
    (bytes!("abc"),
        "900150983cd24fb0d6963f7d28e17f72"),
    (bytes!("message digest"),
        "f96b697d7cb7938d525a2f31aaf161d0"),
    (bytes!("abcdefghijklmnopqrstuvwxyz"),
        "c3fcd3d76192e4007dfb496cca67e13b"),
    (bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),
        "d174ab98d277d9f5a5611c2c9f419d9f"),
    (bytes!("12345678901234567890123456789012345678901234567890123456789012345678901234567890"),
        "57edf4a22be3c955ac49da2e2107b67a")];

    for &(i,o) in in_out.iter() {
        let m=md5(i);
        assert_eq!(format!("{}", m), o.to_string());
    }
}
<|endoftext|>