<commit_before>use nalgebra::ToHomogeneous;

use id::Id;
use model::Model;
use transform::{M44, Orientation, Position, Scale, Transformable, translation_matrix};

pub struct Object<'a> {
  pub model: Id<'a, Model>,
  pub position: Position,
  pub orientation: Orientation,
  pub scale: Scale
}

impl<'a> Transformable for Object<'a> {
  fn transform(&self) -> M44 {
    let m = translation_matrix(-self.position) * self.scale.to_mat() * self.orientation.to_rotation_matrix().to_homogeneous();
    m.as_ref().clone()
  }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct ObjectManifest {
  model: String,
  position: [f32; 3],
  orientation: [f32; 4],
  scale: [f32; 3]
}
<commit_msg>impl Load for Object.<commit_after>use nalgebra::{Quaternion, ToHomogeneous, Unit};
use serde_json::from_reader;
use std::path::Path;
use std::fs::File;

use id::Id;
use model::Model;
use resource::{Cache, Get, Load, LoadError};
use transform::{M44, Orientation, Position, Scale, Transformable, translation_matrix};

pub struct Object<'a> {
  pub model: Id<'a, Model>,
  pub position: Position,
  pub orientation: Orientation,
  pub scale: Scale
}

impl<'a> Transformable for Object<'a> {
  fn transform(&self) -> M44 {
    let m = translation_matrix(-self.position) * self.scale.to_mat() * self.orientation.to_rotation_matrix().to_homogeneous();
    m.as_ref().clone()
  }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct ObjectManifest {
  model: String,
  position: [f32; 3],
  orientation: [f32; 4],
  scale: [f32; 3]
}

impl<'a> Load<'a> for Object<'a> {
  type Args = ();

  fn load<P>(path: P, cache: &mut Cache<'a>, _: Self::Args) -> Result<Self, LoadError> where P: AsRef<Path> {
    let path = path.as_ref();

    info!("loading object {:?}", path);

    // read the manifest
    let manifest: ObjectManifest = {
      let file = File::open("data/scene/objects/{}.json").map_err(|e| LoadError::FileNotFound(path.to_path_buf(), format!("{:?}", e)))?;
      from_reader(file).map_err(|e| LoadError::ParseFailed(format!("{:?}", e)))?
    };

    // get the model id
    let model_id = cache.get_id(&manifest.model, ()).ok_or(LoadError::ConversionFailed(format!("unable to find model {} for object at {:?}", manifest.model, path)))?;

    Ok(Object {
      model: model_id,
      position: (&manifest.position).into(),
      orientation: Unit::new(&Quaternion::from(&manifest.orientation)),
      scale: (&manifest.scale).into()
    })
  }
}
<|endoftext|>


<commit_before>use bytes::{self, MutBuf};
use bytes::buf::BlockBuf;
use proto::{pipeline, Parse, Serialize, Framed};
use tokio::io::Io;
use spki_sexp as sexp;
use serde::{ser, de};
use std::fmt::Write;
use void::Void;

use std::marker::PhantomData;

use super::errors::Error;

#[derive(Debug)]
pub struct SexpParser<T> {
    _x: PhantomData<fn() -> (T)>,
    packets: sexp::Packetiser,
}

pub type Frame<T> = pipeline::Frame<T, Void, Error>;

impl<T> SexpParser<T> {
    pub fn new() -> Self {
        SexpParser {
            _x: PhantomData,
            packets: sexp::Packetiser::new(),
        }
    }
}

impl<T: de::Deserialize> Parse for SexpParser<T> {
    type Out = Frame<T>;

    fn parse(&mut self, buf: &mut BlockBuf) -> Option<Frame<T>> {
        use proto::pipeline::Frame;

        if !buf.is_compact() {
            buf.compact();
        }
        self.packets.feed(&buf.bytes().expect("compacted buffer"));
        let len = buf.len();
        buf.shift(len);
        debug!("Buffer now:{:?}", buf.len());

        debug!("Packets now:{:?}", self.packets);
        match self.packets.take() {
            Ok(Some(msg)) => Some(Frame::Message(msg)),
            Ok(None) => None,
            Err(e) => {
                error!("Transport error:{:?}", e);
                Some(Frame::Error(e.into()))
            }
        }
    }
}

pub struct SexpSerializer<T>(PhantomData<T>);

impl<T: ser::Serialize> Serialize for SexpSerializer<T> {
    type In = Frame<T>;
    fn serialize(&mut self, frame: Frame<T>, buf: &mut BlockBuf) {
        use proto::pipeline::Frame;
        match frame {
            Frame::Message(val) => buf.write_slice(&sexp::as_bytes(&val).expect("serialize")),
            Frame::Error(e) => {
                warn!("Error handling in serializer:{:?}", e);
                let _ = write!(bytes::buf::Fmt(buf), "[ERROR] {}\n", e);
            }
            Frame::Done => {}
            Frame::MessageWithBody(_, _) |
            Frame::Body(_) => unreachable!(),
        }
    }
}

pub type FramedSexpTransport<T, X, Y> = Framed<T, SexpParser<X>, SexpSerializer<Y>>;

pub fn sexp_proto_new<T: Io, X: de::Deserialize, Y: ser::Serialize>
    (inner: T)
     -> FramedSexpTransport<T, X, Y> {
    Framed::new(inner,
                SexpParser::new(),
                SexpSerializer(PhantomData),
                BlockBuf::default(),
                BlockBuf::default())

}
<commit_msg>Genericise errors in sexp protocol.<commit_after>use bytes::{self, MutBuf};
use bytes::buf::BlockBuf;
use proto::{pipeline, Parse, Serialize, Framed};
use tokio::io::Io;
use spki_sexp as sexp;
use serde::{ser, de};
use std::fmt::Write;
use std::error;
use void::Void;

use std::marker::PhantomData;

#[derive(Debug)]
pub struct SexpParser<T, E> {
    _x: PhantomData<fn() -> Result<T, E>>,
    packets: sexp::Packetiser,
}

pub type Frame<T, E> = pipeline::Frame<T, Void, E>;

impl<T, E> SexpParser<T, E> {
    pub fn new() -> Self {
        SexpParser {
            _x: PhantomData,
            packets: sexp::Packetiser::new(),
        }
    }
}

impl<T: de::Deserialize, E: From<sexp::Error>> Parse for SexpParser<T, E> {
    type Out = Frame<T, E>;

    fn parse(&mut self, buf: &mut BlockBuf) -> Option<Self::Out> {
        use proto::pipeline::Frame;

        if !buf.is_compact() {
            buf.compact();
        }
        self.packets.feed(&buf.bytes().expect("compacted buffer"));
        let len = buf.len();
        buf.shift(len);
        debug!("Buffer now:{:?}", buf.len());

        debug!("Packets now:{:?}", self.packets);
        match self.packets.take() {
            Ok(Some(msg)) => Some(Frame::Message(msg)),
            Ok(None) => None,
            Err(e) => {
                error!("Transport error:{:?}", e);
                Some(Frame::Error(e.into()))
            }
        }
    }
}

pub struct SexpSerializer<T, E>(PhantomData<(T, E)>);

impl<T: ser::Serialize, E: error::Error> Serialize for SexpSerializer<T, E> {
    type In = Frame<T, E>;
    fn serialize(&mut self, frame: Self::In, buf: &mut BlockBuf) {
        use proto::pipeline::Frame;
        match frame {
            Frame::Message(val) => buf.write_slice(&sexp::as_bytes(&val).expect("serialize")),
            Frame::Error(e) => {
                warn!("Error handling in serializer:{:?}", e);
                let _ = write!(bytes::buf::Fmt(buf), "[ERROR] {}\n", e);
            }
            Frame::Done => {}
            Frame::MessageWithBody(_, _) |
            Frame::Body(_) => unreachable!(),
        }
    }
}

pub type FramedSexpTransport<T, X, Y, E> = Framed<T, SexpParser<X, E>, SexpSerializer<Y, E>>;

pub fn sexp_proto_new<T: Io,
                      X: de::Deserialize,
                      Y: ser::Serialize,
                      E: From<sexp::Error> + error::Error>
    (inner: T)
     -> FramedSexpTransport<T, X, Y, E> {
    Framed::new(inner,
                SexpParser::new(),
                SexpSerializer(PhantomData),
                BlockBuf::default(),
                BlockBuf::default())

}
<|endoftext|>


<commit_before>use super::{AssertionFailure, Spec};

use std::cmp::PartialEq;
use std::fmt::Debug;

pub trait OptionAssertions<T>
    where T: Debug
{
    fn is_some(&mut self);
    fn is_none(&mut self);
}

pub trait ContainingOptionAssertions<T>
    where T: Debug + PartialEq
{
    fn contains_value(&mut self, expected_value: &T);
}

impl<'s, T> ContainingOptionAssertions<T> for Spec<'s, Option<T>>
    where T: Debug + PartialEq
{
    /// Asserts that the subject is a `Some` containing the expected value. The subject type must
    /// be an `Option`.
    ///
    /// ```rust,ignore
    /// assert_that(&Some(1)).contains_value(&1);
    /// ```
    fn contains_value(&mut self, expected_value: &T) {
        match self.subject {
            &Some(ref val) => {
                if !val.eq(expected_value) {
                    AssertionFailure::from_spec(self)
                        .with_expected(format!("option to contain <{:?}>", expected_value))
                        .with_actual(format!("<{:?}>", val))
                        .fail();
                }
            }
            &None => {
                AssertionFailure::from_spec(self)
                    .with_expected(format!("option<{:?}>", expected_value))
                    .with_actual(format!("option[none]"))
                    .fail();
            }
        };
    }
}

impl<'s, T> OptionAssertions<T> for Spec<'s, Option<T>>
    where T: Debug
{
    /// Asserts that the subject is `Some`. The subject type must be an `Option`.
    ///
    /// ```rust,ignore
    /// assert_that(&Some(1)).is_some();
    /// ```
    fn is_some(&mut self) {
        match self.subject {
            &Some(_) => (),
            &None => {
                AssertionFailure::from_spec(self)
                    .with_expected(format!("option[some]"))
                    .with_actual(format!("option[none]"))
                    .fail();
            }
        };
    }

    /// Asserts that the subject is `None`. The value type must be an `Option`.
    ///
    /// ```rust,ignore
    /// assert_that(&Option::None::<String>).is_none();
    /// ```
    fn is_none(&mut self) {
        match self.subject {
            &None => (),
            &Some(ref val) => {
                AssertionFailure::from_spec(self)
                    .with_expected(format!("option[none]"))
                    .with_actual(format!("option<{:?}>", val))
                    .fail();
            }
        };
    }
}

