<commit_before>//! Symbol- and name-storage facilities.
//!
//! This is based on [Servo's string-cache
//! library](https://github.com/servo/string-cache); at the moment it's very
//! lifetime-unsafe for `Pooled` instances.
use std;
use std::fmt;
use std::slice::bytes;
use std::hash::{hash, Hash, Hasher, SipHasher};
use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::borrow::ToOwned;

use super::util::intrusive;

#[macro_use]
mod nameable;
pub use self::nameable::Nameable;

/// Methods required of `unpacked` types.
pub trait PackFormat {
    /// Pack an unpacked symbol in the implementing format into a generic
    /// Symbol object.
    fn pack(&self) -> Symbol;

    /// Unpack a generic Symbol into the implementing format.  This function is
    /// marked as `unsafe` because the caller must verify that the symbol is
    /// indeed packed by the receiver's implementation.
    unsafe fn unpack(sym: &Symbol) -> Self;

    /// Fetch a `&str` slice from a symbol packed in the implementing format.
    /// This function is marked as `unsafe` because the caller must verify that
    /// the symbol is indeed packed by the receiver's implementation.
    unsafe fn as_slice_from<'t>(sym: &'t Symbol) -> &'t str;
}

/* ****************************************************************
 * Pool
 */
/// A collection of symbols.
pub struct Pool {
    refcount: usize,
    map:  BTreeMap<u64,String>
}

impl Pool {
    /// Create a new symbol pool.
    pub fn new() -> Pool {
        Pool{refcount: 1, map: BTreeMap::new()}
    }
    /// Fetch a symbol corresponding to the given string.  If if
    pub fn symbol(&mut self, name: &str) -> Symbol {
        if name.len() <= INLINE_SYMBOL_MAX_LEN
        { Inline::new(name).pack() }
        else { let hsh = hash::<_, SipHasher>(&name) << 1;
               if ! self.map.contains_key(&hsh) {
                   self.map.insert(hsh, name.to_owned());
               }

               Pooled::new(hsh, self).pack()
        }
    }
}

default_refcounted_impl!(Pool, refcount);

/* ****************************************************************
 * Symbol
 */
/// An atomic `Copy`able string.  Symbol either encodes a short string
/// directly, or stores it in an external Pool.
#[derive(Debug)]
pub struct Symbol {
    value: [u64; 2]
}
impl Copy for Symbol {}

impl Symbol {
    /// Convert the symbol to its unpacked representation.
    #[inline(always)]
    pub fn unpack(&self) -> Unpacked
    { <Unpacked as PackFormat>::unpack(self) }
}

    /// Get symbol's pack format.
    #[inline(always)]
    pub fn type_of(&self) -> Type {
        match (self.value[0] & 0x01) as u8 {
            INLINE => Type::INLINE,
            POOLED => Type::POOLED,
            _ => unreachable!()
        }
    }

}

impl std::str::Str for Symbol {
    fn as_slice<'t>(&'t self) -> &'t str { <Unpacked as PackFormat>::as_slice_from(self) }
}

impl Nameable for Symbol {
    fn name(&self) -> Symbol { *self }
}

impl Hash for Symbol {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.as_slice().hash(state);
    }
}

impl fmt::Display for Symbol {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.as_slice())
    }
}

impl Eq for Symbol {}
impl PartialEq<Symbol> for Symbol
{
    fn eq(&self, other: &Symbol) -> bool
    {
        self.value == other.value
    }
}

/* ****************************************************************
 * Inline
 */
const INLINE_SYMBOL_MAX_LEN: usize = 15;//std::mem::size_of::<Symbol>() - 1;

/// Data format for symbols packed entirely into a `Symbol` instance.
#[derive(Debug)]
pub struct Inline{len: u8, data: [u8; INLINE_SYMBOL_MAX_LEN]}

impl Inline {
    /// Create a new Inline-format symbol using the given string.
    pub fn new(name: &str) -> Self {
        panic_unless!(name.len() <= INLINE_SYMBOL_MAX_LEN,
                      "Argument to Inline::new (length {}) exceeds maximum length ({}) for an inlined symbol",
                      name.len(), INLINE_SYMBOL_MAX_LEN);
        let mut buf: [u8; INLINE_SYMBOL_MAX_LEN] = [0; INLINE_SYMBOL_MAX_LEN];

        bytes::copy_memory(buf.as_mut_slice(), name.as_bytes());
        Inline{len: name.len() as u8, data: buf}
    }
}

impl std::str::Str for Inline {
    fn as_slice<'t>(&'t self) -> &'t str {
        let src: &[u8] = self.data.as_slice();
        std::str::from_utf8(&src[..(self.len as usize)]).unwrap()
    }
}

impl PackFormat for Inline {
    // Convert the Inline symbol into a generic packed representation.
    fn pack(&self) -> Symbol {
        unsafe {
            let mut out = Symbol{ value: [0; 2] };
            let mut dest: &mut [u8; 16] = std::mem::transmute(&mut out.value);
            dest[0] = (self.len << 1) | INLINE;
            bytes::copy_memory(&mut dest[1..], &self.data);
            out
        }
    }
    fn unpack(sym: &Symbol) -> Self {
        let mut out = Inline{len: 0, data: [0; INLINE_SYMBOL_MAX_LEN]};
        let src: &[u8;16] =
            unsafe { std::mem::transmute(&sym.value) };

        panic_unless!(src[0] & TAG_MASK == INLINE, "Invalid tag bit for inlined symbol!");
        out.len = src[0] >> 1;
        panic_unless!(out.len <= INLINE_SYMBOL_MAX_LEN as u8,
                      "Symbol length ({}) exceeds maximum ({}) for inlined symbol",
                      out.len, INLINE_SYMBOL_MAX_LEN);
        bytes::copy_memory(out.data.as_mut_slice(), &src[1..(out.len as usize + 1)]);

        out
    }

    fn as_slice_from<'t>(sym: &'t Symbol) -> &'t str {
        let src: &[u8; 16] = unsafe { std::mem::transmute(&sym.value) };
        panic_unless!(src[0] & TAG_MASK == INLINE, "Invalid tag bit for inlined symbol!");
        let len: usize = (src[0] >> 1) as usize;
        panic_unless!(len <= INLINE_SYMBOL_MAX_LEN,
                      "Symbol length ({}) exceeds maximum ({}) for inlined symbol",
                      len, INLINE_SYMBOL_MAX_LEN);

        std::str::from_utf8(&src[1..(len + 1)]).unwrap()
    }
}

impl std::cmp::Eq for Inline {}
impl std::cmp::PartialEq for Inline {
    fn eq(&self, other: &Self) -> bool {
        self.len == other.len && self.data == other.data
    }
}

/* ****************************************************************
 * Pooled
 */
/// Data format for symbols stored as references to a symbol pool.
#[derive(Debug)]
pub struct Pooled{key: u64, pool: *const Pool}

impl Pooled {
    #[inline(always)]
    pub fn new(key: u64, pool: *const Pool) -> Self {
        Pooled{key: key, pool: pool}
    }

}

impl std::str::Str for Pooled {
    fn as_slice<'u>(&'u self) -> &'u str {
        unsafe { (*self.pool).map[self.key].as_slice() }
    }
}

impl PackFormat for Pooled {
    fn pack(&self) -> Symbol {
        let mut val: [u64; 2] = [0; 2];
        val[0] = self.key  | POOLED as u64;
        val[1] = self.pool as u64;
        Symbol{value: val}
    }
    fn unpack(sym: &Symbol) -> Self {
        Pooled{key: sym.value[0],
               pool: unsafe { std::mem::transmute(sym.value[1] as *const Pool) }}
    }

    fn as_slice_from<'t>(sym: &'t Symbol) -> &'t str {
        panic_unless!(sym.value[0] & TAG_MASK as u64 == POOLED as u64,
                      "Invalid flag bit for pooled symbol");
        unsafe { std::mem::transmute::<_,&'t Pool>(sym.value[1] as *const Pool) }.
            map[sym.value[0]].as_slice()
    }
}

impl std::cmp::Eq for Pooled {}
impl std::cmp::PartialEq for Pooled {
    fn eq(&self, other: &Self) -> bool {
        self.key == other.key && self.pool as u64 == other.pool as u64
    }
}

/* ****************************************************************
 * Types
 */
const TAG_MASK: u8 = 0x01;
const POOLED: u8 = 0;
const INLINE: u8 = 1;

pub enum Type { INLINE = 0, POOLED = 1 }

impl std::cmp::Eq for Type {}
impl std::cmp::PartialEq for Type {
    fn eq(&self, other: &Self) -> bool {
        match *self { Type::INLINE => match *other { Type::INLINE => true, _ => false },
                      Type::POOLED => match *other { Type::POOLED => true, _ => false } }
    }
}

impl std::fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self { Type::INLINE => write!(f, "inline"),
                      Type::POOLED => write!(f, "pooled") }
    }
}

/* ****************************************************************
 * Unpacked
 */

/// A differentiated `Symbol`.
#[derive(Debug)]
pub enum Unpacked {
    /// Symbol stored inline in `Symbol`'s data fields.
    Inline(Inline),

    /// Symbol stored in a Pool
    Pooled(Pooled)
}

impl PackFormat for Unpacked {
    fn pack(&self) -> Symbol {
        match *self {
            Unpacked::Inline(ref x) => x.pack(),
            Unpacked::Pooled(ref x) => x.pack()
        }
    }

    fn unpack(sym: &Symbol) -> Unpacked {
        match sym.type_of() {
            Type::POOLED => Unpacked::Pooled(unsafe { <Pooled as PackFormat>::unpack(sym) }),
            Type::INLINE => Unpacked::Inline(unsafe { <Inline as PackFormat>::unpack(sym) }),
        }
    }

    fn as_slice_from<'t>(sym: &'t Symbol) -> &'t str {
        match sym.type_of() {
            Type::INLINE => unsafe { <Inline as PackFormat>::as_slice_from(sym) },
            Type::POOLED => unsafe { <Pooled as PackFormat>::as_slice_from(sym) }
        }
    }
}

impl std::str::Str for Unpacked {
    fn as_slice<'t>(&'t self) -> &'t str {
        match *self {
            Unpacked::Inline(ref x) => x.as_slice(),
            Unpacked::Pooled(ref x) => x.as_slice()
        }
    }
}

impl std::cmp::Eq for Unpacked {}
impl std::cmp::PartialEq for Unpacked {
    fn eq(&self, other: &Self) -> bool {
        match *self {
            Unpacked::Inline(ref si) =>
                match *other { Unpacked::Inline(ref oi) => si == oi, _ => false },
            Unpacked::Pooled(ref sp) =>
                match *other { Unpacked::Pooled(ref op) => sp == op, _ => false }
        }
    }
}

impl Unpacked {
}
<commit_msg>symbol: misc. remaining fixes<commit_after>//! Symbol- and name-storage facilities.
//!
//! This is based on [Servo's string-cache
//! library](https://github.com/servo/string-cache); at the moment it's very
//! lifetime-unsafe for `Pooled` instances.
use std;
use std::fmt;
use std::slice::bytes;
use std::hash::{hash, Hash, Hasher, SipHasher};
use std::collections::BTreeMap;
use std::borrow::ToOwned;

use super::util::intrusive;

#[macro_use]
pub mod nameable;
pub use self::nameable::Nameable;

/// Methods required of `unpacked` types.
pub trait PackFormat {
    /// Pack an unpacked symbol in the implementing format into a generic
    /// Symbol object.
    fn pack(&self) -> Symbol;

    /// Unpack a generic Symbol into the implementing format.  This function is
    /// marked as `unsafe` because the caller must verify that the symbol is
    /// indeed packed by the receiver's implementation.
    unsafe fn unpack(sym: &Symbol) -> Self;

    /// Fetch a `&str` slice from a symbol packed in the implementing format.
    /// This function is marked as `unsafe` because the caller must verify that
    /// the symbol is indeed packed by the receiver's implementation.
    unsafe fn as_slice_from<'t>(sym: &'t Symbol) -> &'t str;
}

/* ****************************************************************
 * Pool
 */
/// A collection of symbols.
#[derive(Debug)]
pub struct Pool {
    refcount: usize,
    map:  BTreeMap<u64,String>
}

impl Pool {
    /// Create a new symbol pool.
    pub fn new() -> Pool {
        Pool{refcount: 1, map: BTreeMap::new()}
    }
    /// Fetch a symbol corresponding to the given string.  If if
    pub fn symbol(&mut self, name: &str) -> Symbol {
        if name.len() <= INLINE_SYMBOL_MAX_LEN
        { Inline::new(name).pack() }
        else { let hsh = hash::<_, SipHasher>(&name) << 1;
               if ! self.map.contains_key(&hsh) {
                   self.map.insert(hsh, name.to_owned());
               }

               Pooled::new(hsh, self).pack()
        }
    }
}

default_refcounted_impl!(Pool, refcount);

/* ****************************************************************
 * Symbol
 */
/// An atomic `Copy`able string.  Symbol either encodes a short string
/// directly, or stores it in an external Pool.
#[derive(Debug)]
pub struct Symbol {
    value: [u64; 2]
}
impl Copy for Symbol {}

impl Symbol {
    /// Convert the symbol to its unpacked representation.
    #[inline(always)]
    pub fn unpack(&self) -> Unpacked
    { unsafe { <Unpacked as PackFormat>::unpack(self) } }

    /// Get symbol's pack format.
    #[inline(always)]
    pub fn type_of(&self) -> Type {
        match (self.value[0] & 0x01) as u8 {
            INLINE => Type::INLINE,
            POOLED => Type::POOLED,
            _ => unreachable!()
        }
    }

}

impl std::str::Str for Symbol {
    fn as_slice<'t>(&'t self) -> &'t str { unsafe { <Unpacked as PackFormat>::as_slice_from(self) } }
}

impl Nameable for Symbol {
    fn name(&self) -> Symbol { *self }
}

impl Hash for Symbol {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.as_slice().hash(state);
    }
}

impl fmt::Display for Symbol {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.as_slice())
    }
}

impl Eq for Symbol {}
impl PartialEq<Symbol> for Symbol
{
    fn eq(&self, other: &Symbol) -> bool
    {
        self.value == other.value
    }
}

/* ****************************************************************
 * Inline
 */
const INLINE_SYMBOL_MAX_LEN: usize = 15;//std::mem::size_of::<Symbol>() - 1;

/// Data format for symbols packed entirely into a `Symbol` instance.
#[derive(Debug)]
pub struct Inline{len: u8, data: [u8; INLINE_SYMBOL_MAX_LEN]}

impl Inline {
    /// Create a new Inline-format symbol using the given string.
    pub fn new(name: &str) -> Self {
        panic_unless!(name.len() <= INLINE_SYMBOL_MAX_LEN,
                      "Argument to Inline::new (length {}) exceeds maximum length ({}) for an inlined symbol",
                      name.len(), INLINE_SYMBOL_MAX_LEN);
        let mut buf: [u8; INLINE_SYMBOL_MAX_LEN] = [0; INLINE_SYMBOL_MAX_LEN];

        bytes::copy_memory(buf.as_mut_slice(), name.as_bytes());
        Inline{len: name.len() as u8, data: buf}
    }
}

impl std::str::Str for Inline {
    fn as_slice<'t>(&'t self) -> &'t str {
        let src: &[u8] = self.data.as_slice();
        std::str::from_utf8(&src[..(self.len as usize)]).unwrap()
    }
}

impl PackFormat for Inline {
    // Convert the Inline symbol into a generic packed representation.
    fn pack(&self) -> Symbol {
        unsafe {
            let mut out = Symbol{ value: [0; 2] };
            let mut dest: &mut [u8; 16] = std::mem::transmute(&mut out.value);
            dest[0] = (self.len << 1) | INLINE;
            bytes::copy_memory(&mut dest[1..], &self.data);
            out
        }
    }
    fn unpack(sym: &Symbol) -> Self {
        let mut out = Inline{len: 0, data: [0; INLINE_SYMBOL_MAX_LEN]};
        let src: &[u8;16] =
            unsafe { std::mem::transmute(&sym.value) };

        panic_unless!(src[0] & TAG_MASK == INLINE, "Invalid tag bit for inlined symbol!");
        out.len = src[0] >> 1;
        panic_unless!(out.len <= INLINE_SYMBOL_MAX_LEN as u8,
                      "Symbol length ({}) exceeds maximum ({}) for inlined symbol",
                      out.len, INLINE_SYMBOL_MAX_LEN);
        bytes::copy_memory(out.data.as_mut_slice(), &src[1..(out.len as usize + 1)]);

        out
    }

    fn as_slice_from<'t>(sym: &'t Symbol) -> &'t str {
        let src: &[u8; 16] = unsafe { std::mem::transmute(&sym.value) };
        panic_unless!(src[0] & TAG_MASK == INLINE, "Invalid tag bit for inlined symbol!");
        let len: usize = (src[0] >> 1) as usize;
        panic_unless!(len <= INLINE_SYMBOL_MAX_LEN,
                      "Symbol length ({}) exceeds maximum ({}) for inlined symbol",
                      len, INLINE_SYMBOL_MAX_LEN);

        std::str::from_utf8(&src[1..(len + 1)]).unwrap()
    }
}

impl std::cmp::Eq for Inline {}
impl std::cmp::PartialEq for Inline {
    fn eq(&self, other: &Self) -> bool {
        self.len == other.len && self.data == other.data
    }
}

/* ****************************************************************
 * Pooled
 */
/// Data format for symbols stored as references to a symbol pool.
#[derive(Debug)]
pub struct Pooled{key: u64, pool: *const Pool}

impl Pooled {
    #[inline(always)]
    pub fn new(key: u64, pool: *const Pool) -> Self {
        Pooled{key: key, pool: pool}
    }

}

impl std::str::Str for Pooled {
    fn as_slice<'u>(&'u self) -> &'u str {
        unsafe { (*self.pool).map[self.key].as_slice() }
    }
}

impl PackFormat for Pooled {
    fn pack(&self) -> Symbol {
        let mut val: [u64; 2] = [0; 2];
        val[0] = self.key  | POOLED as u64;
        val[1] = self.pool as u64;
        Symbol{value: val}
    }
    fn unpack(sym: &Symbol) -> Self {
        Pooled{key: sym.value[0],
               pool: unsafe { std::mem::transmute(sym.value[1] as *const Pool) }}
    }

    fn as_slice_from<'t>(sym: &'t Symbol) -> &'t str {
        panic_unless!(sym.value[0] & TAG_MASK as u64 == POOLED as u64,
                      "Invalid flag bit for pooled symbol");
        unsafe { std::mem::transmute::<_,&'t Pool>(sym.value[1] as *const Pool) }.
            map[sym.value[0]].as_slice()
    }
}

impl std::cmp::Eq for Pooled {}
impl std::cmp::PartialEq for Pooled {
    fn eq(&self, other: &Self) -> bool {
        self.key == other.key && self.pool as u64 == other.pool as u64
    }
}

/* ****************************************************************
 * Types
 */
const TAG_MASK: u8 = 0x01;
const POOLED: u8 = 0;
const INLINE: u8 = 1;

pub enum Type { INLINE = 0, POOLED = 1 }

impl std::cmp::Eq for Type {}
impl std::cmp::PartialEq for Type {
    fn eq(&self, other: &Self) -> bool {
        match *self { Type::INLINE => match *other { Type::INLINE => true, _ => false },
                      Type::POOLED => match *other { Type::POOLED => true, _ => false } }
    }
}

impl std::fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self { Type::INLINE => write!(f, "inline"),
                      Type::POOLED => write!(f, "pooled") }
    }
}

/* ****************************************************************
 * Unpacked
 */

/// A differentiated `Symbol`.
#[derive(Debug)]
pub enum Unpacked {
    /// Symbol stored inline in `Symbol`'s data fields.
    Inline(Inline),

    /// Symbol stored in a Pool
    Pooled(Pooled)
}

impl PackFormat for Unpacked {
    fn pack(&self) -> Symbol {
        match *self {
            Unpacked::Inline(ref x) => x.pack(),
            Unpacked::Pooled(ref x) => x.pack()
        }
    }

    fn unpack(sym: &Symbol) -> Unpacked {
        match sym.type_of() {
            Type::POOLED => Unpacked::Pooled(unsafe { <Pooled as PackFormat>::unpack(sym) }),
            Type::INLINE => Unpacked::Inline(unsafe { <Inline as PackFormat>::unpack(sym) }),
        }
    }