#[cfg(test)]
mod tests {

    use super::super::prelude::*;

    #[test]
    fn should_not_panic_if_option_is_expected_to_contain_value_and_does() {
        let option = Some("Hello");
        assert_that(&option).is_some();
    }

    #[test]
    #[should_panic(expected = "\n\texpected: option[some]\n\t but was: option[none]")]
    fn should_panic_if_option_is_expected_to_contain_value_and_does_not() {
        let option: Option<&str> = None;
        assert_that(&option).is_some();
    }

    #[test]
    fn should_not_panic_if_option_contains_expected_value() {
        let option = Some("Hello");
        assert_that(&option).contains_value(&"Hello");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: option to contain <\"Hi\">\n\t but was: <\"Hello\">")]
    fn should_panic_if_option_does_not_contain_expected_value() {
        let option = Some("Hello");
        assert_that(&option).contains_value(&"Hi");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: option<\"Hello\">\n\t but was: option[none]")]
    fn should_panic_if_option_is_none_but_expected_value() {
        let option: Option<&str> = None;
        assert_that(&option).contains_value(&"Hello");
    }

    #[test]
    fn should_not_panic_if_option_is_empty() {
        let option: Option<&str> = None;
        assert_that(&option).is_none();
    }

    #[test]
    #[should_panic(expected = "\n\texpected: option[none]\n\t but was: option<\"Hello\"")]
    fn should_panic_if_option_is_not_empty_but_was_expected_as_empty() {
        let option = Some("Hello");
        assert_that(&option).is_none();
    }

}
<commit_msg>is_some() will now also return a Spec containing the unwrapped value<commit_after>use super::{AssertionFailure, Spec};

use std::cmp::PartialEq;
use std::fmt::Debug;

pub trait OptionAssertions<'r, T>
    where T: Debug
{
    fn is_some(&mut self) -> Spec<'r, T>;
    fn is_none(&mut self);
}

pub trait ContainingOptionAssertions<T>
    where T: Debug + PartialEq
{
    fn contains_value(&mut self, expected_value: &T);
}

impl<'s, T> ContainingOptionAssertions<T> for Spec<'s, Option<T>>
    where T: Debug + PartialEq
{
    /// Asserts that the subject is a `Some` containing the expected value. The subject type must
    /// be an `Option`.
    ///
    /// ```rust,ignore
    /// assert_that(&Some(1)).contains_value(&1);
    /// ```
    fn contains_value(&mut self, expected_value: &T) {
        match self.subject {
            &Some(ref val) => {
                if !val.eq(expected_value) {
                    AssertionFailure::from_spec(self)
                        .with_expected(format!("option to contain <{:?}>", expected_value))
                        .with_actual(format!("<{:?}>", val))
                        .fail();
                }
            }
            &None => {
                AssertionFailure::from_spec(self)
                    .with_expected(format!("option<{:?}>", expected_value))
                    .with_actual(format!("option[none]"))
                    .fail();
            }
        };
    }
}

impl<'s, T> OptionAssertions<'s, T> for Spec<'s, Option<T>>
    where T: Debug
{
    /// Asserts that the subject is `Some`. The subject type must be an `Option`.
    ///
    /// This will return a new `Spec` containing the unwrapped value if it is `Some`.
    ///
    /// ```rust,ignore
    /// assert_that(&Some(1)).is_some();
    /// ```
    fn is_some(&mut self) -> Spec<'s, T> {
        return match self.subject {
            &Some(ref val) => {
                Spec {
                    subject: val,
                    description: self.description,
                }
            }
            &None => {
                AssertionFailure::from_spec(self)
                    .with_expected(format!("option[some]"))
                    .with_actual(format!("option[none]"))
                    .fail();

                unreachable!();
            }
        };
    }

    /// Asserts that the subject is `None`. The value type must be an `Option`.
    ///
    /// ```rust,ignore
    /// assert_that(&Option::None::<String>).is_none();
    /// ```
    fn is_none(&mut self) {
        match self.subject {
            &None => (),
            &Some(ref val) => {
                AssertionFailure::from_spec(self)
                    .with_expected(format!("option[none]"))
                    .with_actual(format!("option<{:?}>", val))
                    .fail();
            }
        };
    }
}

#[cfg(test)]
mod tests {

    use super::super::prelude::*;

    #[test]
    fn should_not_panic_if_option_is_expected_to_contain_value_and_does() {
        let option = Some("Hello");
        assert_that(&option).is_some();
    }

    #[test]
    #[should_panic(expected = "\n\texpected: option[some]\n\t but was: option[none]")]
    fn should_panic_if_option_is_expected_to_contain_value_and_does_not() {
        let option: Option<&str> = None;
        assert_that(&option).is_some();
    }

    #[test]
    fn should_be_able_to_unwrap_option_if_some() {
        let option = Some("Hello");
        assert_that(&option).is_some().is_equal_to(&"Hello");
    }

    #[test]
    fn should_not_panic_if_option_contains_expected_value() {
        let option = Some("Hello");
        assert_that(&option).contains_value(&"Hello");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: option to contain <\"Hi\">\n\t but was: <\"Hello\">")]
    fn should_panic_if_option_does_not_contain_expected_value() {
        let option = Some("Hello");
        assert_that(&option).contains_value(&"Hi");
    }

    #[test]
    #[should_panic(expected = "\n\texpected: option<\"Hello\">\n\t but was: option[none]")]
    fn should_panic_if_option_is_none_but_expected_value() {
        let option: Option<&str> = None;
        assert_that(&option).contains_value(&"Hello");
    }

    #[test]
    fn should_not_panic_if_option_is_empty() {
        let option: Option<&str> = None;
        assert_that(&option).is_none();
    }

    #[test]
    #[should_panic(expected = "\n\texpected: option[none]\n\t but was: option<\"Hello\"")]
    fn should_panic_if_option_is_not_empty_but_was_expected_as_empty() {
        let option = Some("Hello");
        assert_that(&option).is_none();
    }

}
<|endoftext|>


<commit_before>use std::io::{self, StdoutLock, Write};
use std::path::Path;
use std::process;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

use lscolors::{LsColors, Style};

use crate::config::Config;
use crate::error::print_error;
use crate::exit_codes::ExitCode;
use crate::filesystem::strip_current_dir;

fn replace_path_separator(path: &str, new_path_separator: &str) -> String {
    path.replace(std::path::MAIN_SEPARATOR, new_path_separator)
}

// TODO: this function is performance critical and can probably be optimized
pub fn print_entry(
    stdout: &mut StdoutLock,
    entry: &Path,
    config: &Config,
    wants_to_quit: &Arc<AtomicBool>,
) {
    let path = if entry.is_absolute() || config.no_strip {
        entry
    } else {
        strip_current_dir(entry)
    };

    let r = if let Some(ref ls_colors) = config.ls_colors {
        print_entry_colorized(stdout, path, config, ls_colors, wants_to_quit)
    } else {
        print_entry_uncolorized(stdout, path, config)
    };

    if let Err(e) = r {
        if e.kind() == ::std::io::ErrorKind::BrokenPipe {
            // Exit gracefully in case of a broken pipe (e.g. 'fd ... | head -n 3').
            process::exit(0);
        } else {
            print_error(format!("Could not write to output: {}", e));
            process::exit(ExitCode::GeneralError.into());
        }
    }
}

// TODO: this function is performance critical and can probably be optimized
fn print_entry_colorized(
    stdout: &mut StdoutLock,
    path: &Path,
    config: &Config,
    ls_colors: &LsColors,
    wants_to_quit: &Arc<AtomicBool>,
) -> io::Result<()> {
    let default_style = ansi_term::Style::default();

    // Traverse the path and colorize each component
    for (component, style) in ls_colors.style_for_path_components(path) {
        let style = style
            .map(Style::to_ansi_term_style)
            .unwrap_or(default_style);

        let mut path_string = component.to_string_lossy();
        if let Some(ref separator) = config.path_separator {
            *path_string.to_mut() = replace_path_separator(&path_string, separator);
        }
        write!(stdout, "{}", style.paint(path_string))?;

        // TODO: can we move this out of the if-statement? Why do we call it that often?
        if wants_to_quit.load(Ordering::Relaxed) {
            writeln!(stdout)?;
            process::exit(ExitCode::KilledBySigint.into());
        }
    }

    if config.null_separator {
        write!(stdout, "\0")
    } else {
        writeln!(stdout)
    }
}

// TODO: this function is performance critical and can probably be optimized
fn print_entry_uncolorized_base(
    stdout: &mut StdoutLock,
    path: &Path,
    config: &Config,
) -> io::Result<()> {
    let separator = if config.null_separator { "\0" } else { "\n" };

    let mut path_string = path.to_string_lossy();
    if let Some(ref separator) = config.path_separator {
        *path_string.to_mut() = replace_path_separator(&path_string, separator);
    }
    write!(stdout, "{}{}", path_string, separator)
}

#[cfg(not(unix))]
fn print_entry_uncolorized(
    stdout: &mut StdoutLock,
    path: &Path,
    config: &Config,
) -> io::Result<()> {
    print_entry_uncolorized_base(stdout, path, config)
}

#[cfg(unix)]
fn print_entry_uncolorized(
    stdout: &mut StdoutLock,
    path: &Path,
    config: &Config,
) -> io::Result<()> {
    use std::os::unix::ffi::OsStrExt;

    if config.interactive_terminal || config.path_separator.is_some() {
        // Fall back to the base implementation
        print_entry_uncolorized_base(stdout, path, config)
    } else {
        // Print path as raw bytes, allowing invalid UTF-8 filenames to be passed to other processes
        let separator = if config.null_separator { b"\0" } else { b"\n" };
        stdout.write_all(path.as_os_str().as_bytes())?;
        stdout.write_all(separator)
    }
}
<commit_msg>simplify check in prent_entry<commit_after>use std::io::{self, StdoutLock, Write};
use std::path::Path;
use std::process;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