    fn as_slice_from<'t>(sym: &'t Symbol) -> &'t str {
        match sym.type_of() {
            Type::INLINE => unsafe { <Inline as PackFormat>::as_slice_from(sym) },
            Type::POOLED => unsafe { <Pooled as PackFormat>::as_slice_from(sym) }
        }
    }
}

impl std::str::Str for Unpacked {
    fn as_slice<'t>(&'t self) -> &'t str {
        match *self {
            Unpacked::Inline(ref x) => x.as_slice(),
            Unpacked::Pooled(ref x) => x.as_slice()
        }
    }
}

impl std::cmp::Eq for Unpacked {}
impl std::cmp::PartialEq for Unpacked {
    fn eq(&self, other: &Self) -> bool {
        match *self {
            Unpacked::Inline(ref si) =>
                match *other { Unpacked::Inline(ref oi) => si == oi, _ => false },
            Unpacked::Pooled(ref sp) =>
                match *other { Unpacked::Pooled(ref op) => sp == op, _ => false }
        }
    }
}

impl Unpacked {
}
<|endoftext|>


<commit_before>use format::field::*;
use nom::{be_u8,be_u16,be_u32,be_u64};

pub const DESCRIPTION: &'static str = "{{name}} - {{major_version}}.{{minor_version}}.{{revision}}";

pub enum Class {
  {{#each specs.classes as |class| ~}}
    {{camel class.name}},
  {{/each ~}}
  None,
}

named!(pub parse<Class>,
  value!(Class::None)
);

{{#each specs.classes as |class|}}
  pub mod {{camel class.name}} {
    use super::Class;
    use format::field::*;
    use nom::{be_u8,be_u16,be_u32,be_u64};

    pub enum Methods {
      {{#each class.methods as |method| ~}}
        {{camel method.name}},
      {{/each ~}}
    }

    named!(pub parse<Class>,
      value!(Class::None)
    );

    {{#each class.methods as |method|}}
      pub struct {{camel method.name}} {
        {{#each method.arguments as |argument| ~}}
          pub {{snake argument.name}}: {{map_type argument}},
        {{/each ~}}

      }

      named!(parse_{{snake method.name}}<{{camel method.name}}>,
        do_parse!(
          {{#each method.arguments as |argument| ~}}
            {{snake argument.name}}: {{map_parser argument}} >>
          {{/each ~}}

          ({{camel method.name}} {
            {{#each method.arguments as |argument| ~}}
              {{snake argument.name}}: {{snake argument.name}},
            {{/each ~}}
          })
        )
      );
    {{/each}}
  }
{{/each}}
<commit_msg>generate enum members<commit_after>use format::field::*;
use nom::{be_u8,be_u16,be_u32,be_u64};

pub const DESCRIPTION: &'static str = "{{name}} - {{major_version}}.{{minor_version}}.{{revision}}";

pub enum Class {
  {{#each specs.classes as |class| ~}}
    {{camel class.name}}({{camel class.name}}Methods),
  {{/each ~}}
  None,
}

macro_rules! call_path (
  ($i: expr, $p: path) => ($p($i))
);

named!(pub parse_class<Class>,
  switch!(be_u16,
  {{#each specs.classes as |class| ~}}
    {{class.id}} => call!(parse_class_{{snake class.name}}) |
  {{/each ~}}
  _ => value!(Class::None)
  )
);

{{#each specs.classes as |class|}}
  pub enum {{camel class.name}}Methods {
    {{#each class.methods as |method| ~}}
      {{camel method.name}}({{camel class.name}}{{camel method.name}}),
    {{/each ~}}
    None,
  }

  named!(pub parse_class_{{snake class.name}}<Class>,
    switch!(be_u16,
      {{#each class.methods as |method| ~}}
      {{method.id}} => map!(call!(parse_class_{{snake class.name}}_method_{{snake method.name}}), |m| Class::{{camel class.name}}(m)) |
      {{/each ~}}
      _  =>  value!(Class::{{camel class.name}}({{camel class.name}}Methods::None))
    )
  );

  {{#each class.methods as |method|}}
    pub struct {{camel class.name}}{{camel method.name}} {
      {{#each method.arguments as |argument| ~}}
        pub {{snake argument.name}}: {{map_type argument}},
      {{/each ~}}

    }

    named!(parse_class_{{snake class.name}}_method_{{snake method.name}}<{{camel class.name}}Methods>,
      do_parse!(
        {{#each method.arguments as |argument| ~}}
          {{snake argument.name}}: {{map_parser argument}} >>
        {{/each ~}}

        ({{camel class.name}}Methods::{{camel method.name}}({{camel class.name}}{{camel method.name}} {
          {{#each method.arguments as |argument| ~}}
            {{snake argument.name}}: {{snake argument.name}},
          {{/each ~}}
        }))
      )
    );
  {{/each}}
{{/each}}
<|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/. */

#[cfg(target_os = "android")]
use android_injected_glue;
#[cfg(not(target_os = "android"))]
use std::env;
#[cfg(target_os = "android")]
use std::ffi::CStr;
use std::fs::File;
use std::io::{self, Read};
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};

lazy_static! {
    static ref CMD_RESOURCE_DIR: Arc<Mutex<Option<String>>> = {
        Arc::new(Mutex::new(None))
    };
}

pub fn set_resources_path(path: Option<String>) {
    let mut dir = CMD_RESOURCE_DIR.lock().unwrap();
    *dir = path;
}

#[cfg(target_os = "android")]
#[allow(unsafe_code)]
pub fn resources_dir_path() -> io::Result<PathBuf> {
    let dir = unsafe {
        CStr::from_ptr((*android_injected_glue::get_app().activity).externalDataPath)
    };
    Ok(PathBuf::from(dir.to_str().unwrap()))
}

#[cfg(not(target_os = "android"))]
pub fn resources_dir_path() -> io::Result<PathBuf> {
    let mut dir = CMD_RESOURCE_DIR.lock().unwrap();

    if let Some(ref path) = *dir {
        return Ok(PathBuf::from(path));
    }

    // FIXME: Find a way to not rely on the executable being
    // under `<servo source>[/$target_triple]/target/debug`
    // or `<servo source>[/$target_triple]/target/release`.
    let mut path = env::current_exe()?;
    // Follow symlink
    path = path.canonicalize()?;

    while path.pop() {
        path.push("resources");
        if path.is_dir() {
            break;
        }
        path.pop();
        // Check for Resources on mac when using a case sensitive filesystem.
        path.push("Resources");
        if path.is_dir() {
            break;
        }
        path.pop();
    }
    *dir = Some(path.to_str().unwrap().to_owned());
    Ok(path)
}

pub fn read_resource_file<P: AsRef<Path>>(relative_path: P) -> io::Result<Vec<u8>> {
    let mut path = resources_dir_path()?;
    path.push(relative_path);
    let mut file = File::open(&path)?;
    let mut data = Vec::new();
    file.read_to_end(&mut data)?;
    Ok(data)
}
<commit_msg>do not force resource_path on android<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/. */

#[cfg(target_os = "android")]
use android_injected_glue;
#[cfg(not(target_os = "android"))]
use std::env;
#[cfg(target_os = "android")]
use std::ffi::CStr;
use std::fs::File;
use std::io::{self, Read};
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};

lazy_static! {
    static ref CMD_RESOURCE_DIR: Arc<Mutex<Option<String>>> = {
        Arc::new(Mutex::new(None))
    };
}

pub fn set_resources_path(path: Option<String>) {
    let mut dir = CMD_RESOURCE_DIR.lock().unwrap();
    *dir = path;
}

#[cfg(target_os = "android")]
#[allow(unsafe_code)]
pub fn resources_dir_path() -> io::Result<PathBuf> {
    let mut dir = CMD_RESOURCE_DIR.lock().unwrap();

    if let Some(ref path) = *dir {
        return Ok(PathBuf::from(path));
    }

    let data_path = unsafe {
        CStr::from_ptr((*android_injected_glue::get_app().activity).externalDataPath)
    };
    let path = PathBuf::from(data_path.to_str().unwrap());
    *dir = Some(path.to_str().unwrap().to_owned());
    Ok(path)
}

#[cfg(not(target_os = "android"))]
pub fn resources_dir_path() -> io::Result<PathBuf> {
    let mut dir = CMD_RESOURCE_DIR.lock().unwrap();

    if let Some(ref path) = *dir {
        return Ok(PathBuf::from(path));
    }

    // FIXME: Find a way to not rely on the executable being
    // under `<servo source>[/$target_triple]/target/debug`
    // or `<servo source>[/$target_triple]/target/release`.
    let mut path = env::current_exe()?;
    // Follow symlink
    path = path.canonicalize()?;

    while path.pop() {
        path.push("resources");
        if path.is_dir() {
            break;
        }
        path.pop();
        // Check for Resources on mac when using a case sensitive filesystem.
        path.push("Resources");
        if path.is_dir() {
            break;
        }
        path.pop();
    }
    *dir = Some(path.to_str().unwrap().to_owned());
    Ok(path)
}

pub fn read_resource_file<P: AsRef<Path>>(relative_path: P) -> io::Result<Vec<u8>> {
    let mut path = resources_dir_path()?;
    path.push(relative_path);
    let mut file = File::open(&path)?;
    let mut data = Vec::new();
    file.read_to_end(&mut data)?;
    Ok(data)
}
<|endoftext|>


<commit_before>pub type Unit = usize;

#[derive(Debug, Clone)]
pub struct UnitGraph {
}

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

    /// Returns a unit representing when a quantity is unitless
    ///
    /// In lion programs, this is denoted '_
    pub fn unitless(&self) -> Unit {
        0 //TODO: Return a unit for the '_ unit
    }

    /// Returns the unique unit ID for the given unit name.
    /// New ID will be created and associated with the unit name if necessary
    ///
    /// Note: name must be given without "'", i.e. to lookup 'foo, use lookup("foo")
    pub fn lookup(&mut self, name: &str) -> Unit {
        0 //TODO
    }
}
<commit_msg>Ensuring empty unit names (incorrect parses) can never slip through<commit_after>pub type Unit = usize;

#[derive(Debug, Clone)]
pub struct UnitGraph {
}

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

    /// Returns a unit representing when a quantity is unitless
    ///
    /// In lion programs, this is denoted '_
    pub fn unitless(&self) -> Unit {
        0 //TODO: Return a unit for the '_ unit
    }

    /// Returns the unique unit ID for the given unit name.
    /// New ID will be created and associated with the unit name if necessary
    ///
    /// Note: name must be given without "'", i.e. to lookup 'foo, use lookup("foo")
    pub fn lookup(&mut self, name: &str) -> Unit {
        assert!(!name.is_empty(), "unit name cannot be empty");
        0 //TODO
    }
}

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

    #[test]
    #[should_panic(expected = "unit name cannot be empty")]
    fn lookup_empty() {
        let mut units = UnitGraph::new();
        units.lookup("");
    }
}
<|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 https://mozilla.org/MPL/2.0/. */

use crate::context::LayoutContext;
use crate::dom_traversal::{Contents, NodeExt};
use crate::flow::construct::ContainsFloats;
use crate::flow::float::FloatBox;
use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::Fragment;
use crate::geom::flow_relative::Vec2;
use crate::geom::{PhysicalPoint, PhysicalRect, PhysicalSize};
use crate::positioned::AbsolutelyPositionedBox;
use crate::positioned::PositioningContext;
use crate::replaced::ReplacedContent;
use crate::sizing::ContentSizesRequest;
use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside};
use crate::DefiniteContainingBlock;
use app_units::Au;
use euclid::default::{Point2D, Rect, Size2D};
use gfx_traits::print_tree::PrintTree;
use script_layout_interface::wrapper_traits::LayoutNode;
use servo_arc::Arc;
use style::dom::OpaqueNode;
use style::properties::{style_structs, ComputedValues};
use style::values::computed::Length;
use style_traits::CSSPixel;

pub struct BoxTreeRoot(BlockFormattingContext);

pub struct FragmentTreeRoot {
    /// The children of the root of the fragment tree.
    children: Vec<Fragment>,

    /// The scrollable overflow of the root of the fragment tree.
    scrollable_overflow: PhysicalRect<Length>,

    /// The containing block used in the layout of this fragment tree.
    initial_containing_block: PhysicalRect<Length>,
}

impl BoxTreeRoot {
    pub fn construct<'dom, Node>(context: &LayoutContext, root_element: Node) -> Self
    where
        Node: 'dom + Copy + LayoutNode + Send + Sync,
    {
        let (contains_floats, boxes) = construct_for_root_element(&context, root_element);
        Self(BlockFormattingContext {
            contains_floats: contains_floats == ContainsFloats::Yes,
            contents: BlockContainer::BlockLevelBoxes(boxes),
        })
    }
}

fn construct_for_root_element<'dom>(
    context: &LayoutContext,
    root_element: impl NodeExt<'dom>,
) -> (ContainsFloats, Vec<Arc<BlockLevelBox>>) {
    let style = root_element.style(context);
    let replaced = ReplacedContent::for_element(root_element);
    let box_style = style.get_box();

    let display_inside = match Display::from(box_style.display) {
        Display::None => return (ContainsFloats::No, Vec::new()),
        Display::Contents if replaced.is_some() => {
            // 'display: contents' computes to 'none' for replaced elements
            return (ContainsFloats::No, Vec::new());
        },
        // https://drafts.csswg.org/css-display-3/#transformations
        Display::Contents => DisplayInside::Flow,
        // The root element is blockified, ignore DisplayOutside
        Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { inside, .. }) => inside,
    };

    let contents = replaced.map_or(Contents::OfElement, Contents::Replaced);
    if box_style.position.is_absolutely_positioned() {
        (
            ContainsFloats::No,
            vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(
                AbsolutelyPositionedBox::construct(
                    context,
                    root_element,
                    style,
                    display_inside,
                    contents,
                ),
            ))],
        )
    } else if box_style.float.is_floating() {
        (
            ContainsFloats::Yes,
            vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox(
                FloatBox::construct(context, root_element, style, display_inside, contents),
            ))],
        )
    } else {
        (
            ContainsFloats::No,
            vec![Arc::new(BlockLevelBox::Independent(
                IndependentFormattingContext::construct(
                    context,
                    root_element,
                    style,
                    display_inside,
                    contents,
                    ContentSizesRequest::None,
                ),
            ))],
        )
    }
}

impl BoxTreeRoot {
    pub fn layout(
        &self,
        layout_context: &LayoutContext,
        viewport: euclid::Size2D<f32, CSSPixel>,
    ) -> FragmentTreeRoot {
        let style = ComputedValues::initial_values();

        // FIXME: use the document’s mode:
        // https://drafts.csswg.org/css-writing-modes/#principal-flow
        let physical_containing_block = PhysicalRect::new(
            PhysicalPoint::zero(),
            PhysicalSize::new(Length::new(viewport.width), Length::new(viewport.height)),
        );
        let initial_containing_block = DefiniteContainingBlock {
            size: Vec2 {
                inline: physical_containing_block.size.width,
                block: physical_containing_block.size.height,
            },
            style,
        };

        let dummy_tree_rank = 0;
        let mut positioning_context = PositioningContext::new_for_initial_containing_block();
        let mut independent_layout = self.0.layout(
            layout_context,
            &mut positioning_context,
            &(&initial_containing_block).into(),
            dummy_tree_rank,
        );

        positioning_context.layout_in_initial_containing_block(
            layout_context,
            &initial_containing_block,
            &mut independent_layout.fragments,
        );

        let scrollable_overflow =
            independent_layout
                .fragments
                .iter()
                .fold(PhysicalRect::zero(), |acc, child| {
                    let child_overflow = child.scrollable_overflow();

                    // https://drafts.csswg.org/css-overflow/#scrolling-direction
                    // We want to clip scrollable overflow on box-start and inline-start
                    // sides of the scroll container.
                    //
                    // FIXME(mrobinson, bug 25564): This should take into account writing
                    // mode.
                    let child_overflow = PhysicalRect::new(
                        euclid::Point2D::zero(),
                        euclid::Size2D::new(
                            child_overflow.size.width + child_overflow.origin.x,
                            child_overflow.size.height + child_overflow.origin.y,
                        ),
                    );
                    acc.union(&child_overflow)
                });

        FragmentTreeRoot {
            children: independent_layout.fragments,
            scrollable_overflow,
            initial_containing_block: physical_containing_block,
        }
    }
}

impl FragmentTreeRoot {
    pub fn build_display_list(&self, builder: &mut crate::display_list::DisplayListBuilder) {
        for fragment in &self.children {
            fragment.build_display_list(builder, &self.initial_containing_block)
        }
    }

    pub fn print(&self) {
        let mut print_tree = PrintTree::new("Fragment Tree".to_string());
        for fragment in &self.children {
            fragment.print(&mut print_tree);
        }
    }

    pub fn scrollable_overflow(&self) -> webrender_api::units::LayoutSize {
        webrender_api::units::LayoutSize::from_untyped(Size2D::new(
            self.scrollable_overflow.size.width.px(),
            self.scrollable_overflow.size.height.px(),
        ))
    }

    fn iterate_through_fragments<F>(&self, process_func: &mut F)
    where
        F: FnMut(&Fragment, &PhysicalRect<Length>) -> bool,
    {
        fn do_iteration<M>(
            fragment: &Fragment,
            containing_block: &PhysicalRect<Length>,
            process_func: &mut M,
        ) -> bool
        where
            M: FnMut(&Fragment, &PhysicalRect<Length>) -> bool,
        {
            if !process_func(fragment, containing_block) {
                return false;
            }

            match fragment {
                Fragment::Box(fragment) => {
                    let new_containing_block = fragment
                        .content_rect
                        .to_physical(fragment.style.writing_mode, containing_block)
                        .translate(containing_block.origin.to_vector());
                    for child in &fragment.children {
                        if !do_iteration(child, &new_containing_block, process_func) {
                            return false;
                        }
                    }
                },
                Fragment::Anonymous(fragment) => {
                    let new_containing_block = fragment
                        .rect
                        .to_physical(fragment.mode, containing_block)
                        .translate(containing_block.origin.to_vector());
                    for child in &fragment.children {
                        if !do_iteration(child, &new_containing_block, process_func) {
                            return false;
                        }
                    }
                },
                _ => {},
            }

            true
        }

        for child in &self.children {
            if !do_iteration(child, &self.initial_containing_block, process_func) {
                break;
            }
        }
    }

    pub fn get_content_box_for_node(&self, requested_node: OpaqueNode) -> Rect<Au> {
        let mut rect = PhysicalRect::zero();
        let mut process = |fragment: &Fragment, containing_block: &PhysicalRect<Length>| {
            let fragment_relative_rect = match fragment {
                Fragment::Box(fragment) if fragment.tag == requested_node => fragment
                    .border_rect()
                    .to_physical(fragment.style.writing_mode, &containing_block),
                Fragment::Text(fragment) if fragment.tag == requested_node => fragment
                    .rect
                    .to_physical(fragment.parent_style.writing_mode, &containing_block),
                Fragment::Box(_) |
                Fragment::Text(_) |
                Fragment::Image(_) |
                Fragment::Anonymous(_) => return true,
            };

            rect = fragment_relative_rect
                .translate(containing_block.origin.to_vector())
                .union(&rect);
            return true;
        };

        self.iterate_through_fragments(&mut process);

        Rect::new(
            Point2D::new(
                Au::from_f32_px(rect.origin.x.px()),
                Au::from_f32_px(rect.origin.y.px()),
            ),
            Size2D::new(
                Au::from_f32_px(rect.size.width.px()),
                Au::from_f32_px(rect.size.height.px()),
            ),
        )
    }

    pub fn get_border_dimensions_for_node(&self, requested_node: OpaqueNode) -> Rect<i32> {
        let mut border_dimensions = Rect::zero();
        let mut process = |fragment: &Fragment, containing_block: &PhysicalRect<Length>| {
            let (style, padding_rect) = match fragment {
                Fragment::Box(fragment) if fragment.tag == requested_node => {
                    (&fragment.style, fragment.padding_rect())
                },
                Fragment::Box(_) |
                Fragment::Text(_) |
                Fragment::Image(_) |
                Fragment::Anonymous(_) => return true,
            };

            // https://drafts.csswg.org/cssom-view/#dom-element-clienttop
            // " If the element has no associated CSS layout box or if the
            //   CSS layout box is inline, return zero." For this check we
            // also explicitly ignore the list item portion of the display
            // style.
            let display = &style.get_box().display;
            if display.inside() == style::values::specified::box_::DisplayInside::Flow &&
                display.outside() == style::values::specified::box_::DisplayOutside::Inline
            {
                return false;
            }

            let style_structs::Border {
                border_top_width: top_width,
                border_left_width: left_width,
                ..
            } = *style.get_border();

            let padding_rect = padding_rect.to_physical(style.writing_mode, &containing_block);
            border_dimensions.size.width = padding_rect.size.width.px() as i32;
            border_dimensions.size.height = padding_rect.size.height.px() as i32;
            border_dimensions.origin.y = top_width.px() as i32;
            border_dimensions.origin.x = left_width.px() as i32;

            false
        };

        self.iterate_through_fragments(&mut process);

        border_dimensions
    }
}
<commit_msg>Deduplicate the loop in iterate_through_fragments<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 https://mozilla.org/MPL/2.0/. */

use crate::context::LayoutContext;
use crate::dom_traversal::{Contents, NodeExt};
use crate::flow::construct::ContainsFloats;
use crate::flow::float::FloatBox;
use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::Fragment;
use crate::geom::flow_relative::Vec2;
use crate::geom::{PhysicalPoint, PhysicalRect, PhysicalSize};
use crate::positioned::AbsolutelyPositionedBox;
use crate::positioned::PositioningContext;
use crate::replaced::ReplacedContent;
use crate::sizing::ContentSizesRequest;
use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside};
use crate::DefiniteContainingBlock;
use app_units::Au;
use euclid::default::{Point2D, Rect, Size2D};
use gfx_traits::print_tree::PrintTree;
use script_layout_interface::wrapper_traits::LayoutNode;
use servo_arc::Arc;
use style::dom::OpaqueNode;
use style::properties::{style_structs, ComputedValues};
use style::values::computed::Length;
use style_traits::CSSPixel;

pub struct BoxTreeRoot(BlockFormattingContext);

pub struct FragmentTreeRoot {
    /// The children of the root of the fragment tree.
    children: Vec<Fragment>,

    /// The scrollable overflow of the root of the fragment tree.
    scrollable_overflow: PhysicalRect<Length>,

    /// The containing block used in the layout of this fragment tree.
    initial_containing_block: PhysicalRect<Length>,
}

impl BoxTreeRoot {
    pub fn construct<'dom, Node>(context: &LayoutContext, root_element: Node) -> Self
    where
        Node: 'dom + Copy + LayoutNode + Send + Sync,
    {
        let (contains_floats, boxes) = construct_for_root_element(&context, root_element);
        Self(BlockFormattingContext {
            contains_floats: contains_floats == ContainsFloats::Yes,
            contents: BlockContainer::BlockLevelBoxes(boxes),
        })
    }
}

fn construct_for_root_element<'dom>(
    context: &LayoutContext,
    root_element: impl NodeExt<'dom>,
) -> (ContainsFloats, Vec<Arc<BlockLevelBox>>) {
    let style = root_element.style(context);
    let replaced = ReplacedContent::for_element(root_element);
    let box_style = style.get_box();

    let display_inside = match Display::from(box_style.display) {
        Display::None => return (ContainsFloats::No, Vec::new()),
        Display::Contents if replaced.is_some() => {
            // 'display: contents' computes to 'none' for replaced elements
            return (ContainsFloats::No, Vec::new());
        },
        // https://drafts.csswg.org/css-display-3/#transformations
        Display::Contents => DisplayInside::Flow,
        // The root element is blockified, ignore DisplayOutside
        Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { inside, .. }) => inside,
    };

    let contents = replaced.map_or(Contents::OfElement, Contents::Replaced);
    if box_style.position.is_absolutely_positioned() {
        (
            ContainsFloats::No,
            vec![Arc::new(BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(
                AbsolutelyPositionedBox::construct(
                    context,
                    root_element,
                    style,
                    display_inside,
                    contents,
                ),
            ))],
        )
    } else if box_style.float.is_floating() {
        (
            ContainsFloats::Yes,
            vec![Arc::new(BlockLevelBox::OutOfFlowFloatBox(
                FloatBox::construct(context, root_element, style, display_inside, contents),
            ))],
        )
    } else {
        (
            ContainsFloats::No,
            vec![Arc::new(BlockLevelBox::Independent(
                IndependentFormattingContext::construct(
                    context,
                    root_element,
                    style,
                    display_inside,
                    contents,
                    ContentSizesRequest::None,
                ),
            ))],
        )
    }
}

impl BoxTreeRoot {
    pub fn layout(
        &self,
        layout_context: &LayoutContext,
        viewport: euclid::Size2D<f32, CSSPixel>,
    ) -> FragmentTreeRoot {
        let style = ComputedValues::initial_values();

        // FIXME: use the document’s mode:
        // https://drafts.csswg.org/css-writing-modes/#principal-flow
        let physical_containing_block = PhysicalRect::new(
            PhysicalPoint::zero(),
            PhysicalSize::new(Length::new(viewport.width), Length::new(viewport.height)),
        );
        let initial_containing_block = DefiniteContainingBlock {
            size: Vec2 {
                inline: physical_containing_block.size.width,
                block: physical_containing_block.size.height,
            },
            style,
        };

        let dummy_tree_rank = 0;
        let mut positioning_context = PositioningContext::new_for_initial_containing_block();
        let mut independent_layout = self.0.layout(
            layout_context,
            &mut positioning_context,
            &(&initial_containing_block).into(),
            dummy_tree_rank,
        );

        positioning_context.layout_in_initial_containing_block(
            layout_context,
            &initial_containing_block,
            &mut independent_layout.fragments,
        );

        let scrollable_overflow =
            independent_layout
                .fragments
                .iter()
                .fold(PhysicalRect::zero(), |acc, child| {
                    let child_overflow = child.scrollable_overflow();

                    // https://drafts.csswg.org/css-overflow/#scrolling-direction
                    // We want to clip scrollable overflow on box-start and inline-start
                    // sides of the scroll container.
                    //
                    // FIXME(mrobinson, bug 25564): This should take into account writing
                    // mode.
                    let child_overflow = PhysicalRect::new(
                        euclid::Point2D::zero(),
                        euclid::Size2D::new(
                            child_overflow.size.width + child_overflow.origin.x,
                            child_overflow.size.height + child_overflow.origin.y,
                        ),
                    );
                    acc.union(&child_overflow)
                });

        FragmentTreeRoot {
            children: independent_layout.fragments,
            scrollable_overflow,
            initial_containing_block: physical_containing_block,
        }
    }
}

impl FragmentTreeRoot {
    pub fn build_display_list(&self, builder: &mut crate::display_list::DisplayListBuilder) {
        for fragment in &self.children {
            fragment.build_display_list(builder, &self.initial_containing_block)
        }
    }

    pub fn print(&self) {
        let mut print_tree = PrintTree::new("Fragment Tree".to_string());
        for fragment in &self.children {
            fragment.print(&mut print_tree);
        }
    }

    pub fn scrollable_overflow(&self) -> webrender_api::units::LayoutSize {
        webrender_api::units::LayoutSize::from_untyped(Size2D::new(
            self.scrollable_overflow.size.width.px(),
            self.scrollable_overflow.size.height.px(),
        ))
    }

    fn iterate_through_fragments<F>(&self, process_func: &mut F)
    where
        F: FnMut(&Fragment, &PhysicalRect<Length>) -> bool,
    {
        fn recur<M>(
            fragments: &[Fragment],
            containing_block: &PhysicalRect<Length>,
            process_func: &mut M,
        ) -> bool
        where
            M: FnMut(&Fragment, &PhysicalRect<Length>) -> bool,
        {
            for fragment in fragments {
                if !process_func(fragment, containing_block) {
                    return false;
                }

                match fragment {
                    Fragment::Box(fragment) => {
                        let new_containing_block = fragment
                            .content_rect
                            .to_physical(fragment.style.writing_mode, containing_block)
                            .translate(containing_block.origin.to_vector());
                        if !recur(&fragment.children, &new_containing_block, process_func) {
                            return false;
                        }
                    },
                    Fragment::Anonymous(fragment) => {
                        let new_containing_block = fragment
                            .rect
                            .to_physical(fragment.mode, containing_block)
                            .translate(containing_block.origin.to_vector());
                        if !recur(&fragment.children, &new_containing_block, process_func) {
                            return false;
                        }
                    },
                    _ => {},
                }
            }
            true
        }
        recur(&self.children, &self.initial_containing_block, process_func);
    }

    pub fn get_content_box_for_node(&self, requested_node: OpaqueNode) -> Rect<Au> {
        let mut rect = PhysicalRect::zero();
        let mut process = |fragment: &Fragment, containing_block: &PhysicalRect<Length>| {
            let fragment_relative_rect = match fragment {
                Fragment::Box(fragment) if fragment.tag == requested_node => fragment
                    .border_rect()
                    .to_physical(fragment.style.writing_mode, &containing_block),
                Fragment::Text(fragment) if fragment.tag == requested_node => fragment
                    .rect
                    .to_physical(fragment.parent_style.writing_mode, &containing_block),
                Fragment::Box(_) |
                Fragment::Text(_) |
                Fragment::Image(_) |
                Fragment::Anonymous(_) => return true,
            };

            rect = fragment_relative_rect
                .translate(containing_block.origin.to_vector())
                .union(&rect);
            return true;
        };

        self.iterate_through_fragments(&mut process);

        Rect::new(
            Point2D::new(
                Au::from_f32_px(rect.origin.x.px()),
                Au::from_f32_px(rect.origin.y.px()),
            ),
            Size2D::new(
                Au::from_f32_px(rect.size.width.px()),
                Au::from_f32_px(rect.size.height.px()),
            ),
        )
    }

    pub fn get_border_dimensions_for_node(&self, requested_node: OpaqueNode) -> Rect<i32> {
        let mut border_dimensions = Rect::zero();
        let mut process = |fragment: &Fragment, containing_block: &PhysicalRect<Length>| {
            let (style, padding_rect) = match fragment {
                Fragment::Box(fragment) if fragment.tag == requested_node => {
                    (&fragment.style, fragment.padding_rect())
                },
                Fragment::Box(_) |
                Fragment::Text(_) |
                Fragment::Image(_) |
                Fragment::Anonymous(_) => return true,
            };

            // https://drafts.csswg.org/cssom-view/#dom-element-clienttop
            // " If the element has no associated CSS layout box or if the
            //   CSS layout box is inline, return zero." For this check we
            // also explicitly ignore the list item portion of the display
            // style.
            let display = &style.get_box().display;
            if display.inside() == style::values::specified::box_::DisplayInside::Flow &&
                display.outside() == style::values::specified::box_::DisplayOutside::Inline
            {
                return false;
            }

            let style_structs::Border {
                border_top_width: top_width,
                border_left_width: left_width,
                ..
            } = *style.get_border();

            let padding_rect = padding_rect.to_physical(style.writing_mode, &containing_block);
            border_dimensions.size.width = padding_rect.size.width.px() as i32;
            border_dimensions.size.height = padding_rect.size.height.px() as i32;
            border_dimensions.origin.y = top_width.px() as i32;
            border_dimensions.origin.x = left_width.px() as i32;

            false
        };

        self.iterate_through_fragments(&mut process);

        border_dimensions
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::str::Chars;

pub struct Position {
    pub line: usize,
    pub column: usize,
}

pub enum Token {
    Empty,
    Invalid,
    Identifier(String),
    Literal(Literal),
    Punctuation(String),
    Linefeed,
    Colon,
    Semicolon,
}

pub enum Literal {
    StringLiteral(String),
    Character(char),
    Integer(String),
    FloatingPoint(String),
    Hex(String),
}

pub struct Lexer<'a> {
    pub token: Token,
    character: Option<char>,
    chars: Chars<'a>,
    previous_line: usize,
    previous_column: usize,
    pub line: usize,
    pub column: usize,
}

impl<'a> Lexer<'a> {
    pub fn new(deck: &'a str) -> Lexer {
        let mut lexer = Lexer {
            chars: deck.chars(),
            token: Token::Empty,
            character: None,
            previous_line: 1,
            previous_column: 0,
            line: 1,
            column: 0,
        };
        lexer.read_character();
        lexer
    }

    fn read_character(&mut self) {
        self.character = self.chars.next();
        match self.character {
            None => (),
            Some(c) => match c {
                '\r' => (),
                '\n' => {
                    self.column = 0;
                    self.line = self.line + 1;
                }
                '\t' => self.column = self.column + 4,
                _ => self.column = self.column + 1,
            },
        }
    }

    pub fn advance(&mut self) {
        self.skip_whitespace();
        self.previous_line = self.line;
        self.previous_column = self.column;
        match self.character {
            None => return,
            Some(c) => {
                if ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) {
                    self.token = self.scan_identifier();
                    return;
                }

                if (c >= '1') && (c <= '9') {
                    let mut value = String::new();
                    value.push(c);
                    self.token = self.scan_numeric_literal(value);
                    return;
                }

                match c {
                    '\n' => {
                        self.read_character();
                        self.token = Token::Linefeed;
                    }
                    ':' => {
                        self.read_character();
                        self.token = Token::Colon;
                    }
                    ';' => {
                        self.read_character();
                        self.token = Token::Semicolon;
                    }
                    '0' => {
                        let mut value = String::new();
                        value.push(c);
                        self.token = self.scan_numeric_or_hex_literal(value);
                    }
                    '+' | '-' | '*' | '/' | '=' | '%' | '&' | '|' | '^' | '~' | '<' | '>' => {
                        let mut operation = String::new();
                        operation.push(c);
                        self.token = self.scan_operator(operation)
                    }
                    '\"' => self.token = { self.scan_string_literal() },
                    '\'' => self.token = { self.scan_character_literal() },
                    '{' | '}' | '(' | ')' | '[' | ']' | '.' | ',' | '?' | '!' | '@' | '#'
                    | '$' | '_' | '`' => {
                        let mut punctuation_string = String::new();
                        punctuation_string.push(c);
                        self.read_character();
                        self.token = Token::Punctuation(punctuation_string);
                    }
                    _ => self.token = Token::Invalid,
                }
            }
        }
    }

    pub fn empty(&mut self) {
        self.token = Token::Empty;
    }

    fn scan_identifier(&mut self) -> Token {
        let mut name = String::new();
        loop {
            match self.character {
                None => {
                    if name.len() == 0 {
                        return Token::Invalid;
                    } else {
                        return Token::Identifier(name);
                    }
                }

                Some(c) => match c {
                    'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => {
                        name.push(c);
                        self.read_character();
                    }
                    _ => return Token::Identifier(name),
                },
            }
        }
    }

    fn scan_operator(&mut self, mut operation: String) -> Token {
        loop {
            match self.character {
                None => {
                    if operation.len() == 0 {
                        return Token::Invalid;
                    } else {
                        return Token::Identifier(operation);
                    }
                }
                Some(c) => match c {
                    '+' | '-' | '*' | '/' | '=' | '%' | '&' | '|' | '^' | '~' | '<' | '>' => {
                        operation.push(c);
                    }

                    _ => return Token::Identifier(operation),
                },
            }
        }
    }

    fn scan_string_literal(&mut self) -> Token {
        let mut value = String::new();

        loop {
            self.read_character();

            match self.character {
                None => return Token::Invalid,
                Some(c) => match c {
                    '\"' => {
                        self.read_character();
                        return Token::Literal(Literal::StringLiteral(value));
                    }

                    '\\' => {
                        self.read_character();
                        match self.character {
                            None => return Token::Invalid,
                            Some(c) => match c {
                                '\"' | '\\' | '\'' => {
                                    value.push('\\');
                                    value.push(c);
                                }
                                'n' => {
                                    value.push('\\');
                                    value.push('n');
                                }
                                'r' => {
                                    value.push('\\');
                                    value.push('r');
                                }
                                't' => {
                                    value.push('\\');
                                    value.push('t');
                                }
                                '0' => {
                                    value.push('\\');
                                    value.push('0');
                                }
                                _ => return Token::Invalid,
                            },
                        }
                    }

                    _ => {
                        value.push(c);
                    }
                },
            }
        }
    }

    fn scan_character_literal(&mut self) -> Token {
        let value: char;
        self.read_character();

        match self.character {
            None => return Token::Invalid,
            Some(c) => match c {
                '\'' => return Token::Invalid,
                '\\' => {
                    self.read_character();
                    match self.character {
                        None => return Token::Invalid,
                        Some(c) => match c {
                            '\"' | '\\' | '\'' => value = c,
                            'n' => value = '\n',
                            'r' => value = '\r',
                            't' => value = '\t',
                            '0' => value = '\0',
                            _ => return Token::Invalid,
                        },
                    }
                }
                _ => value = c,
            },
        }
        self.read_character();
        match self.character {
            None => Token::Invalid,
            Some(c) => match c {
                '\'' => Token::Literal(Literal::Character(value)),
                _ => Token::Invalid,
            },
        }
    }

    fn scan_numeric_or_hex_literal(&mut self, mut value: String) -> Token {
        self.read_character();
        match self.character {
            None => return Token::Literal(Literal::Integer(value)),
            Some(c) => match c {
                '0'..='9' => {
                    value.push(c);
                    return self.scan_numeric_literal(value);
                }
                '.' => {
                    value.push(c);
                    return self.scan_fraction(value);
                }
                'E' | 'e' => {
                    value.push(c);
                    return self.scan_exponent(value);
                }
                'x' => {
                    return self.scan_hex_literal();
                }
                _ => return Token::Literal(Literal::Integer(value)),
            },
        }
    }

    fn scan_numeric_literal(&mut self, mut value: String) -> Token {
        loop {
            self.read_character();
            match self.character {
                None => {
                    return Token::Literal(Literal::Integer(value));
                }
                Some(c) => match c {
                    '0'..='9' => {
                        value.push(c);
                    }
                    '.' => {
                        value.push(c);
                        return self.scan_fraction(value);
                    }
                    'E' | 'e' => {
                        value.push(c);
                        return self.scan_exponent(value);
                    }
                    _ => return Token::Literal(Literal::Integer(value)),
                },
            }
        }
    }

    fn scan_fraction(&mut self, mut value: String) -> Token {
        loop {
            self.read_character();
            match self.character {
                None => {
                    return Token::Literal(Literal::FloatingPoint(value));
                }
                Some(c) => match c {
                    '0'..='9' => {
                        value.push(c);
                    }
                    'E' | 'e' => {
                        value.push(c);
                        return self.scan_exponent(value);
                    }
                    _ => return Token::Literal(Literal::FloatingPoint(value)),
                },
            }
        }
    }

    fn scan_exponent(&mut self, mut value: String) -> Token {
        loop {
            self.read_character();
            match self.character {
                None => {
                    return Token::Literal(Literal::FloatingPoint(value));
                }
                Some(c) => match c {
                    '0'..='9' => {
                        value.push(c);
                    }
                    _ => return Token::Literal(Literal::FloatingPoint(value)),
                },
            }
        }
    }

    fn scan_hex_literal(&mut self) -> Token {
        let mut value = String::new();
        loop {
            self.read_character();
            match self.character {
                None => {
                    return Token::Literal(Literal::FloatingPoint(value));
                }
                Some(c) => match c {
                    '0'..='9' | 'a'..='f' | 'A'..='F' => {
                        value.push(c);
                    }
                    _ => return Token::Literal(Literal::Hex(value)),
                },
            }
        }
    }

    fn skip_whitespace(&mut self) {
        loop {
            match self.character {
                None => return,
                Some(c) => match c {
                    ' ' => {
                        self.read_character();
                        continue;
                    }
                    '\t' => {
                        self.read_character();
                        continue;
                    }
                    '\r' => {
                        self.read_character();
                        continue;
                    }
                    '/' => {
                        self.read_character();
                        match self.character {
                            None => return,
                            Some(c) => match c {
                                '/' => {
                                    self.read_character();
                                    self.handle_single_line_comment()
                                }
                                '*' => {
                                    self.read_character();
                                    self.handle_multi_line_comment()
                                }
                                _ => return,
                            },
                        }
                    }

                    _ => {
                        return;
                    }
                },
            }
        }
    }

    fn handle_single_line_comment(&mut self) {
        loop {
            match self.character {
                None => return,
                Some(c) => match c {
                    '\t' => {
                        self.read_character();
                        continue;
                    }
                    '\r' => {
                        continue;
                    }
                    '\n' => {
                        self.read_character();
                        return;
                    }
                    _ => {
                        self.read_character();
                        continue;
                    }
                },
            }
        }
    }

    fn handle_multi_line_comment(&mut self) {
        loop {
            match self.character {
                None => return,
                Some(c) => match c {
                    '/' => {
                        self.read_character();
                        match self.character {
                            None => return,
                            Some(c) => match c {
                                '*' => self.handle_multi_line_comment(),
                                _ => return,
                            },
                        }
                    }

                    '*' => {
                        self.read_character();
                        match self.character {
                            None => return,
                            Some(c) => match c {
                                '/' => {
                                    self.read_character();
                                    return;
                                }
                                _ => (),
                            },
                        }
                    }

                    '\t' => {
                        self.read_character();
                        continue;
                    }

                    '\r' => {
                        continue;
                    }

                    '\n' => {
                        self.read_character();
                        continue;
                    }

                    _ => {
                        self.read_character();
                        continue;
                    }
                },
            }
        }
    }

    pub fn parse_keyword(&mut self, fixed_string: String) -> bool {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Identifier(name) => {
                let right_keyword = *name == fixed_string;
                if right_keyword {
                    self.empty();
                }
                return right_keyword;
            }
            _ => return false,
        }
    }

    pub fn parse_identifier(&mut self, keywords: &HashSet<String>) -> Option<String> {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Identifier(name) => {
                if keywords.contains(name) {
                    return None;
                }
                let ret = String::from(name);
                self.empty();
                return Some(ret);
            }
            _ => return None,
        }
    }

    pub fn parse_punctuation(&mut self, fixed_string: String) -> bool {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Punctuation(name) => {
                let ret = *name == fixed_string;
                if ret {
                    self.empty();
                }
                return ret;
            }
            _ => return false,
        }
    }

    pub fn parse_literal(&mut self) -> Option<Literal> {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Literal(Literal::StringLiteral(name)) => {
                let ret = String::from(name);
                self.empty();
                Some(Literal::StringLiteral(ret))
            }
            Token::Literal(Literal::Character(character)) => {
                let ret = *character;
                self.empty();
                Some(Literal::Character(ret))
            }
            Token::Literal(Literal::Integer(name)) => {
                let ret = String::from(name);
                self.empty();
                Some(Literal::Integer(ret))
            }
            Token::Literal(Literal::FloatingPoint(name)) => {
                let ret = String::from(name);
                self.empty();
                Some(Literal::FloatingPoint(ret))
            }
            Token::Literal(Literal::Hex(name)) => {
                let ret = String::from(name);
                self.empty();
                Some(Literal::Hex(ret))
            }
            _ => None,
        }
    }

    pub fn parse_colon(&mut self) -> bool {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Colon | Token::Linefeed => {
                self.empty();
                true
            }
            _ => false,
        }
    }

    pub fn parse_semicolon(&mut self) -> bool {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Semicolon | Token::Linefeed => {
                self.empty();
                true
            }
            _ => false,
        }
    }

    pub fn is_at_end(&mut self) -> bool {
        match self.character {
            None => true,
            Some(_) => false,
        }
    }

    pub fn get_position(&self) -> Position {
        Position {
            line: self.line,
            column: self.column,
        }
    }

    pub fn get_previous_position(&self) -> Position {
        Position {
            line: self.previous_line,
            column: self.previous_column,
        }
    }
}
<commit_msg>Lexer: attribute token<commit_after>use std::collections::HashSet;
use std::str::Chars;

pub struct Position {
    pub line: usize,
    pub column: usize,
}

pub enum Token {
    Empty,
    Invalid,
    Identifier(String),
    Attribute(String),
    Literal(Literal),
    Punctuation(String),
    Linefeed,
    Colon,
    Semicolon,
}

pub enum Literal {
    StringLiteral(String),
    Character(char),
    Integer(String),
    FloatingPoint(String),
    Hex(String),
}

pub struct Lexer<'a> {
    pub token: Token,
    character: Option<char>,
    chars: Chars<'a>,
    previous_line: usize,
    previous_column: usize,
    pub line: usize,
    pub column: usize,
}

impl<'a> Lexer<'a> {
    pub fn new(deck: &'a str) -> Lexer {
        let mut lexer = Lexer {
            chars: deck.chars(),
            token: Token::Empty,
            character: None,
            previous_line: 1,
            previous_column: 0,
            line: 1,
            column: 0,
        };
        lexer.read_character();
        lexer
    }

    fn read_character(&mut self) {
        self.character = self.chars.next();
        match self.character {
            None => (),
            Some(c) => match c {
                '\r' => (),
                '\n' => {
                    self.column = 0;
                    self.line = self.line + 1;
                }
                '\t' => self.column = self.column + 4,
                _ => self.column = self.column + 1,
            },
        }
    }

    pub fn advance(&mut self) {
        self.skip_whitespace();
        self.previous_line = self.line;
        self.previous_column = self.column;
        match self.character {
            None => return,
            Some(c) => {
                if ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) {
                    self.token = self.scan_identifier();
                    return;
                }

                if (c >= '1') && (c <= '9') {
                    let mut value = String::new();
                    value.push(c);
                    self.token = self.scan_numeric_literal(value);
                    return;
                }

                match c {
                    '\n' => {
                        self.read_character();
                        self.token = Token::Linefeed;
                    }
                    ':' => {
                        self.read_character();
                        self.token = Token::Colon;
                    }
                    ';' => {
                        self.read_character();
                        self.token = Token::Semicolon;
                    }
                    '0' => {
                        let mut value = String::new();
                        value.push(c);
                        self.token = self.scan_numeric_or_hex_literal(value);
                    }
                    '@' => {
                        self.read_character();
                        self.token = self.scan_attribute();
                        return;
                        }
                    '+' | '-' | '*' | '/' | '=' | '%' | '&' | '|' | '^' | '~' | '<' | '>' => {
                        let mut operation = String::new();
                        operation.push(c);
                        self.token = self.scan_operator(operation)
                    }
                    '\"' => self.token = { self.scan_string_literal() },
                    '\'' => self.token = { self.scan_character_literal() },
                    '{' | '}' | '(' | ')' | '[' | ']' | '.' | ',' | '?' | '!' | '#'
                    | '$' | '_' | '`' => {
                        let mut punctuation_string = String::new();
                        punctuation_string.push(c);
                        self.read_character();
                        self.token = Token::Punctuation(punctuation_string);
                    }
                    _ => self.token = Token::Invalid,
                }
            }
        }
    }

    pub fn empty(&mut self) {
        self.token = Token::Empty;
    }

    fn scan_identifier(&mut self) -> Token {
        let mut name = String::new();
        loop {
            match self.character {
                None => {
                    if name.len() == 0 {
                        return Token::Invalid;
                    } else {
                        return Token::Identifier(name);
                    }
                }

                Some(c) => match c {
                    'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => {
                        name.push(c);
                        self.read_character();
                    }
                    _ => return Token::Identifier(name),
                },
            }
        }
    }

    fn scan_attribute(&mut self) -> Token {
        let mut name = String::new();
        loop {
            match self.character {
                None => {
                    if name.len() == 0 {
                        return Token::Invalid;
                    } else {
                        return Token::Attribute(name);
                    }
                }

                Some(c) => match c {
                    'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => {
                        name.push(c);
                        self.read_character();
                    }
                    _ => return Token::Attribute(name),
                },
            }
        }
    }

    fn scan_operator(&mut self, mut operation: String) -> Token {
        loop {
            match self.character {
                None => {
                    if operation.len() == 0 {
                        return Token::Invalid;
                    } else {
                        return Token::Identifier(operation);
                    }
                }
                Some(c) => match c {
                    '+' | '-' | '*' | '/' | '=' | '%' | '&' | '|' | '^' | '~' | '<' | '>' => {
                        operation.push(c);
                    }

                    _ => return Token::Identifier(operation),
                },
            }
        }
    }

    fn scan_string_literal(&mut self) -> Token {
        let mut value = String::new();

        loop {
            self.read_character();

            match self.character {
                None => return Token::Invalid,
                Some(c) => match c {
                    '\"' => {
                        self.read_character();
                        return Token::Literal(Literal::StringLiteral(value));
                    }

                    '\\' => {
                        self.read_character();
                        match self.character {
                            None => return Token::Invalid,
                            Some(c) => match c {
                                '\"' | '\\' | '\'' => {
                                    value.push('\\');
                                    value.push(c);
                                }
                                'n' => {
                                    value.push('\\');
                                    value.push('n');
                                }
                                'r' => {
                                    value.push('\\');
                                    value.push('r');
                                }
                                't' => {
                                    value.push('\\');
                                    value.push('t');
                                }
                                '0' => {
                                    value.push('\\');
                                    value.push('0');
                                }
                                _ => return Token::Invalid,
                            },
                        }
                    }

                    _ => {
                        value.push(c);
                    }
                },
            }
        }
    }

    fn scan_character_literal(&mut self) -> Token {
        let value: char;
        self.read_character();

        match self.character {
            None => return Token::Invalid,
            Some(c) => match c {
                '\'' => return Token::Invalid,
                '\\' => {
                    self.read_character();
                    match self.character {
                        None => return Token::Invalid,
                        Some(c) => match c {
                            '\"' | '\\' | '\'' => value = c,
                            'n' => value = '\n',
                            'r' => value = '\r',
                            't' => value = '\t',
                            '0' => value = '\0',
                            _ => return Token::Invalid,
                        },
                    }
                }
                _ => value = c,
            },
        }
        self.read_character();
        match self.character {
            None => Token::Invalid,
            Some(c) => match c {
                '\'' => Token::Literal(Literal::Character(value)),
                _ => Token::Invalid,
            },
        }
    }

    fn scan_numeric_or_hex_literal(&mut self, mut value: String) -> Token {
        self.read_character();
        match self.character {
            None => return Token::Literal(Literal::Integer(value)),
            Some(c) => match c {
                '0'..='9' => {
                    value.push(c);
                    return self.scan_numeric_literal(value);
                }
                '.' => {
                    value.push(c);
                    return self.scan_fraction(value);
                }
                'E' | 'e' => {
                    value.push(c);
                    return self.scan_exponent(value);
                }
                'x' => {
                    return self.scan_hex_literal();
                }
                _ => return Token::Literal(Literal::Integer(value)),
            },
        }
    }

    fn scan_numeric_literal(&mut self, mut value: String) -> Token {
        loop {
            self.read_character();
            match self.character {
                None => {
                    return Token::Literal(Literal::Integer(value));
                }
                Some(c) => match c {
                    '0'..='9' => {
                        value.push(c);
                    }
                    '.' => {
                        value.push(c);
                        return self.scan_fraction(value);
                    }
                    'E' | 'e' => {
                        value.push(c);
                        return self.scan_exponent(value);
                    }
                    _ => return Token::Literal(Literal::Integer(value)),
                },
            }
        }
    }

    fn scan_fraction(&mut self, mut value: String) -> Token {
        loop {
            self.read_character();
            match self.character {
                None => {
                    return Token::Literal(Literal::FloatingPoint(value));
                }
                Some(c) => match c {
                    '0'..='9' => {
                        value.push(c);
                    }
                    'E' | 'e' => {
                        value.push(c);
                        return self.scan_exponent(value);
                    }
                    _ => return Token::Literal(Literal::FloatingPoint(value)),
                },
            }
        }
    }

    fn scan_exponent(&mut self, mut value: String) -> Token {
        loop {
            self.read_character();
            match self.character {
                None => {
                    return Token::Literal(Literal::FloatingPoint(value));
                }
                Some(c) => match c {
                    '0'..='9' => {
                        value.push(c);
                    }
                    _ => return Token::Literal(Literal::FloatingPoint(value)),
                },
            }
        }
    }

    fn scan_hex_literal(&mut self) -> Token {
        let mut value = String::new();
        loop {
            self.read_character();
            match self.character {
                None => {
                    return Token::Literal(Literal::FloatingPoint(value));
                }
                Some(c) => match c {
                    '0'..='9' | 'a'..='f' | 'A'..='F' => {
                        value.push(c);
                    }
                    _ => return Token::Literal(Literal::Hex(value)),
                },
            }
        }
    }

    fn skip_whitespace(&mut self) {
        loop {
            match self.character {
                None => return,
                Some(c) => match c {
                    ' ' => {
                        self.read_character();
                        continue;
                    }
                    '\t' => {
                        self.read_character();
                        continue;
                    }
                    '\r' => {
                        self.read_character();
                        continue;
                    }
                    '/' => {
                        self.read_character();
                        match self.character {
                            None => return,
                            Some(c) => match c {
                                '/' => {
                                    self.read_character();
                                    self.handle_single_line_comment()
                                }
                                '*' => {
                                    self.read_character();
                                    self.handle_multi_line_comment()
                                }
                                _ => return,
                            },
                        }
                    }

                    _ => {
                        return;
                    }
                },
            }
        }
    }

    fn handle_single_line_comment(&mut self) {
        loop {
            match self.character {
                None => return,
                Some(c) => match c {
                    '\t' => {
                        self.read_character();
                        continue;
                    }
                    '\r' => {
                        continue;
                    }
                    '\n' => {
                        self.read_character();
                        return;
                    }
                    _ => {
                        self.read_character();
                        continue;
                    }
                },
            }
        }
    }

    fn handle_multi_line_comment(&mut self) {
        loop {
            match self.character {
                None => return,
                Some(c) => match c {
                    '/' => {
                        self.read_character();
                        match self.character {
                            None => return,
                            Some(c) => match c {
                                '*' => self.handle_multi_line_comment(),
                                _ => return,
                            },
                        }
                    }

                    '*' => {
                        self.read_character();
                        match self.character {
                            None => return,
                            Some(c) => match c {
                                '/' => {
                                    self.read_character();
                                    return;
                                }
                                _ => (),
                            },
                        }
                    }

                    '\t' => {
                        self.read_character();
                        continue;
                    }

                    '\r' => {
                        continue;
                    }

                    '\n' => {
                        self.read_character();
                        continue;
                    }

                    _ => {
                        self.read_character();
                        continue;
                    }
                },
            }
        }
    }

    pub fn parse_keyword(&mut self, fixed_string: String) -> bool {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Identifier(name) => {
                let right_keyword = *name == fixed_string;
                if right_keyword {
                    self.empty();
                }
                return right_keyword;
            }
            _ => return false,
        }
    }

    pub fn parse_identifier(&mut self, keywords: &HashSet<String>) -> Option<String> {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Identifier(name) => {
                if keywords.contains(name) {
                    return None;
                }
                let ret = String::from(name);
                self.empty();
                return Some(ret);
            }
            _ => return None,
        }
    }

    pub fn parse_punctuation(&mut self, fixed_string: String) -> bool {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Punctuation(name) => {
                let ret = *name == fixed_string;
                if ret {
                    self.empty();
                }
                return ret;
            }
            _ => return false,
        }
    }

    pub fn parse_literal(&mut self) -> Option<Literal> {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Literal(Literal::StringLiteral(name)) => {
                let ret = String::from(name);
                self.empty();
                Some(Literal::StringLiteral(ret))
            }
            Token::Literal(Literal::Character(character)) => {
                let ret = *character;
                self.empty();
                Some(Literal::Character(ret))
            }
            Token::Literal(Literal::Integer(name)) => {
                let ret = String::from(name);
                self.empty();
                Some(Literal::Integer(ret))
            }
            Token::Literal(Literal::FloatingPoint(name)) => {
                let ret = String::from(name);
                self.empty();
                Some(Literal::FloatingPoint(ret))
            }
            Token::Literal(Literal::Hex(name)) => {
                let ret = String::from(name);
                self.empty();
                Some(Literal::Hex(ret))
            }
            _ => None,
        }
    }

    pub fn parse_colon(&mut self) -> bool {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Colon | Token::Linefeed => {
                self.empty();
                true
            }
            _ => false,
        }
    }