use lscolors::{LsColors, Style};

use crate::config::Config;
use crate::error::print_error;
use crate::exit_codes::ExitCode;
use crate::filesystem::strip_current_dir;

fn replace_path_separator(path: &str, new_path_separator: &str) -> String {
    path.replace(std::path::MAIN_SEPARATOR, new_path_separator)
}

// TODO: this function is performance critical and can probably be optimized
pub fn print_entry(
    stdout: &mut StdoutLock,
    entry: &Path,
    config: &Config,
    wants_to_quit: &Arc<AtomicBool>,
) {
    let path = if config.no_strip {
        entry
    } else {
        strip_current_dir(entry)
    };

    let r = if let Some(ref ls_colors) = config.ls_colors {
        print_entry_colorized(stdout, path, config, ls_colors, wants_to_quit)
    } else {
        print_entry_uncolorized(stdout, path, config)
    };

    if let Err(e) = r {
        if e.kind() == ::std::io::ErrorKind::BrokenPipe {
            // Exit gracefully in case of a broken pipe (e.g. 'fd ... | head -n 3').
            process::exit(0);
        } else {
            print_error(format!("Could not write to output: {}", e));
            process::exit(ExitCode::GeneralError.into());
        }
    }
}

// TODO: this function is performance critical and can probably be optimized
fn print_entry_colorized(
    stdout: &mut StdoutLock,
    path: &Path,
    config: &Config,
    ls_colors: &LsColors,
    wants_to_quit: &Arc<AtomicBool>,
) -> io::Result<()> {
    let default_style = ansi_term::Style::default();

    // Traverse the path and colorize each component
    for (component, style) in ls_colors.style_for_path_components(path) {
        let style = style
            .map(Style::to_ansi_term_style)
            .unwrap_or(default_style);

        let mut path_string = component.to_string_lossy();
        if let Some(ref separator) = config.path_separator {
            *path_string.to_mut() = replace_path_separator(&path_string, separator);
        }
        write!(stdout, "{}", style.paint(path_string))?;

        // TODO: can we move this out of the if-statement? Why do we call it that often?
        if wants_to_quit.load(Ordering::Relaxed) {
            writeln!(stdout)?;
            process::exit(ExitCode::KilledBySigint.into());
        }
    }

    if config.null_separator {
        write!(stdout, "\0")
    } else {
        writeln!(stdout)
    }
}

// TODO: this function is performance critical and can probably be optimized
fn print_entry_uncolorized_base(
    stdout: &mut StdoutLock,
    path: &Path,
    config: &Config,
) -> io::Result<()> {
    let separator = if config.null_separator { "\0" } else { "\n" };

    let mut path_string = path.to_string_lossy();
    if let Some(ref separator) = config.path_separator {
        *path_string.to_mut() = replace_path_separator(&path_string, separator);
    }
    write!(stdout, "{}{}", path_string, separator)
}

#[cfg(not(unix))]
fn print_entry_uncolorized(
    stdout: &mut StdoutLock,
    path: &Path,
    config: &Config,
) -> io::Result<()> {
    print_entry_uncolorized_base(stdout, path, config)
}

#[cfg(unix)]
fn print_entry_uncolorized(
    stdout: &mut StdoutLock,
    path: &Path,
    config: &Config,
) -> io::Result<()> {
    use std::os::unix::ffi::OsStrExt;

    if config.interactive_terminal || config.path_separator.is_some() {
        // Fall back to the base implementation
        print_entry_uncolorized_base(stdout, path, config)
    } else {
        // Print path as raw bytes, allowing invalid UTF-8 filenames to be passed to other processes
        let separator = if config.null_separator { b"\0" } else { b"\n" };
        stdout.write_all(path.as_os_str().as_bytes())?;
        stdout.write_all(separator)
    }
}
<|endoftext|>


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

use std::ascii::AsciiExt;
use std::str::CowString;
use std::ops;
use tokenizer::{Token, NumericValue, PercentageValue, Tokenizer, SourcePosition, SourceLocation};

/// Like std::borrow::Cow, except:
///
/// * The Owned variant is boxed
/// * The Borrowed variant contains a mutable reference.
enum MaybeOwned<'a, T: 'a> {
    Owned(Box<T>),
    Borrowed(&'a mut T),
}

impl<'a, T> ops::Deref<T> for MaybeOwned<'a, T> {
    fn deref<'a>(&'a self) -> &'a T {
        match *self {
            MaybeOwned::Owned(ref pointer) => &**pointer,
            MaybeOwned::Borrowed(ref pointer) => &**pointer,
        }
    }
}

impl<'a, T> ops::DerefMut<T> for MaybeOwned<'a, T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        match *self {
            MaybeOwned::Owned(ref mut pointer) => &mut **pointer,
            MaybeOwned::Borrowed(ref mut pointer) => &mut **pointer,
        }
    }
}

impl<'a, T> Clone for MaybeOwned<'a, T> where T: Clone {
    fn clone(&self) -> MaybeOwned<'a, T> {
        MaybeOwned::Owned(box() (**self).clone())
    }
}

#[deriving(Clone)]
pub struct Parser<'i: 't, 't> {
    tokenizer: MaybeOwned<'t, Tokenizer<'i>>,
    /// If `Some(_)`, .parse_nested_block() can be called.
    at_start_of: Option<BlockType>,
    /// If `Some(_)`, this parser is from .parse_nested_block()
    parse_until_before_end_of: Option<BlockType>,
    /// For parsers from `parse_until`
    parse_until_before: Delimiters,
}

#[deriving(Copy, Clone, PartialEq, Eq, Show)]
enum BlockType {
    Parenthesis,
    SquareBracket,
    CurlyBracket,
}

impl BlockType {
    fn opening(token: &Token) -> Option<BlockType> {
        match *token {
            Token::Function(_) |
            Token::ParenthesisBlock => Some(BlockType::Parenthesis),
            Token::SquareBracketBlock => Some(BlockType::SquareBracket),
            Token::CurlyBracketBlock => Some(BlockType::CurlyBracket),
            _ => None
        }
    }

    fn closing(token: &Token) -> Option<BlockType> {
        match *token {
            Token::CloseParenthesis => Some(BlockType::Parenthesis),
            Token::CloseSquareBracket => Some(BlockType::SquareBracket),
            Token::CloseCurlyBracket => Some(BlockType::CurlyBracket),
            _ => None
        }
    }
}

#[deriving(Copy, Clone, PartialEq, Eq, Show)]
pub struct Delimiters {
    bits: u8,
}

#[allow(non_upper_case_globals, non_snake_case)]
pub mod Delimiter {
    use super::Delimiters;

    pub const None: Delimiters = Delimiters { bits: 0 };
    /// `{`
    pub const CurlyBracketBlock: Delimiters = Delimiters { bits: 1 << 1 };
    /// `;`
    pub const Semicolon: Delimiters = Delimiters { bits: 1 << 2 };
    /// `!`
    pub const Bang: Delimiters = Delimiters { bits: 1 << 3 };
    /// `,`
    pub const Comma: Delimiters = Delimiters { bits: 1 << 4 };
}

impl BitOr<Delimiters, Delimiters> for Delimiters {
    fn bitor(&self, other: &Delimiters) -> Delimiters {
        Delimiters { bits: self.bits | other.bits }
    }
}

impl Delimiters {
    fn contains(&self, other: Delimiters) -> bool {
        (self.bits & other.bits) != 0
    }

    fn from_token(token: &Token) -> Delimiters {
        match *token {
            Token::Semicolon => Delimiter::Semicolon,
            Token::Comma  => Delimiter::Comma,
            Token::Delim('!') => Delimiter::Bang,
            Token::CurlyBracketBlock => Delimiter::CurlyBracketBlock,
            _ => Delimiter::None,
        }
    }
}

impl<'i, 't> Parser<'i, 't> {
    #[inline]
    pub fn new(input: &'i str) -> Parser<'i, 'i> {
        Parser {
            tokenizer: MaybeOwned::Owned(box Tokenizer::new(input)),
            at_start_of: None,
            parse_until_before_end_of: None,
            parse_until_before: Delimiter::None,
        }
    }

    #[inline]
    pub fn is_exhausted(&mut self) -> bool {
        self.expect_exhausted().is_ok()
    }

    #[inline]
    pub fn expect_exhausted(&mut self) -> Result<(), ()> {
        match self.next() {
            Err(()) => Ok(()),
            Ok(token) => self.unexpected(token),
        }
    }