    pub fn parse_semicolon(&mut self) -> bool {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Semicolon | Token::Linefeed => {
                self.empty();
                true
            }
            _ => false,
        }
    }

    pub fn is_at_end(&mut self) -> bool {
        match self.character {
            None => true,
            Some(_) => false,
        }
    }

    pub fn get_position(&self) -> Position {
        Position {
            line: self.line,
            column: self.column,
        }
    }

    pub fn get_previous_position(&self) -> Position {
        Position {
            line: self.previous_line,
            column: self.previous_column,
        }
    }
}
<|endoftext|>


<commit_before>use anyhow::{Context, Result};

// https://github.com/dtolnay/anyhow/issues/18
#[test]
fn test_inference() -> Result<()> {
    let x = "1";
    let y: u32 = x.parse().context("...")?;
    assert_eq!(y, 1);
    Ok(())
}
<commit_msg>Add tests for downcasting context<commit_after>mod drop;

use crate::drop::{DetectDrop, Flag};
use anyhow::{Context, Error, Result};
use std::fmt::{self, Display};
use thiserror::Error;

// https://github.com/dtolnay/anyhow/issues/18
#[test]
fn test_inference() -> Result<()> {
    let x = "1";
    let y: u32 = x.parse().context("...")?;
    assert_eq!(y, 1);
    Ok(())
}

macro_rules! context_type {
    ($name:ident) => {
        #[derive(Debug)]
        struct $name {
            message: &'static str,
            drop: DetectDrop,
        }

        impl Display for $name {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                f.write_str(self.message)
            }
        }
    };
}

context_type!(HighLevel);
context_type!(MidLevel);

#[derive(Error, Debug)]
#[error("{message}")]
struct LowLevel {
    message: &'static str,
    drop: DetectDrop,
}

struct Dropped {
    low: Flag,
    mid: Flag,
    high: Flag,
}

impl Dropped {
    fn none(&self) -> bool {
        !self.low.get() && !self.mid.get() && !self.high.get()
    }

    fn all(&self) -> bool {
        self.low.get() && self.mid.get() && self.high.get()
    }
}

fn make_chain() -> (Error, Dropped) {
    let dropped = Dropped {
        low: Flag::new(),
        mid: Flag::new(),
        high: Flag::new(),
    };

    let low = LowLevel {
        message: "no such file or directory",
        drop: DetectDrop::new(&dropped.low),
    };

    // impl Context for Result<T, E>
    let mid = Err::<(), LowLevel>(low)
        .context(MidLevel {
            message: "failed to load config",
            drop: DetectDrop::new(&dropped.mid),
        })
        .unwrap_err();

    // impl Context for Result<T, Error>
    let high = Err::<(), Error>(mid)
        .context(HighLevel {
            message: "failed to start server",
            drop: DetectDrop::new(&dropped.high),
        })
        .unwrap_err();

    (high, dropped)
}