    #[inline]
    pub fn peek(&mut self) -> Result<&Token<'i>, ()> {
        // Consume whatever needs to be consumed (e.g. open blocks).
        let token = try!(self.next());
        self.push_back(token);
        self.tokenizer.peek()
    }

    #[inline]
    pub fn push_back(&mut self, token: Token<'i>) {
        if BlockType::opening(&token) == self.at_start_of {
            self.at_start_of = None;
        }
        self.tokenizer.push_back(token)
    }

    #[inline]
    pub fn push_back_result(&mut self, token_result: Result<Token<'i>, ()>) {
        if let Ok(token) = token_result {
            self.push_back(token)
        }
    }

    #[inline]
    pub fn unexpected<T>(&mut self, token: Token<'i>) -> Result<T, ()> {
        self.push_back(token);
        Err(())
    }

    #[inline]
    pub fn unexpected_ident<T>(&mut self, value: CowString<'i>) -> Result<T, ()> {
        self.push_back(Token::Ident(value));
        Err(())
    }

    #[inline]
    pub fn position(&self) -> SourcePosition {
        self.tokenizer.position()
    }

    #[inline]
    pub fn slice_from(&self, start_pos: SourcePosition) -> &'i str {
        self.tokenizer.slice_from(start_pos)
    }

    #[inline]
    pub fn current_source_location(&self) -> SourceLocation {
        self.tokenizer.current_source_location()
    }

    #[inline]
    pub fn source_location(&self, target: SourcePosition) -> SourceLocation {
        self.tokenizer.source_location(target)
    }

    pub fn next(&mut self) -> Result<Token<'i>, ()> {
        loop {
            match self.next_including_whitespace() {
                Ok(Token::WhiteSpace) => {},
                result => return result
            }
        }
    }

    pub fn next_including_whitespace(&mut self) -> Result<Token<'i>, ()> {
        if let Some(block_type) = self.at_start_of.take() {
            if consume_until_end_of_block(block_type, &mut *self.tokenizer) {
                return Err(())
            }
        }
        let token = try!(self.tokenizer.next());
        if self.parse_until_before.contains(Delimiters::from_token(&token)) {
            self.tokenizer.push_back(token);
            return Err(())
        }
        if self.parse_until_before_end_of.is_some() &&
                BlockType::closing(&token) == self.parse_until_before_end_of {
            self.tokenizer.push_back(token);
            return Err(())
        }
        if let Some(block_type) = BlockType::opening(&token) {
            self.at_start_of = Some(block_type);
        }
        Ok(token)
    }

    // FIXME: Take an unboxed `FnOnce` closure.
    #[inline]
    pub fn parse_entirely<T>(&mut self, parse: |&mut Parser| -> Result<T, ()>)
                             -> Result<T, ()> {
        let result = parse(self);
        try!(self.expect_exhausted());
        result
    }

    #[inline]
    pub fn parse_comma_separated<T>(&mut self, parse_one: |&mut Parser| -> Result<T, ()>)
                                    -> Result<Vec<T>, ()> {
        let mut values = vec![];
        loop {
            values.push(try!(self.parse_until_before(Delimiter::Comma, |parser| parse_one(parser))));
            match self.next() {
                Err(()) => return Ok(values),
                Ok(Token::Comma) => continue,
                Ok(_) => unreachable!(),
            }
        }
    }

    #[inline]
    pub fn parse_nested_block<T>(&mut self, parse: |&mut Parser| -> Result<T, ()>)
                                 -> Result <T, ()> {
        let block_type = self.at_start_of.take().expect("\
            A nested parser can only be created when a Function, \
            ParenthesisBlock, SquareBracketBlock, or CurlyBracketBlock \
            token was just consumed.\
        ");
        let result;
        // Introduce a new scope to limit duration of nested_parser’s borrow
        {
            let mut nested_parser = Parser {
                tokenizer: MaybeOwned::Borrowed(&mut *self.tokenizer),
                at_start_of: None,
                parse_until_before_end_of: Some(block_type),
                parse_until_before: Delimiter::None,
            };
            result = nested_parser.parse_entirely(parse);
        }
        consume_until_end_of_block(block_type, &mut *self.tokenizer);
        result
    }

    #[inline]
    pub fn parse_until_before<T>(&mut self, delimiters: Delimiters,
                                 parse: |&mut Parser| -> Result<T, ()>)
                                 -> Result <T, ()> {
        let delimiters = self.parse_until_before | delimiters;
        let result;
        // Introduce a new scope to limit duration of nested_parser’s borrow
        {
            let mut delimited_parser = Parser {
                tokenizer: MaybeOwned::Borrowed(&mut *self.tokenizer),
                at_start_of: self.at_start_of.take(),
                parse_until_before_end_of: self.parse_until_before_end_of,
                parse_until_before: delimiters,
            };
            result = delimited_parser.parse_entirely(parse);
        }
        // FIXME: have a special-purpose tokenizer method for this that does less work.
        while let Ok(token) = self.tokenizer.next() {
            if delimiters.contains(Delimiters::from_token(&token)) || (
                self.parse_until_before_end_of.is_some() &&
                BlockType::closing(&token) == self.parse_until_before_end_of
            ) {
                self.tokenizer.push_back(token);
                break
            }
            if let Some(block_type) = BlockType::opening(&token) {
                if consume_until_end_of_block(block_type, &mut *self.tokenizer) {
                    break
                }
            }
        }
        result
    }

    #[inline]
    pub fn parse_until_after<T>(&mut self, delimiters: Delimiters,
                                parse: |&mut Parser| -> Result<T, ()>)
                                -> Result <T, ()> {
        let result = self.parse_until_before(delimiters, parse);
        // Expect exhausted input or a relevant delimiter (which we consume):
        if let Ok(token) = self.next() {
            debug_assert!(delimiters.contains(Delimiters::from_token(&token)));
        }
        result
    }

    #[inline]
    pub fn expect_ident(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Ident(value) => Ok(value),
            token => self.unexpected(token)
        }
    }

    /// Expect an *ident* token whose value is an ASCII-insensitive match for the given value.
    #[inline]
    pub fn expect_ident_matching<'a>(&mut self, expected_value: &str) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Ident(ref value) if value.eq_ignore_ascii_case(expected_value) => Ok(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_string(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::QuotedString(value) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_ident_or_string(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Ident(value) => Ok(value),
            Token::QuotedString(value) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_url(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Url(value) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_url_or_string(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Url(value) => Ok(value),
            Token::QuotedString(value) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_number(&mut self) -> Result<f64, ()> {
        match try!(self.next()) {
            Token::Number(NumericValue { value, .. }) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_integer(&mut self) -> Result<i64, ()> {
        match try!(self.next()) {
            Token::Number(NumericValue { int_value, .. }) => int_value.ok_or(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_percentage(&mut self) -> Result<f64, ()> {
        match try!(self.next()) {
            Token::Percentage(PercentageValue { unit_value, .. }) => Ok(unit_value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_colon(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Colon => Ok(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_semicolon(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Semicolon => Ok(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_comma(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Comma => Ok(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_delim(&mut self, expected_value: char) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Delim(value) if value == expected_value => Ok(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_curly_bracket_block(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::CurlyBracketBlock => Ok(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_function(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Function(name) => Ok(name),
            token => self.unexpected(token)
        }
    }
}

/// Return value indicates whether the end of the input was reached.
fn consume_until_end_of_block(block_type: BlockType, tokenizer: &mut Tokenizer) -> bool {
    // FIXME: have a special-purpose tokenizer method for this that does less work.
    while let Ok(ref token) = tokenizer.next() {
        if BlockType::closing(token) == Some(block_type) {
            return false
        }
        if let Some(block_type) = BlockType::opening(token) {
            if consume_until_end_of_block(block_type, tokenizer) {
                return true
            }
        }
    }
    true
}
<commit_msg>Internal refactor: remove consume_until_end_of_block’s return value.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::ascii::AsciiExt;
use std::str::CowString;
use std::ops;
use tokenizer::{Token, NumericValue, PercentageValue, Tokenizer, SourcePosition, SourceLocation};

/// Like std::borrow::Cow, except:
///
/// * The Owned variant is boxed
/// * The Borrowed variant contains a mutable reference.
enum MaybeOwned<'a, T: 'a> {
    Owned(Box<T>),
    Borrowed(&'a mut T),
}

impl<'a, T> ops::Deref<T> for MaybeOwned<'a, T> {
    fn deref<'a>(&'a self) -> &'a T {
        match *self {
            MaybeOwned::Owned(ref pointer) => &**pointer,
            MaybeOwned::Borrowed(ref pointer) => &**pointer,
        }
    }
}

impl<'a, T> ops::DerefMut<T> for MaybeOwned<'a, T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        match *self {
            MaybeOwned::Owned(ref mut pointer) => &mut **pointer,
            MaybeOwned::Borrowed(ref mut pointer) => &mut **pointer,
        }
    }
}

impl<'a, T> Clone for MaybeOwned<'a, T> where T: Clone {
    fn clone(&self) -> MaybeOwned<'a, T> {
        MaybeOwned::Owned(box() (**self).clone())
    }
}

#[deriving(Clone)]
pub struct Parser<'i: 't, 't> {
    tokenizer: MaybeOwned<'t, Tokenizer<'i>>,
    /// If `Some(_)`, .parse_nested_block() can be called.
    at_start_of: Option<BlockType>,
    /// If `Some(_)`, this parser is from .parse_nested_block()
    parse_until_before_end_of: Option<BlockType>,
    /// For parsers from `parse_until`
    parse_until_before: Delimiters,
}

#[deriving(Copy, Clone, PartialEq, Eq, Show)]
enum BlockType {
    Parenthesis,
    SquareBracket,
    CurlyBracket,
}

impl BlockType {
    fn opening(token: &Token) -> Option<BlockType> {
        match *token {
            Token::Function(_) |
            Token::ParenthesisBlock => Some(BlockType::Parenthesis),
            Token::SquareBracketBlock => Some(BlockType::SquareBracket),
            Token::CurlyBracketBlock => Some(BlockType::CurlyBracket),
            _ => None
        }
    }

    fn closing(token: &Token) -> Option<BlockType> {
        match *token {
            Token::CloseParenthesis => Some(BlockType::Parenthesis),
            Token::CloseSquareBracket => Some(BlockType::SquareBracket),
            Token::CloseCurlyBracket => Some(BlockType::CurlyBracket),
            _ => None
        }
    }
}

#[deriving(Copy, Clone, PartialEq, Eq, Show)]
pub struct Delimiters {
    bits: u8,
}

#[allow(non_upper_case_globals, non_snake_case)]
pub mod Delimiter {
    use super::Delimiters;

    pub const None: Delimiters = Delimiters { bits: 0 };
    /// `{`
    pub const CurlyBracketBlock: Delimiters = Delimiters { bits: 1 << 1 };
    /// `;`
    pub const Semicolon: Delimiters = Delimiters { bits: 1 << 2 };
    /// `!`
    pub const Bang: Delimiters = Delimiters { bits: 1 << 3 };
    /// `,`
    pub const Comma: Delimiters = Delimiters { bits: 1 << 4 };
}

impl BitOr<Delimiters, Delimiters> for Delimiters {
    fn bitor(&self, other: &Delimiters) -> Delimiters {
        Delimiters { bits: self.bits | other.bits }
    }
}

impl Delimiters {
    fn contains(&self, other: Delimiters) -> bool {
        (self.bits & other.bits) != 0
    }

    fn from_token(token: &Token) -> Delimiters {
        match *token {
            Token::Semicolon => Delimiter::Semicolon,
            Token::Comma  => Delimiter::Comma,
            Token::Delim('!') => Delimiter::Bang,
            Token::CurlyBracketBlock => Delimiter::CurlyBracketBlock,
            _ => Delimiter::None,
        }
    }
}

impl<'i, 't> Parser<'i, 't> {
    #[inline]
    pub fn new(input: &'i str) -> Parser<'i, 'i> {
        Parser {
            tokenizer: MaybeOwned::Owned(box Tokenizer::new(input)),
            at_start_of: None,
            parse_until_before_end_of: None,
            parse_until_before: Delimiter::None,
        }
    }

    #[inline]
    pub fn is_exhausted(&mut self) -> bool {
        self.expect_exhausted().is_ok()
    }

    #[inline]
    pub fn expect_exhausted(&mut self) -> Result<(), ()> {
        match self.next() {
            Err(()) => Ok(()),
            Ok(token) => self.unexpected(token),
        }
    }

    #[inline]
    pub fn peek(&mut self) -> Result<&Token<'i>, ()> {
        // Consume whatever needs to be consumed (e.g. open blocks).
        let token = try!(self.next());
        self.push_back(token);
        self.tokenizer.peek()
    }

    #[inline]
    pub fn push_back(&mut self, token: Token<'i>) {
        if BlockType::opening(&token) == self.at_start_of {
            self.at_start_of = None;
        }
        self.tokenizer.push_back(token)
    }

    #[inline]
    pub fn push_back_result(&mut self, token_result: Result<Token<'i>, ()>) {
        if let Ok(token) = token_result {
            self.push_back(token)
        }
    }

    #[inline]
    pub fn unexpected<T>(&mut self, token: Token<'i>) -> Result<T, ()> {
        self.push_back(token);
        Err(())
    }

    #[inline]
    pub fn unexpected_ident<T>(&mut self, value: CowString<'i>) -> Result<T, ()> {
        self.push_back(Token::Ident(value));
        Err(())
    }

    #[inline]
    pub fn position(&self) -> SourcePosition {
        self.tokenizer.position()
    }

    #[inline]
    pub fn slice_from(&self, start_pos: SourcePosition) -> &'i str {
        self.tokenizer.slice_from(start_pos)
    }

    #[inline]
    pub fn current_source_location(&self) -> SourceLocation {
        self.tokenizer.current_source_location()
    }

    #[inline]
    pub fn source_location(&self, target: SourcePosition) -> SourceLocation {
        self.tokenizer.source_location(target)
    }

    pub fn next(&mut self) -> Result<Token<'i>, ()> {
        loop {
            match self.next_including_whitespace() {
                Ok(Token::WhiteSpace) => {},
                result => return result
            }
        }
    }

    pub fn next_including_whitespace(&mut self) -> Result<Token<'i>, ()> {
        if let Some(block_type) = self.at_start_of.take() {
            consume_until_end_of_block(block_type, &mut *self.tokenizer);
        }
        let token = try!(self.tokenizer.next());
        if self.parse_until_before.contains(Delimiters::from_token(&token)) {
            self.tokenizer.push_back(token);
            return Err(())
        }
        if self.parse_until_before_end_of.is_some() &&
                BlockType::closing(&token) == self.parse_until_before_end_of {
            self.tokenizer.push_back(token);
            return Err(())
        }
        if let Some(block_type) = BlockType::opening(&token) {
            self.at_start_of = Some(block_type);
        }
        Ok(token)
    }

    // FIXME: Take an unboxed `FnOnce` closure.
    #[inline]
    pub fn parse_entirely<T>(&mut self, parse: |&mut Parser| -> Result<T, ()>)
                             -> Result<T, ()> {
        let result = parse(self);
        try!(self.expect_exhausted());
        result
    }

    #[inline]
    pub fn parse_comma_separated<T>(&mut self, parse_one: |&mut Parser| -> Result<T, ()>)
                                    -> Result<Vec<T>, ()> {
        let mut values = vec![];
        loop {
            values.push(try!(self.parse_until_before(Delimiter::Comma, |parser| parse_one(parser))));
            match self.next() {
                Err(()) => return Ok(values),
                Ok(Token::Comma) => continue,
                Ok(_) => unreachable!(),
            }
        }
    }

    #[inline]
    pub fn parse_nested_block<T>(&mut self, parse: |&mut Parser| -> Result<T, ()>)
                                 -> Result <T, ()> {
        let block_type = self.at_start_of.take().expect("\
            A nested parser can only be created when a Function, \
            ParenthesisBlock, SquareBracketBlock, or CurlyBracketBlock \
            token was just consumed.\
        ");
        let result;
        // Introduce a new scope to limit duration of nested_parser’s borrow
        {
            let mut nested_parser = Parser {
                tokenizer: MaybeOwned::Borrowed(&mut *self.tokenizer),
                at_start_of: None,
                parse_until_before_end_of: Some(block_type),
                parse_until_before: Delimiter::None,
            };
            result = nested_parser.parse_entirely(parse);
        }
        consume_until_end_of_block(block_type, &mut *self.tokenizer);
        result
    }

    #[inline]
    pub fn parse_until_before<T>(&mut self, delimiters: Delimiters,
                                 parse: |&mut Parser| -> Result<T, ()>)
                                 -> Result <T, ()> {
        let delimiters = self.parse_until_before | delimiters;
        let result;
        // Introduce a new scope to limit duration of nested_parser’s borrow
        {
            let mut delimited_parser = Parser {
                tokenizer: MaybeOwned::Borrowed(&mut *self.tokenizer),
                at_start_of: self.at_start_of.take(),
                parse_until_before_end_of: self.parse_until_before_end_of,
                parse_until_before: delimiters,
            };
            result = delimited_parser.parse_entirely(parse);
        }
        // FIXME: have a special-purpose tokenizer method for this that does less work.
        while let Ok(token) = self.tokenizer.next() {
            if delimiters.contains(Delimiters::from_token(&token)) || (
                self.parse_until_before_end_of.is_some() &&
                BlockType::closing(&token) == self.parse_until_before_end_of
            ) {
                self.tokenizer.push_back(token);
                break
            }
            if let Some(block_type) = BlockType::opening(&token) {
                consume_until_end_of_block(block_type, &mut *self.tokenizer);
            }
        }
        result
    }

    #[inline]
    pub fn parse_until_after<T>(&mut self, delimiters: Delimiters,
                                parse: |&mut Parser| -> Result<T, ()>)
                                -> Result <T, ()> {
        let result = self.parse_until_before(delimiters, parse);
        // Expect exhausted input or a relevant delimiter (which we consume):
        if let Ok(token) = self.next() {
            debug_assert!(delimiters.contains(Delimiters::from_token(&token)));
        }
        result
    }

    #[inline]
    pub fn expect_ident(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Ident(value) => Ok(value),
            token => self.unexpected(token)
        }
    }

    /// Expect an *ident* token whose value is an ASCII-insensitive match for the given value.
    #[inline]
    pub fn expect_ident_matching<'a>(&mut self, expected_value: &str) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Ident(ref value) if value.eq_ignore_ascii_case(expected_value) => Ok(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_string(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::QuotedString(value) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_ident_or_string(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Ident(value) => Ok(value),
            Token::QuotedString(value) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_url(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Url(value) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_url_or_string(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Url(value) => Ok(value),
            Token::QuotedString(value) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_number(&mut self) -> Result<f64, ()> {
        match try!(self.next()) {
            Token::Number(NumericValue { value, .. }) => Ok(value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_integer(&mut self) -> Result<i64, ()> {
        match try!(self.next()) {
            Token::Number(NumericValue { int_value, .. }) => int_value.ok_or(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_percentage(&mut self) -> Result<f64, ()> {
        match try!(self.next()) {
            Token::Percentage(PercentageValue { unit_value, .. }) => Ok(unit_value),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_colon(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Colon => Ok(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_semicolon(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Semicolon => Ok(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_comma(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Comma => Ok(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_delim(&mut self, expected_value: char) -> Result<(), ()> {
        match try!(self.next()) {
            Token::Delim(value) if value == expected_value => Ok(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_curly_bracket_block(&mut self) -> Result<(), ()> {
        match try!(self.next()) {
            Token::CurlyBracketBlock => Ok(()),
            token => self.unexpected(token)
        }
    }

    #[inline]
    pub fn expect_function(&mut self) -> Result<CowString<'i>, ()> {
        match try!(self.next()) {
            Token::Function(name) => Ok(name),
            token => self.unexpected(token)
        }
    }
}

/// Return value indicates whether the end of the input was reached.
fn consume_until_end_of_block(block_type: BlockType, tokenizer: &mut Tokenizer) {
    // FIXME: have a special-purpose tokenizer method for this that does less work.
    while let Ok(ref token) = tokenizer.next() {
        if BlockType::closing(token) == Some(block_type) {
            return
        }
        if let Some(block_type) = BlockType::opening(token) {
            consume_until_end_of_block(block_type, tokenizer);
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "regex1")]
use regex::Regex;
use serde_json::{Value, Map, Number};
use url::percent_encoding::percent_decode;

use merge::merge;
use helpers::{create_array, push_item_to_array};

#[cfg(feature = "regex1")]
lazy_static! {
    static ref PARENT_REGEX: Regex = Regex::new(r"^([^\]\[]+)").unwrap();
    static ref CHILD_REGEX: Regex = Regex::new(r"(\[[^\]\[]*\])").unwrap();
}

type Object = Map<String, Value>;

#[derive(Debug)]
#[allow(missing_copy_implementations)]
pub enum ParseErrorKind {
    DecodingError,
    Other
}

#[derive(Debug)]
pub struct ParseError {
    pub kind: ParseErrorKind,
    pub message: String
}

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

pub fn decode_component(source: &str) -> Result<String,String> {
    let result = percent_decode(source.as_bytes()).decode_utf8_lossy().to_string();
    return Ok(result);
}

fn parse_pair(part: &str) -> (&str, Option<&str>) {
    let separator = part.find("]=")
                        .and_then(|pos| Some(pos+1))
                        .or_else(|| part.find("="));
    match separator {
        None => return (part, None),
        Some(pos) => {
            let key = &part[..pos];
            let val = &part[(pos + 1)..];
            return (key, Some(val));
        }
    }
}

fn parse_pairs(body: &str) -> Vec<(&str, Option<&str>)> {
    let mut pairs = vec![];
    for part in body.split("&") {
        pairs.push(parse_pair(part));
    }
    return pairs
}

#[cfg(feature = "regex1")]
fn parse_key(key: &str) -> ParseResult<Vec<String>> {
    let mut keys: Vec<String> = vec![];

    match PARENT_REGEX.captures(key) {
        Some(captures) => {
            match decode_component(captures.get(1).unwrap().as_str()) {
                Ok(decoded_key) => keys.push(decoded_key),
                Err(err_msg) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err_msg })
            }
        }
        None => ()
    };

    for captures in CHILD_REGEX.captures_iter(key) {
        match decode_component(captures.get(1).unwrap().as_str()) {
            Ok(decoded_key) => keys.push(decoded_key),
            Err(err_msg) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err_msg })
        }
    }

    Ok(keys)
}

#[cfg(not(feature = "regex1"))]
fn parse_key(key: &str) -> ParseResult<Vec<String>> {
    let mut keys: Vec<String> = vec![];

    match key.split(|c| c=='[' || c==']').next() {
        Some(parent) if !parent.is_empty() =>  {
            match decode_component(parent) {
                Ok(decoded_key) => keys.push(decoded_key),
                Err(err_msg) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err_msg })
            }
        }
        _ => ()
    }

    let mut prev_bracket = None;
    for (idx, ch) in key.char_indices() {
        match ch {
            '[' => prev_bracket = Some(idx),
            ']' => {
                if let Some(prev_idx) = prev_bracket {
                    prev_bracket = None;
                    let child = &key[prev_idx..=idx];
                    match decode_component(child) {
                        Ok(decoded_key) => keys.push(decoded_key),
                        Err(err_msg) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err_msg })
                    }
                }
            }
            _ => (),
        }
    }

    Ok(keys)
}

fn cleanup_key(key: &str) -> &str {
    if key.starts_with("[") && key.ends_with("]") {
        &key[1..(key.len()-1)]
    } else {
        key
    }
}

fn create_idx_merger(idx: u64, obj: Value) -> Value {
    let mut tree = Object::new();
    tree.insert("__idx".to_string(), Value::Number(Number::from(idx)));
    tree.insert("__object".to_string(), obj);
    return Value::Object(tree)
}

fn create_object_with_key(key: String, obj: Value) -> Value {
    let mut tree = Object::new();
    tree.insert(key, obj);
    return Value::Object(tree)
}

fn apply_object(keys: &[String], val: Value) -> Value {

    if keys.len() > 0 {
        let key = keys.get(0).unwrap();
        if key == "[]" {
            let mut new_array = create_array();
            let item = apply_object(&keys[1..], val);
            push_item_to_array(&mut new_array, item);
            return new_array;
        } else {
            let key = cleanup_key(key);
            let array_index = key.parse();

            match array_index {
                Ok(idx) => {
                    let result = apply_object(&keys[1..], val);
                    let item = create_idx_merger(idx, result);
                    return item;
                },
                Err(_) => {
                    return create_object_with_key(key.to_string(), apply_object(&keys[1..], val));
                }
            }
        }

    } else {
        return val;
    }
}

pub fn parse(params: &str) -> ParseResult<Value> {
    let tree = Object::new();
    let mut obj = Value::Object(tree);
    let decoded_params = match decode_component(params) {
        Ok(val) => val,
        Err(err) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err })
    };
    let pairs = parse_pairs(&decoded_params);
    for &(key, value) in pairs.iter() {
        let parse_key_res = try!(parse_key(key));
        let key_chain = &parse_key_res[0..];
        let decoded_value = match decode_component(value.unwrap_or("")) {
            Ok(val) => val,
            Err(err) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err })
        };
        let partial = apply_object(key_chain, Value::String(decoded_value));
        merge(&mut obj, &partial);
    }

    Ok(obj)
}

#[cfg(test)]
mod tests {
    use parse;
    use super::parse_pair;
    use serde_json::{Value, to_string};

    fn eq_str(value: Value, string: &str) {
        assert_eq!(&to_string(&value).unwrap(), string)
    }

    #[test]
    fn test_parse_pair() {
        assert_eq!(parse_pair("foo=1"), ("foo", Some("1")));
    }

    #[test]
    fn it_parses_simple_string() {
        eq_str(parse("0=foo").unwrap(), r#"{"0":"foo"}"#);
        eq_str(parse("a[<=>]==23").unwrap(), r#"{"a":{"<=>":"=23"}}"#);
        eq_str(parse(" foo = bar = baz ").unwrap(), r#"{" foo ":" bar = baz "}"#);
    }

    #[test]
    fn it_parses_nested_string() {
        eq_str(parse("a[b][c][d][e][f][g][h]=i").unwrap(),
            r#"{"a":{"b":{"c":{"d":{"e":{"f":{"g":{"h":"i"}}}}}}}}"#);
    }

    #[test]
    fn it_parses_simple_array() {
        eq_str(parse("a=b&a=c&a=d&a=e").unwrap(),
            r#"{"a":["b","c","d","e"]}"#);
    }

    #[test]
    fn it_parses_explicit_array() {
        eq_str(parse("a[]=b&a[]=c&a[]=d").unwrap(),
            r#"{"a":["b","c","d"]}"#);
    }

    #[test]
    fn it_parses_nested_array() {
        eq_str(parse("a[b][]=c&a[b][]=d").unwrap(),
            r#"{"a":{"b":["c","d"]}}"#);
    }

    #[test]
    fn it_allows_to_specify_array_indexes() {
        eq_str(parse("a[0][]=c&a[1][]=d").unwrap(),
            r#"{"a":[["c"],["d"]]}"#);
    }

    #[test]
    fn it_transforms_arrays_to_object() {
        eq_str(parse("foo[0]=bar&foo[bad]=baz").unwrap(),
            r#"{"foo":{"0":"bar","bad":"baz"}}"#);

        eq_str(parse("foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb").unwrap(),
            r#"{"foo":[{"a":"a","b":"b"},{"a":"aa","b":"bb"}]}"#);
    }

    #[test]
    fn it_transforms_standalone_keys() {
        eq_str(parse("foo=bar&baz").unwrap(),
            r#"{"foo":"bar","baz":null}"#);
    }

    #[test]
    fn it_doesnt_produce_empty_keys() {
        eq_str(parse("_r=1&").unwrap(),
            r#"{"_r":"1"}"#);
    }

    #[test]
    fn it_supports_encoded_strings() {
        eq_str(parse("a[b%20c]=c%20d").unwrap(),
            r#"{"a":{"b c":"c d"}}"#);
    }

    #[test]
    fn it_parses_explicit_encoded_array() {
        eq_str(parse("a%5B%5D=b&a%5B%5D=c&a%5B%5D=d").unwrap(),
            r#"{"a":["b","c","d"]}"#);
    }
}
<commit_msg>test(parser): Add test coverage over key-value parsing<commit_after>#[cfg(feature = "regex1")]
use regex::Regex;
use serde_json::{Value, Map, Number};
use url::percent_encoding::percent_decode;

use merge::merge;
use helpers::{create_array, push_item_to_array};

#[cfg(feature = "regex1")]
lazy_static! {
    static ref PARENT_REGEX: Regex = Regex::new(r"^([^\]\[]+)").unwrap();
    static ref CHILD_REGEX: Regex = Regex::new(r"(\[[^\]\[]*\])").unwrap();
}

type Object = Map<String, Value>;

#[derive(Debug)]
#[allow(missing_copy_implementations)]
pub enum ParseErrorKind {
    DecodingError,
    Other
}

#[derive(Debug)]
pub struct ParseError {
    pub kind: ParseErrorKind,
    pub message: String
}

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

pub fn decode_component(source: &str) -> Result<String,String> {
    let result = percent_decode(source.as_bytes()).decode_utf8_lossy().to_string();
    return Ok(result);
}

fn parse_pair(part: &str) -> (&str, Option<&str>) {
    let separator = part.find("]=")
                        .and_then(|pos| Some(pos+1))
                        .or_else(|| part.find("="));
    match separator {
        None => return (part, None),
        Some(pos) => {
            let key = &part[..pos];
            let val = &part[(pos + 1)..];
            return (key, Some(val));
        }
    }
}

fn parse_pairs(body: &str) -> Vec<(&str, Option<&str>)> {
    let mut pairs = vec![];
    for part in body.split("&") {
        pairs.push(parse_pair(part));
    }
    return pairs
}

#[cfg(feature = "regex1")]
fn parse_key(key: &str) -> ParseResult<Vec<String>> {
    let mut keys: Vec<String> = vec![];

    match PARENT_REGEX.captures(key) {
        Some(captures) => {
            match decode_component(captures.get(1).unwrap().as_str()) {
                Ok(decoded_key) => keys.push(decoded_key),
                Err(err_msg) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err_msg })
            }
        }
        None => ()
    };

    for captures in CHILD_REGEX.captures_iter(key) {
        match decode_component(captures.get(1).unwrap().as_str()) {
            Ok(decoded_key) => keys.push(decoded_key),
            Err(err_msg) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err_msg })
        }
    }

    Ok(keys)
}

#[cfg(not(feature = "regex1"))]
fn parse_key(key: &str) -> ParseResult<Vec<String>> {
    let mut keys: Vec<String> = vec![];

    match key.split(|c| c=='[' || c==']').next() {
        Some(parent) if !parent.is_empty() =>  {
            match decode_component(parent) {
                Ok(decoded_key) => keys.push(decoded_key),
                Err(err_msg) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err_msg })
            }
        }
        _ => ()
    }

    let mut prev_bracket = None;
    for (idx, ch) in key.char_indices() {
        match ch {
            '[' => prev_bracket = Some(idx),
            ']' => {
                if let Some(prev_idx) = prev_bracket {
                    prev_bracket = None;
                    let child = &key[prev_idx..=idx];
                    match decode_component(child) {
                        Ok(decoded_key) => keys.push(decoded_key),
                        Err(err_msg) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err_msg })
                    }
                }
            }
            _ => (),
        }
    }

    Ok(keys)
}

fn cleanup_key(key: &str) -> &str {
    if key.starts_with("[") && key.ends_with("]") {
        &key[1..(key.len()-1)]
    } else {
        key
    }
}

fn create_idx_merger(idx: u64, obj: Value) -> Value {
    let mut tree = Object::new();
    tree.insert("__idx".to_string(), Value::Number(Number::from(idx)));
    tree.insert("__object".to_string(), obj);
    return Value::Object(tree)
}

fn create_object_with_key(key: String, obj: Value) -> Value {
    let mut tree = Object::new();
    tree.insert(key, obj);
    return Value::Object(tree)
}

fn apply_object(keys: &[String], val: Value) -> Value {

    if keys.len() > 0 {
        let key = keys.get(0).unwrap();
        if key == "[]" {
            let mut new_array = create_array();
            let item = apply_object(&keys[1..], val);
            push_item_to_array(&mut new_array, item);
            return new_array;
        } else {
            let key = cleanup_key(key);
            let array_index = key.parse();

            match array_index {
                Ok(idx) => {
                    let result = apply_object(&keys[1..], val);
                    let item = create_idx_merger(idx, result);
                    return item;
                },
                Err(_) => {
                    return create_object_with_key(key.to_string(), apply_object(&keys[1..], val));
                }
            }
        }

    } else {
        return val;
    }
}

pub fn parse(params: &str) -> ParseResult<Value> {
    let tree = Object::new();
    let mut obj = Value::Object(tree);
    let decoded_params = match decode_component(params) {
        Ok(val) => val,
        Err(err) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err })
    };
    let pairs = parse_pairs(&decoded_params);
    for &(key, value) in pairs.iter() {
        let parse_key_res = try!(parse_key(key));
        let key_chain = &parse_key_res[0..];
        let decoded_value = match decode_component(value.unwrap_or("")) {
            Ok(val) => val,
            Err(err) => return Err(ParseError{ kind: ParseErrorKind::DecodingError, message: err })
        };
        let partial = apply_object(key_chain, Value::String(decoded_value));
        merge(&mut obj, &partial);
    }

    Ok(obj)
}

#[cfg(test)]
mod tests {
    use parse;
    use super::parse_pair;
    use serde_json::{Value, to_string};

    fn eq_str(value: Value, string: &str) {
        assert_eq!(&to_string(&value).unwrap(), string)
    }

    #[test]
    fn test_parse_pair() {
        assert_eq!(parse_pair("foo=1"), ("foo", Some("1")));
        assert_eq!(parse_pair("empty="), ("empty", Some("")));
        assert_eq!(parse_pair("noval"), ("noval", None));
    }

    #[test]
    fn it_parses_simple_string() {
        eq_str(parse("0=foo").unwrap(), r#"{"0":"foo"}"#);
        eq_str(parse("a[<=>]==23").unwrap(), r#"{"a":{"<=>":"=23"}}"#);
        eq_str(parse(" foo = bar = baz ").unwrap(), r#"{" foo ":" bar = baz "}"#);
    }

    #[test]
    fn it_parses_nested_string() {
        eq_str(parse("a[b][c][d][e][f][g][h]=i").unwrap(),
            r#"{"a":{"b":{"c":{"d":{"e":{"f":{"g":{"h":"i"}}}}}}}}"#);
    }

    #[test]
    fn it_parses_simple_array() {
        eq_str(parse("a=b&a=c&a=d&a=e").unwrap(),
            r#"{"a":["b","c","d","e"]}"#);
    }

    #[test]
    fn it_parses_explicit_array() {
        eq_str(parse("a[]=b&a[]=c&a[]=d").unwrap(),
            r#"{"a":["b","c","d"]}"#);
    }

    #[test]
    fn it_parses_nested_array() {
        eq_str(parse("a[b][]=c&a[b][]=d").unwrap(),
            r#"{"a":{"b":["c","d"]}}"#);
    }

    #[test]
    fn it_allows_to_specify_array_indexes() {
        eq_str(parse("a[0][]=c&a[1][]=d").unwrap(),
            r#"{"a":[["c"],["d"]]}"#);
    }

    #[test]
    fn it_transforms_arrays_to_object() {
        eq_str(parse("foo[0]=bar&foo[bad]=baz").unwrap(),
            r#"{"foo":{"0":"bar","bad":"baz"}}"#);

        eq_str(parse("foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb").unwrap(),
            r#"{"foo":[{"a":"a","b":"b"},{"a":"aa","b":"bb"}]}"#);
    }

    #[test]
    fn it_transforms_standalone_keys() {
        eq_str(parse("foo=bar&baz").unwrap(),
            r#"{"foo":"bar","baz":null}"#);
    }

    #[test]
    fn it_doesnt_produce_empty_keys() {
        eq_str(parse("_r=1&").unwrap(),
            r#"{"_r":"1"}"#);
    }

    #[test]
    fn it_supports_encoded_strings() {
        eq_str(parse("a[b%20c]=c%20d").unwrap(),
            r#"{"a":{"b c":"c d"}}"#);
    }

    #[test]
    fn it_parses_explicit_encoded_array() {
        eq_str(parse("a%5B%5D=b&a%5B%5D=c&a%5B%5D=d").unwrap(),
            r#"{"a":["b","c","d"]}"#);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::borrow::{Cow, Borrow};
use std::hash::Hash;
use std::cmp::min;
use std::fmt;

use tendril::StrTendril;

use fragment::{self, Fragment, InputType, ReturnType};
use codegen::ContentType;

#[derive(Debug)]
pub enum Error {
    Fragment(fragment::Error),
    Other(Cow<'static, str>)
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Fragment(ref e) => write!(f, "during fragment expansion: {}", e),
            Error::Other(ref e) => write!(f, "while parsing: {}", e)
        }
    }
}

impl From<fragment::Error> for Error {
    fn from(error: fragment::Error) -> Error {
        Error::Fragment(error)
    }
}

impl<T: Into<Cow<'static, str>>> From<T> for Error {
    fn from(error: T) -> Error {
        Error::Other(error.into())
    }
}

pub enum ExtensibleMap<'a, K: 'a, V: 'a> {
    Owned(HashMap<K, V>),
    Extended(&'a HashMap<K, V>, HashMap<K, V>)
}

impl<'a, K: Hash + Eq, V> ExtensibleMap<'a, K, V> {
    pub fn extend(base: &'a HashMap<K, V>) -> ExtensibleMap<'a, K, V> {
        ExtensibleMap::Extended(base, HashMap::new())
    }

    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
        match self {
            &mut ExtensibleMap::Owned(ref mut map) => map.insert(key, value),
            &mut ExtensibleMap::Extended(_, ref mut map) => map.insert(key, value),
        }
    }

    pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> where
        K: Borrow<Q>,
        Q: Hash + Eq
    {
        match self {
            &ExtensibleMap::Owned(ref map) => map.get(k),
            &ExtensibleMap::Extended(ref base, ref map) => map.get(k).or_else(|| base.get(k))
        }
    }
}

pub fn parse_content(content: StrTendril, fragments: &ExtensibleMap<&'static str, Box<Fragment>>) -> Result<Vec<ReturnType>, Error> {
    let mut tokens = Vec::new();
    let mut content = Slicer::new(content);

    while let Some(character) = content.next() {
        match character {
            b'{' => match content.next() {
                Some(b'{') => {
                    if content.slice_len() > 2 {
                        tokens.push(ReturnType::String(content.slice_excluding(2)));
                    } else {
                        content.discard();
                    }

                    tokens.push(try!(parse_fragment(&mut content, fragments)));
                },
                None => break,
                _ => {}
            },
            b'\\' => if let Some(b'{') = content.next() {
                content.go_back();
                tokens.push(ReturnType::String(content.slice_excluding(1)));
                content.next();
            },
            _ => {}
        }
    }

    let remaining = content.remaining();
    if remaining.len() > 0 {
        tokens.push(ReturnType::String(remaining));
    }

    Ok(tokens)
}

fn parse_fragment(content: &mut Slicer, fragments: &ExtensibleMap<&'static str, Box<Fragment>>) -> Result<ReturnType, fragment::Error> {
    content.skip_whitespace();
    if let Some(name) = content.take_while(|c| c == b'_' || (c as char).is_alphabetic()) {
        content.skip_whitespace();
        if content.eat(b'(') {
            if let Some(fragment) = fragments.get(&*name) {
                let pattern = fragment.pattern();
                pattern.parse(content, |src, inner| inner_fragment(src, inner, fragments))
                    .and_then(|args| {
                        content.skip_whitespace();
                        match content.next_char() {
                            Some(')') => fragment.process(args),
                            Some(c) => Err(format!("expected ')', but found {}", c).into()),
                            None => Err("expected ')'".into())
                        }
                    }).map_err(|mut e| {
                        e.add_callee(fragment.identifier());
                        e
                    })
            } else {
                Err(format!("'{}' is not a registered fragment", name).into())
            }
        } else if &*name == "end" {
            Ok(ReturnType::End)
        } else if name.len() > 0 {
            Ok(ReturnType::Placeholder(name, ContentType::String(false)))
        } else {
            Err("empty fragment".into())
        }
    } else {
        if let Some(c) = content.next_char() {
            Err(format!("expected an identifier, but found {}", c).into())
        } else {
            Err("expected an identifier".into())
        }
    }
}

fn inner_fragment(content: &mut Slicer, name: StrTendril, fragments: &ExtensibleMap<&'static str, Box<Fragment>>) -> Result<InputType, fragment::Error> {
    if let Some(fragment) = fragments.get(&*name) {
        let pattern = fragment.pattern();
        pattern.parse(content, |src, inner| inner_fragment(src, inner, fragments))
            .and_then(|args| {
                match try!(fragment.process(args)) {
                    ReturnType::Placeholder(name, ty) => Ok(InputType::Placeholder(name, ty)),
                    ReturnType::Logic(cond) => Ok(InputType::Logic(cond)),
                    _ => return Err("inner fragments must only return placeholders and logic".into())
                }
            }).map_err(|mut e| {
                e.add_callee(fragment.identifier());
                e
            })
    } else {
        Err(format!("'{}' is not a registered fragment", name).into())
    }
}

pub struct Slicer {
    src: StrTendril,
    offset: u32,
    length: u32
}

impl Slicer {
    pub fn new(src: StrTendril) -> Slicer {
        Slicer {
            src: src,
            offset: 0,
            length: 0
        }
    }

    pub fn slice(&mut self) -> StrTendril {
        let slice = self.src.subtendril(self.offset, self.length);
        self.offset += self.length;
        self.length = 0;
        slice
    }

    pub fn slice_excluding(&mut self, nbytes: u32) -> StrTendril {
        let len = if self.length >= nbytes {
            self.length - nbytes
        } else {
            0
        };

        let slice = self.src.subtendril(self.offset, len);
        self.offset += self.length;
        self.length = 0;
        slice
    }

    pub fn discard(&mut self) {
        self.offset += self.length;
        self.length = 0;
    }

    pub fn remaining(&mut self) -> StrTendril {
        self.src.subtendril(self.offset, self.src.len32() - self.offset)
    }

    pub fn next(&mut self) -> Option<u8> {
        let index = self.length + self.offset;
        if index < self.src.len32() {
            self.length += 1;
            Some(self.src.as_bytes()[index as usize])
        } else {
            None
        }
    }

    pub fn next_char(&mut self) -> Option<char> {
        let i = (self.offset + self.length) as usize;
        if let Some(c) = self.src[i..].chars().next() {
            self.length += c.len_utf8() as u32;
            Some(c)
        } else {
            None
        }
    }

    pub fn go_back(&mut self) {
        if self.length > 0 {
            self.length -= 1;
        }
    }

    pub fn slice_len(&self) -> u32 {
        self.length
    }

    pub fn offset(&self) -> u32 {
        self.offset
    }

    pub fn jump_to(&mut self, offset: u32) {
        self.offset = min(offset, self.src.len32());
        self.length = 0;
    }

    pub fn skip_whitespace(&mut self) {
        while let Some(c) = self.next() {
            if !(c as char).is_whitespace() {
                self.go_back();
                self.discard();
                break;
            }
        }
    }

    pub fn take_while<F: FnMut(u8) -> bool>(&mut self, mut pred: F) -> Option<StrTendril> {
        while let Some(c) = self.next() {
            if !pred(c) {
                self.go_back();
                return Some(self.slice());
            }
        }

        None
    }

    pub fn eat(&mut self, byte: u8) -> bool {
        match self.next() {
            Some(c) if c == byte => {
                self.discard();
                true
            },
            Some(_) => {
                self.go_back();
                false
            },
            None => false
        }
    }

    pub fn eat_bytes(&mut self, bytes: &[u8]) -> bool {
        let snapshot = self.length;

        for &byte in bytes {
            match self.next() {
                Some(c) => if c != byte {
                    self.length = snapshot;
                    return false;
                },
                None => {
                    self.length = snapshot;
                    return false;
                }
            }
        }

        self.discard();

        true
    }
}
<commit_msg>Parse the end of fragments again<commit_after>use std::collections::HashMap;
use std::borrow::{Cow, Borrow};
use std::hash::Hash;
use std::cmp::min;
use std::fmt;

use tendril::StrTendril;

use fragment::{self, Fragment, InputType, ReturnType};
use codegen::ContentType;

#[derive(Debug)]
pub enum Error {
    Fragment(fragment::Error),
    Other(Cow<'static, str>)
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Fragment(ref e) => write!(f, "during fragment expansion: {}", e),
            Error::Other(ref e) => write!(f, "while parsing: {}", e)
        }
    }
}

impl From<fragment::Error> for Error {
    fn from(error: fragment::Error) -> Error {
        Error::Fragment(error)
    }
}

impl<T: Into<Cow<'static, str>>> From<T> for Error {
    fn from(error: T) -> Error {
        Error::Other(error.into())
    }
}

pub enum ExtensibleMap<'a, K: 'a, V: 'a> {
    Owned(HashMap<K, V>),
    Extended(&'a HashMap<K, V>, HashMap<K, V>)
}

impl<'a, K: Hash + Eq, V> ExtensibleMap<'a, K, V> {
    pub fn extend(base: &'a HashMap<K, V>) -> ExtensibleMap<'a, K, V> {
        ExtensibleMap::Extended(base, HashMap::new())
    }

    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
        match self {
            &mut ExtensibleMap::Owned(ref mut map) => map.insert(key, value),
            &mut ExtensibleMap::Extended(_, ref mut map) => map.insert(key, value),
        }
    }

    pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> where
        K: Borrow<Q>,
        Q: Hash + Eq
    {
        match self {
            &ExtensibleMap::Owned(ref map) => map.get(k),
            &ExtensibleMap::Extended(ref base, ref map) => map.get(k).or_else(|| base.get(k))
        }
    }
}

pub fn parse_content(content: StrTendril, fragments: &ExtensibleMap<&'static str, Box<Fragment>>) -> Result<Vec<ReturnType>, Error> {
    let mut tokens = Vec::new();
    let mut content = Slicer::new(content);

    while let Some(character) = content.next() {
        match character {
            b'{' => match content.next() {
                Some(b'{') => {
                    if content.slice_len() > 2 {
                        tokens.push(ReturnType::String(content.slice_excluding(2)));
                    } else {
                        content.discard();
                    }

                    tokens.push(try!(parse_fragment(&mut content, fragments)));

                    content.skip_whitespace();
                    if !content.eat_bytes(b"}}") {
                        if let Some(c) = content.next_char() {
                            return Err(format!("expected '}}}}', but found '{}'", c).into());
                        } else {
                            return Err("expected '}}', but found nothing".into());
                        }
                    }
                },
                None => break,
                _ => {}
            },
            b'\\' => if let Some(b'{') = content.next() {
                content.go_back();
                tokens.push(ReturnType::String(content.slice_excluding(1)));
                content.next();
            },
            _ => {}
        }
    }

    let remaining = content.remaining();
    if remaining.len() > 0 {
        tokens.push(ReturnType::String(remaining));
    }

    Ok(tokens)
}

fn parse_fragment(content: &mut Slicer, fragments: &ExtensibleMap<&'static str, Box<Fragment>>) -> Result<ReturnType, fragment::Error> {
    content.skip_whitespace();
    if let Some(name) = content.take_while(|c| c == b'_' || (c as char).is_alphabetic()) {
        content.skip_whitespace();
        if content.eat(b'(') {
            if let Some(fragment) = fragments.get(&*name) {
                let pattern = fragment.pattern();
                pattern.parse(content, |src, inner| inner_fragment(src, inner, fragments))
                    .and_then(|args| {
                        content.skip_whitespace();
                        match content.next_char() {
                            Some(')') => fragment.process(args),
                            Some(c) => Err(format!("expected ')', but found {}", c).into()),
                            None => Err("expected ')'".into())
                        }
                    }).map_err(|mut e| {
                        e.add_callee(fragment.identifier());
                        e
                    })
            } else {
                Err(format!("'{}' is not a registered fragment", name).into())
            }
        } else if &*name == "end" {
            Ok(ReturnType::End)
        } else if name.len() > 0 {
            Ok(ReturnType::Placeholder(name, ContentType::String(false)))
        } else {
            Err("empty fragment".into())
        }
    } else {
        if let Some(c) = content.next_char() {
            Err(format!("expected an identifier, but found {}", c).into())
        } else {
            Err("expected an identifier".into())
        }
    }
}

fn inner_fragment(content: &mut Slicer, name: StrTendril, fragments: &ExtensibleMap<&'static str, Box<Fragment>>) -> Result<InputType, fragment::Error> {
    if let Some(fragment) = fragments.get(&*name) {
        let pattern = fragment.pattern();
        pattern.parse(content, |src, inner| inner_fragment(src, inner, fragments))
            .and_then(|args| {
                match try!(fragment.process(args)) {
                    ReturnType::Placeholder(name, ty) => Ok(InputType::Placeholder(name, ty)),
                    ReturnType::Logic(cond) => Ok(InputType::Logic(cond)),
                    _ => return Err("inner fragments must only return placeholders and logic".into())
                }
            }).map_err(|mut e| {
                e.add_callee(fragment.identifier());
                e
            })
    } else {
        Err(format!("'{}' is not a registered fragment", name).into())
    }
}

pub struct Slicer {
    src: StrTendril,
    offset: u32,
    length: u32
}

impl Slicer {
    pub fn new(src: StrTendril) -> Slicer {
        Slicer {
            src: src,
            offset: 0,
            length: 0
        }
    }

    pub fn slice(&mut self) -> StrTendril {
        let slice = self.src.subtendril(self.offset, self.length);
        self.offset += self.length;
        self.length = 0;
        slice
    }

    pub fn slice_excluding(&mut self, nbytes: u32) -> StrTendril {
        let len = if self.length >= nbytes {
            self.length - nbytes
        } else {
            0
        };

        let slice = self.src.subtendril(self.offset, len);
        self.offset += self.length;
        self.length = 0;
        slice
    }

    pub fn discard(&mut self) {
        self.offset += self.length;
        self.length = 0;
    }

    pub fn remaining(&mut self) -> StrTendril {
        self.src.subtendril(self.offset, self.src.len32() - self.offset)
    }

    pub fn next(&mut self) -> Option<u8> {
        let index = self.length + self.offset;
        if index < self.src.len32() {
            self.length += 1;
            Some(self.src.as_bytes()[index as usize])
        } else {
            None
        }
    }

    pub fn next_char(&mut self) -> Option<char> {
        let i = (self.offset + self.length) as usize;
        if let Some(c) = self.src[i..].chars().next() {
            self.length += c.len_utf8() as u32;
            Some(c)
        } else {
            None
        }
    }

    pub fn go_back(&mut self) {
        if self.length > 0 {
            self.length -= 1;
        }
    }

    pub fn slice_len(&self) -> u32 {
        self.length
    }

    pub fn offset(&self) -> u32 {
        self.offset
    }

    pub fn jump_to(&mut self, offset: u32) {
        self.offset = min(offset, self.src.len32());
        self.length = 0;
    }

    pub fn skip_whitespace(&mut self) {
        while let Some(c) = self.next() {
            if !(c as char).is_whitespace() {
                self.go_back();
                self.discard();
                break;
            }
        }
    }

    pub fn take_while<F: FnMut(u8) -> bool>(&mut self, mut pred: F) -> Option<StrTendril> {
        while let Some(c) = self.next() {
            if !pred(c) {
                self.go_back();
                return Some(self.slice());
            }
        }

        None
    }

    pub fn eat(&mut self, byte: u8) -> bool {
        match self.next() {
            Some(c) if c == byte => {
                self.discard();
                true
            },
            Some(_) => {
                self.go_back();
                false
            },
            None => false
        }
    }

    pub fn eat_bytes(&mut self, bytes: &[u8]) -> bool {
        let snapshot = self.length;

        for &byte in bytes {
            match self.next() {
                Some(c) => if c != byte {
                    self.length = snapshot;
                    return false;
                },
                None => {
                    self.length = snapshot;
                    return false;
                }
            }
        }

        self.discard();

        true
    }
}
<|endoftext|>