#[test]
fn test_downcast_ref() {
    let (err, dropped) = make_chain();

    assert!(!err.is::<String>());
    assert!(err.downcast_ref::<String>().is_none());

    assert!(err.is::<HighLevel>());
    let high = err.downcast_ref::<HighLevel>().unwrap();
    assert_eq!(high.to_string(), "failed to start server");

    assert!(err.is::<MidLevel>());
    let mid = err.downcast_ref::<MidLevel>().unwrap();
    assert_eq!(mid.to_string(), "failed to load config");

    assert!(err.is::<LowLevel>());
    let low = err.downcast_ref::<LowLevel>().unwrap();
    assert_eq!(low.to_string(), "no such file or directory");

    assert!(dropped.none());
    drop(err);
    assert!(dropped.all());
}

#[test]
fn test_downcast_high() {
    let (err, dropped) = make_chain();

    let err = err.downcast::<HighLevel>().unwrap();
    assert!(!dropped.high.get());
    assert!(dropped.low.get() && dropped.mid.get());

    drop(err);
    assert!(dropped.all());
}

#[test]
fn test_downcast_mid() {
    let (err, dropped) = make_chain();

    let err = err.downcast::<MidLevel>().unwrap();
    assert!(!dropped.mid.get());
    assert!(dropped.low.get() && dropped.high.get());

    drop(err);
    assert!(dropped.all());
}

#[test]
fn test_downcast_low() {
    let (err, dropped) = make_chain();

    let err = err.downcast::<LowLevel>().unwrap();
    assert!(!dropped.low.get());
    assert!(dropped.mid.get() && dropped.high.get());

    drop(err);
    assert!(dropped.all());
}

#[test]
fn test_unsuccessful_downcast() {
    let (err, dropped) = make_chain();

    let err = err.downcast::<String>().unwrap_err();
    assert!(dropped.none());

    drop(err);
    assert!(dropped.all());
}
<|endoftext|>