<commit_before>pub mod builtins;

use std::collections::HashMap;
use std::path::PathBuf;
use std::io;
use std::io::{Read, Write};
use std::collections::hash_map::Entry;

#[derive(PartialEq, Debug, Clone)]
pub struct State {
    cwd: PathBuf,
    environment: HashMap<String, String>,
    aliases: HashMap<String, String>,
    argv: Vec<String>,
    argc: usize,
}

impl State {
    pub fn new(cwd: String) -> State {
        State {
            cwd: PathBuf::from(cwd),
            environment: HashMap::new(),
            aliases: HashMap::new(),
            argv: Vec::new(),
            argc: 0,
        }
    }
}

pub fn run(initial_state: State) {
    let mut builtins = builtins::load();
    let mut s = initial_state.clone();

    println!("Welcome to rsh! {:?}", s);

    loop {

        print!("\n");
        print!("{} -> ", s.cwd.to_str().unwrap());

        // this forces the prompt to print
        io::stdout().flush();

        // read the user input
        let mut input = String::new();
        io::stdin().read_line(&mut input).unwrap();

        s.argv = parse_args(&input);
        s.argc = s.argv.len();

        print!("\n");
        println!("Input: {}\nState: {:?}", input, s);

        let first_arg = s.argv.get(0).unwrap().clone();
        if let Entry::Occupied(f) = builtins.entry(String::from(first_arg)) {
            let bn = f.get();
            s = bn(s.clone());
        }
    }
}

#[derive(PartialEq)]
enum BuildType {
    None,
    Single,
    Double,
}

struct ParseResult {
    result: Vec<String>,
    completed: bool,
    build_string: String,
    build_type: BuildType,
}

fn parse_args(args: &String) -> Vec<String> {
    let mut parse_result: ParseResult = ParseResult {
        result: Vec::new(),
        completed: false,
        build_string: String::from(""),
        build_type: BuildType::None,
    };

    if args.len() == 0 {
        return parse_result.result;
    }

    let mut argstr = args.clone();
    loop {
        parse_string_into_vec(&argstr, &mut parse_result);

        if (parse_result.completed) {
            break;
        }

        match parse_result.build_type {
            BuildType::Single => print!("quote> "),
            BuildType::Double => print!("dquote> "),
            _ => {}
        }
        io::stdout().flush();
        argstr = String::from("");
        io::stdin().read_line(&mut argstr).unwrap();
    }

    let result: Vec<String> = parse_result.result
        .into_iter()
        .filter(|s| s.len() > 0)
        .collect();

    result
}

fn parse_string_into_vec(string: &String, parse_result: &mut ParseResult) {
    let &mut ParseResult { ref mut build_string,
                           ref mut build_type,
                           ref mut completed,
                           ref mut result } = parse_result;
    let mut iter = string.chars().peekable();

    while let Some(c) = iter.next() {
        match c {
            '\'' => {
                match *build_type {
                    BuildType::Single => {
                        *build_type = BuildType::None;
                        if iter.peek() == Some(&' ') {
                            result.push(build_string.clone());
                            *build_string = String::from("");
                        }
                    }

                    BuildType::None => {
                        *build_type = BuildType::Single;
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            '\"' => {
                match *build_type {
                    BuildType::Double => {
                        *build_type = BuildType::None;
                        if iter.peek() == Some(&' ') {
                            result.push(build_string.clone());
                            *build_string = String::from("");
                        }
                    }

                    BuildType::None => {
                        *build_type = BuildType::Double;
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            ' ' => {
                match *build_type {
                    BuildType::None => {
                        result.push(build_string.clone());
                        *build_string = String::from("");
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            _ => {
                build_string.push(c);
            }
        }
    }

    if *build_type == BuildType::None {
        result.push(build_string.clone());
        *completed = true;
    }
}

#[test]
fn parse_args_test() {
    // parse empty string
    {
        let expected: Vec<String> = Vec::new();
        let result = parse_args(&String::from(""));
        assert_eq!(result, expected);
    }

    // parse single-word string
    {
        let expected: Vec<String> = vec!["echo".to_string()];
        let result = parse_args(&String::from("echo"));
        assert_eq!(result, expected);
    }

    // parse single-word string inside quotes
    {
        let expected = vec!["echo".to_string()];
        let result = parse_args(&String::from("\"echo\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with closed quotes section
    {
        let expected = vec!["echo".to_string(), "-n".into(), "Hello Dear World".into()];
        let result = parse_args(&String::from("echo -n \"Hello Dear World\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with multiple closed quotes sections
    {
        let expected = vec!["echo".to_string(), "Hello".into(), "Dear World".into()];
        let result = parse_args(&String::from("echo \"Hello\" \"Dear World\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with no spaces around single quotes
    {
        let expected = vec!["echo".to_string(), "helloworld".into()];
        let result = parse_args(&String::from("echo 'hello'world"));
        assert_eq!(result, expected);
    }

    // parse multi-word string with no spaces around double quotes
    {
        let expected = vec!["echo".to_string(), "helloworld".into()];
        let result = parse_args(&String::from("echo \"hello\"world"));
        assert_eq!(result, expected);
    }

    // allow double quotes inside single quotes
    {
        let expected = vec!["\"".to_string()];
        let result = parse_args(&String::from("'\"'"));
        assert_eq!(result, expected);
    }

    // allow single quotes inside double quotes
    {
        let expected = vec!["\'".to_string()];
        let result = parse_args(&String::from("\"\'\""));
        assert_eq!(result, expected);
    }
}
<commit_msg>Update parse_string_into_vec to ignore final newline<commit_after>pub mod builtins;

use std::collections::HashMap;
use std::path::PathBuf;
use std::io;
use std::io::{Read, Write};
use std::collections::hash_map::Entry;

#[derive(PartialEq, Debug, Clone)]
pub struct State {
    cwd: PathBuf,
    environment: HashMap<String, String>,
    aliases: HashMap<String, String>,
    argv: Vec<String>,
    argc: usize,
}

impl State {
    pub fn new(cwd: String) -> State {
        State {
            cwd: PathBuf::from(cwd),
            environment: HashMap::new(),
            aliases: HashMap::new(),
            argv: Vec::new(),
            argc: 0,
        }
    }
}

pub fn run(initial_state: State) {
    let mut builtins = builtins::load();
    let mut s = initial_state.clone();

    println!("Welcome to rsh! {:?}", s);

    loop {

        print!("\n");
        print!("{} -> ", s.cwd.to_str().unwrap());

        // this forces the prompt to print
        io::stdout().flush();

        // read the user input
        let mut input = String::new();
        io::stdin().read_line(&mut input).unwrap();

        s.argv = parse_args(&input);
        s.argc = s.argv.len();

        print!("\n");
        println!("Input: {}\nState: {:?}", input, s);

        let first_arg = s.argv.get(0).unwrap().clone();
        if let Entry::Occupied(f) = builtins.entry(String::from(first_arg)) {
            let bn = f.get();
            s = bn(s.clone());
        }
    }
}

#[derive(PartialEq)]
enum BuildType {
    None,
    Single,
    Double,
}

struct ParseResult {
    result: Vec<String>,
    completed: bool,
    build_string: String,
    build_type: BuildType,
}

fn parse_args(args: &String) -> Vec<String> {
    let mut parse_result: ParseResult = ParseResult {
        result: Vec::new(),
        completed: false,
        build_string: String::from(""),
        build_type: BuildType::None,
    };

    if args.len() == 0 {
        return parse_result.result;
    }

    let mut argstr = args.clone();
    loop {
        parse_string_into_vec(&argstr, &mut parse_result);

        if (parse_result.completed) {
            break;
        }

        match parse_result.build_type {
            BuildType::Single => print!("quote> "),
            BuildType::Double => print!("dquote> "),
            _ => {}
        }
        io::stdout().flush();
        argstr = String::from("");
        io::stdin().read_line(&mut argstr).unwrap();
    }

    let result: Vec<String> = parse_result.result
        .into_iter()
        .filter(|s| s.len() > 0)
        .collect();

    result
}

fn parse_string_into_vec(string: &String, parse_result: &mut ParseResult) {
    let &mut ParseResult { ref mut build_string,
                           ref mut build_type,
                           ref mut completed,
                           ref mut result } = parse_result;
    let mut iter = string.chars().peekable();

    while let Some(c) = iter.next() {
        match c {
            '\'' => {
                match *build_type {
                    BuildType::Single => {
                        *build_type = BuildType::None;
                        if iter.peek() == Some(&' ') {
                            result.push(build_string.clone());
                            *build_string = String::from("");
                        }
                    }

                    BuildType::None => {
                        *build_type = BuildType::Single;
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            '\"' => {
                match *build_type {
                    BuildType::Double => {
                        *build_type = BuildType::None;
                        if iter.peek() == Some(&' ') {
                            result.push(build_string.clone());
                            *build_string = String::from("");
                        }
                    }

                    BuildType::None => {
                        *build_type = BuildType::Double;
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            ' ' => {
                match *build_type {
                    BuildType::None => {
                        result.push(build_string.clone());
                        *build_string = String::from("");
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            '\n' => {
                match iter.peek() {
                    Some(_) => build_string.push(c),
                    None => {}
                }
            }

            _ => {
                build_string.push(c);
            }
        }
    }

    if *build_type == BuildType::None {
        *completed = true;
    }

    result.push(build_string.clone());
    *build_string = String::from("");
}

#[test]
fn parse_args_test() {
    // parse empty string
    {
        let expected: Vec<String> = Vec::new();
        let result = parse_args(&String::from(""));
        assert_eq!(result, expected);
    }

    // parse single-word string
    {
        let expected: Vec<String> = vec!["echo".to_string()];
        let result = parse_args(&String::from("echo"));
        assert_eq!(result, expected);
    }

    // parse single-word string inside quotes
    {
        let expected = vec!["echo".to_string()];
        let result = parse_args(&String::from("\"echo\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with closed quotes section
    {
        let expected = vec!["echo".to_string(), "-n".into(), "Hello Dear World".into()];
        let result = parse_args(&String::from("echo -n \"Hello Dear World\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with multiple closed quotes sections
    {
        let expected = vec!["echo".to_string(), "Hello".into(), "Dear World".into()];
        let result = parse_args(&String::from("echo \"Hello\" \"Dear World\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with no spaces around single quotes
    {
        let expected = vec!["echo".to_string(), "helloworld".into()];
        let result = parse_args(&String::from("echo 'hello'world"));
        assert_eq!(result, expected);
    }

    // parse multi-word string with no spaces around double quotes
    {
        let expected = vec!["echo".to_string(), "helloworld".into()];
        let result = parse_args(&String::from("echo \"hello\"world"));
        assert_eq!(result, expected);
    }

    // allow double quotes inside single quotes
    {
        let expected = vec!["\"".to_string()];
        let result = parse_args(&String::from("'\"'"));
        assert_eq!(result, expected);
    }

    // allow single quotes inside double quotes
    {
        let expected = vec!["\'".to_string()];
        let result = parse_args(&String::from("\"\'\""));
        assert_eq!(result, expected);
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The SAX-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[comment = "Wrapper for libxml2's SAX parser."];
#[crate_id = "github.com/bjz/sax-rs#sax:0.1"];

#[crate_type = "lib"];

#[feature(globs)];

extern crate sync;

use std::cast;
use std::comm::{Receiver, channel};
use std::libc::{c_char, c_int};
use std::str;
use std::io::{File, IoResult};
use std::fmt;
// use std::task;

use error::ErrorData;

pub mod error;
pub mod ffi;
mod extfn;

/// Events to be sent by the parser.
#[deriving(Eq, Clone)]
pub enum ParseEvent {
    /// The document has begun to be processed.
    StartDocument,
    /// The document processing has finished.
    EndDocument,
    /// An opening tag has was parsed.
    StartElement(~str, Attributes),
    /// A closing tag was parsed.
    EndElement(~str),
    /// Some characters between tags have been recived.
    Characters(~str),
    /// A comment tag was parsed.
    Comment(~str),
    /// A `CDATA` block was parsed.
    CdataBlock(~str),
}

impl fmt::Show for ParseEvent {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            StartDocument => write!(fmt.buf, "START DOCUMENT"),
            EndDocument => write!(fmt.buf, "END DOCUMENT"),
            StartElement(ref name, ref atts) => write!(fmt.buf, "<{}{}>", *name, atts),
            EndElement(ref name) => write!(fmt.buf, "</{}>", *name),
            Characters(ref ch) => write!(fmt.buf, "{}", ch.clone()),
            Comment(ref value) => write!(fmt.buf, "", *value),
            CdataBlock(ref value) => write!(fmt.buf, "<![CDATA[{}]]>", *value),
        }
    }
}

#[deriving(Eq, Clone)]
pub struct Attribute {
    name: ~str,
    value: ~str,
}

/// A list of attributes
#[deriving(Eq, Clone)]
pub struct Attributes(~[Attribute]);

impl Attributes {
    unsafe fn from_buf(atts: **ffi::xmlChar) -> Attributes {
        let mut ret = ~[];
        let mut ptr = atts as **c_char;
        while !ptr.is_null() && !(*ptr).is_null() {
            ret.push(
                Attribute {
                    name: str::raw::from_c_str(*ptr),
                    value: str::raw::from_c_str(*ptr.offset(1)),
                }
            );
            ptr = ptr.offset(2);
        }
        Attributes(ret)
    }

    pub fn find<'a>(&'a self, name: &str) -> Option<&'a str> {
        let Attributes(ref s) = *self;
        s.iter()
         .find(|att| name == att.name)
         .map(|att| att.value.as_slice())
    }

    pub fn get<'a>(&'a self, name: &str) -> &'a str {
        self.find(name).expect(format!("Could not find an attribute with the name \"{}\"", name))
    }

    pub fn find_clone(&self, name: &str) -> Option<~str> {
        self.find(name).map(|v| v.to_owned())
    }

    pub fn get_clone(&self, name: &str) -> ~str {
        self.get(name).to_owned()
    }
}

impl fmt::Show for Attributes {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let Attributes(ref s) = *self;
        write!(fmt.buf, "{}", s.iter().map(|att| {
                                  format!(" {}=\"{}\"", att.name, att.value)
                              }).to_owned_vec().concat())
    }
}

/// Either a parse event wrapped in `Ok` or some Error data wrapped in `Err`.
pub type ParseResult = Result<ParseEvent, ErrorData>;

/// Parses the entire XML string.
///
/// # Returns
///
/// A receiver that recieves parse results.
///
/// # Example
///
/// ~~~rust
/// let parser = parse_str("<yo>hullo!</yo>");
/// for result in parser.iter() {
///     match result {
///         Ok(StartDocument) => (),
///         Ok(EndDocument) => break,
///         Ok(event) => println!("{}", event.to_str()),
///         Err(err) => println!("{}", err.to_str()),
///     }
/// }
/// ~~~
#[inline(never)]
pub fn parse_str(src: &str) -> Receiver<ParseResult> {
    // ensure that the xml library is ready for use
    use sync::one::{Once, ONCE_INIT};
    static mut INIT: Once = ONCE_INIT;
    unsafe {
        INIT.doit(|| {
            ffi::xmlInitParser();
            std::rt::at_exit(proc() ffi::xmlCleanupParser());
        })
    }

    let len = src.len() as c_int;
    src.to_c_str().with_ref(|c_str| {
        let (sender, receiver) = channel();
        // do task::spawn {
            unsafe {
                ffi::xmlSAXUserParseMemory(&extfn::new_handler(),
                                           cast::transmute(&sender),
                                           c_str, len);
            }
        // }
        receiver
    })
}

pub fn parse_file(path: &Path) -> IoResult<Receiver<ParseResult> > {
  File::open(path)
    .and_then( |mut file| {
      file.read_to_str()
    })
    .and_then( |contents| {
      Ok(parse_str(contents))
    })
}

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

    fn get_mock_atts() -> Attributes {
        Attributes(~[
            Attribute { name: ~"foo", value: ~"0" },
            Attribute { name: ~"bar", value: ~"1" },
            Attribute { name: ~"baz", value: ~"2" }
        ])
    }

    #[test]
    fn test_att_get() {
        let atts = get_mock_atts();
        assert_eq!(atts.get("foo"), "0");
        assert_eq!(atts.get("bar"), "1");
        assert_eq!(atts.get("baz"), "2");
    }

    #[test]
    fn test_att_find() {
        let atts = get_mock_atts();
        assert_eq!(atts.find("foo"), Some("0"));
        assert_eq!(atts.find("bar"), Some("1"));
        assert_eq!(atts.find("baz"), Some("2"));
    }

    #[test]
    fn test() {
        let sax = parse_str(
            "<hello><this />test</hello>"
        );
        loop {
            match sax.recv() {
                Ok(StartDocument) => (),
                Ok(EndDocument) => break,
                Ok(event) => println!("{}", event.to_str()),
                Err(err) => println!("{}", err.to_str()),
            }
        }
    }
}
<commit_msg>Use vec_ng<commit_after>// Copyright 2013 The SAX-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[comment = "Wrapper for libxml2's SAX parser."];
#[crate_id = "github.com/bjz/sax-rs#sax:0.1"];

#[crate_type = "lib"];

#[feature(globs)];

extern crate sync;

use std::cast;
use std::comm::{Receiver, channel};
use std::libc::{c_char, c_int};
use std::str;
use std::io::{File, IoResult};
use std::fmt;
use std::vec_ng::Vec;
// use std::task;

use error::ErrorData;

pub mod error;
pub mod ffi;
mod extfn;

/// Events to be sent by the parser.
#[deriving(Eq, Clone)]
pub enum ParseEvent {
    /// The document has begun to be processed.
    StartDocument,
    /// The document processing has finished.
    EndDocument,
    /// An opening tag has was parsed.
    StartElement(~str, Attributes),
    /// A closing tag was parsed.
    EndElement(~str),
    /// Some characters between tags have been recived.
    Characters(~str),
    /// A comment tag was parsed.
    Comment(~str),
    /// A `CDATA` block was parsed.
    CdataBlock(~str),
}

impl fmt::Show for ParseEvent {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            StartDocument => write!(fmt.buf, "START DOCUMENT"),
            EndDocument => write!(fmt.buf, "END DOCUMENT"),
            StartElement(ref name, ref atts) => write!(fmt.buf, "<{}{}>", *name, atts),
            EndElement(ref name) => write!(fmt.buf, "</{}>", *name),
            Characters(ref ch) => write!(fmt.buf, "{}", ch.clone()),
            Comment(ref value) => write!(fmt.buf, "", *value),
            CdataBlock(ref value) => write!(fmt.buf, "<![CDATA[{}]]>", *value),
        }
    }
}

#[deriving(Eq, Clone)]
pub struct Attribute {
    name: ~str,
    value: ~str,
}

/// A list of attributes
#[deriving(Eq, Clone)]
pub struct Attributes(Vec<Attribute>);

impl Attributes {
    unsafe fn from_buf(atts: **ffi::xmlChar) -> Attributes {
        let mut ret = Vec::new();
        let mut ptr = atts as **c_char;
        while !ptr.is_null() && !(*ptr).is_null() {
            ret.push(
                Attribute {
                    name: str::raw::from_c_str(*ptr),
                    value: str::raw::from_c_str(*ptr.offset(1)),
                }
            );
            ptr = ptr.offset(2);
        }
        Attributes(ret)
    }

    pub fn find<'a>(&'a self, name: &str) -> Option<&'a str> {
        let Attributes(ref s) = *self;
        s.iter()
         .find(|att| name == att.name)
         .map(|att| att.value.as_slice())
    }

    pub fn get<'a>(&'a self, name: &str) -> &'a str {
        self.find(name).expect(format!("Could not find an attribute with the name \"{}\"", name))
    }

    pub fn find_clone(&self, name: &str) -> Option<~str> {
        self.find(name).map(|v| v.to_owned())
    }

    pub fn get_clone(&self, name: &str) -> ~str {
        self.get(name).to_owned()
    }
}

impl fmt::Show for Attributes {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let Attributes(ref s) = *self;
        for att in s.iter() {
            try!(write!(fmt.buf, " {}=\"{}\"", att.name, att.value));
        }
        Ok(())
    }
}

/// Either a parse event wrapped in `Ok` or some Error data wrapped in `Err`.
pub type ParseResult = Result<ParseEvent, ErrorData>;

/// Parses the entire XML string.
///
/// # Returns
///
/// A receiver that recieves parse results.
///
/// # Example
///
/// ~~~rust
/// let parser = parse_str("<yo>hullo!</yo>");
/// for result in parser.iter() {
///     match result {
///         Ok(StartDocument) => (),
///         Ok(EndDocument) => break,
///         Ok(event) => println!("{}", event.to_str()),
///         Err(err) => println!("{}", err.to_str()),
///     }
/// }
/// ~~~
#[inline(never)]
pub fn parse_str(src: &str) -> Receiver<ParseResult> {
    // ensure that the xml library is ready for use
    use sync::one::{Once, ONCE_INIT};
    static mut INIT: Once = ONCE_INIT;
    unsafe {
        INIT.doit(|| {
            ffi::xmlInitParser();
            std::rt::at_exit(proc() ffi::xmlCleanupParser());
        })
    }

    let len = src.len() as c_int;
    src.to_c_str().with_ref(|c_str| {
        let (sender, receiver) = channel();
        // do task::spawn {
            unsafe {
                ffi::xmlSAXUserParseMemory(&extfn::new_handler(),
                                           cast::transmute(&sender),
                                           c_str, len);
            }
        // }
        receiver
    })
}

pub fn parse_file(path: &Path) -> IoResult<Receiver<ParseResult> > {
  File::open(path)
    .and_then( |mut file| {
      file.read_to_str()
    })
    .and_then( |contents| {
      Ok(parse_str(contents))
    })
}

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

    fn get_mock_atts() -> Attributes {
        Attributes(Vec::from_slice([
            Attribute { name: ~"foo", value: ~"0" },
            Attribute { name: ~"bar", value: ~"1" },
            Attribute { name: ~"baz", value: ~"2" }
        ]))
    }

    #[test]
    fn test_att_get() {
        let atts = get_mock_atts();
        assert_eq!(atts.get("foo"), "0");
        assert_eq!(atts.get("bar"), "1");
        assert_eq!(atts.get("baz"), "2");
    }

    #[test]
    fn test_att_find() {
        let atts = get_mock_atts();
        assert_eq!(atts.find("foo"), Some("0"));
        assert_eq!(atts.find("bar"), Some("1"));
        assert_eq!(atts.find("baz"), Some("2"));
    }

    #[test]
    fn test() {
        let sax = parse_str(
            "<hello><this />test</hello>"
        );
        loop {
            match sax.recv() {
                Ok(StartDocument) => (),
                Ok(EndDocument) => break,
                Ok(event) => println!("{}", event.to_str()),
                Err(err) => println!("{}", err.to_str()),
            }
        }
    }
}
<|endoftext|>


<commit_before>//
// Copyright:: Copyright (c) 2015 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

/// This module is responsible for handling the .delivery/config.json file

use std::collections::HashMap;
use std::default::Default;
use std::fs::File;
use std::io::prelude::*;
use std::path::PathBuf;

use rustc_serialize::json;
use rustc_serialize::json::DecoderError;

use errors::{DeliveryError, Kind};
use types::DeliveryResult;
use git;
use utils::{walk_tree_for_path, read_file, copy_recursive, file_needs_updated};
use utils::path_join_many::PathJoinMany;

pub mod project;

#[derive(RustcEncodable, RustcDecodable, Clone)]
pub struct DeliveryConfig {
    pub version: String,
    pub build_cookbook: HashMap<String, String>,
    pub skip_phases: Option<Vec<String>>,
    pub build_nodes: Option<HashMap<String, Vec<String>>>,
    pub dependencies: Option<Vec<String>>
}

// v1 config, deprecated, but still supported
#[derive(RustcDecodable)]
pub struct DeliveryConfigV1 {
    pub version: String,
    pub build_cookbook: String,
    pub skip_phases: Option<Vec<String>>,
    pub build_nodes: Option<HashMap<String, Vec<String>>>
}

impl Default for DeliveryConfig {
    fn default() -> DeliveryConfig {
        let mut build_cookbook = HashMap::new();
        build_cookbook.insert("name".to_string(),
                              "build_cookbook".to_string());
        build_cookbook.insert("path".to_string(),
                              ".delivery/build_cookbook".to_string());
        DeliveryConfig {
            version: "2".to_string(),
            build_cookbook: build_cookbook,
            skip_phases: Some(Vec::new()),
            build_nodes: Some(HashMap::new()),
            dependencies: Some(Vec::new())
        }
    }
}

impl DeliveryConfig {
    /// Copy a provided `config.json` file to `.delivery/` of
    /// the project root path. Also verify that the config is
    /// valid and finally add/commit the changes.
    /// If the config already exists, skip this process.
    pub fn copy_config_file(config_f: &PathBuf,
                            proj_path: &PathBuf) -> DeliveryResult<Option<String>> {
        let write_path = DeliveryConfig::config_file_path(proj_path);

        // If a config.json already exists, check to see if it is exactly
        // the same as what we want to copy to it.
        if !try!(file_needs_updated(config_f, &write_path)) {
            return Ok(None)
        }

        try!(copy_recursive(config_f, &write_path));
        try!(DeliveryConfig::validate_config_file(proj_path));
        let content = try!(read_file(&write_path));
        Ok(Some(content))
    }

    pub fn git_add_commit_config(proj_path: &PathBuf) -> DeliveryResult<bool> {
        let config_path = DeliveryConfig::config_file_path(proj_path);
        let config_path_str = &config_path.to_str().unwrap();
        try!(git::git_command(&["add", &config_path_str], proj_path));

        // Commit the changes made in .delivery but detect if nothing has changed,
        // if that is the case, we are Ok() to continue
        match git::git_commit("Adds custom Delivery config") {
          Ok(_) => Ok(true),
          Err(DeliveryError{ kind: Kind::EmptyGitCommit, .. }) => Ok(false),
          Err(e) => Err(e)
        }
    }

    pub fn config_file_path(proj_path: &PathBuf) -> PathBuf {
        proj_path.join_many(&[".delivery", "config.json"])
    }

    fn find_config_file(proj_path: &PathBuf) -> DeliveryResult<PathBuf> {
        match walk_tree_for_path(proj_path, ".delivery/config.json") {
            Some(p) => {
                debug!("found config: {:?}", p);
                Ok(p)
            },
            None => Err(DeliveryError{kind: Kind::MissingProjectConfig,
                                      detail: None})
        }
    }

    pub fn validate_config_file(proj_path: &PathBuf) -> DeliveryResult<bool> {
        let config_file_path = try!(DeliveryConfig::find_config_file(proj_path));
        let mut config_file = try!(File::open(&config_file_path));
        let mut config_file_content = String::new();
        try!(config_file.read_to_string(&mut config_file_content));
        let config_file_content_str = config_file_content.trim();
        // try to parse it as v2
        let parse_v2_result: Result<DeliveryConfig, DecoderError> = json::decode(config_file_content_str);
        let result = match parse_v2_result {
            Ok(_) => Ok(true),
            Err(_) => {
                // then try as v1
                let parse_v1_result: Result<DeliveryConfigV1, DecoderError> = json::decode(config_file_content_str);
                match parse_v1_result {
                    Ok(_) => Ok(true),
                    Err(e) => Err(e)
                }
            }
        };
        // convert any error in a delivery error
        let boolean_result = try!(result);
        Ok(boolean_result)
    }

}
<commit_msg>Properly load DeliveryConfig<commit_after>//
// Copyright:: Copyright (c) 2015 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

/// This module is responsible for handling the .delivery/config.json file

use std::collections::HashMap;
use std::default::Default;
use std::fs::File;
use std::io::prelude::*;
use std::path::PathBuf;
use rustc_serialize::json;
use errors::{DeliveryError, Kind};
use types::DeliveryResult;
use git;
use utils::{walk_tree_for_path, read_file, copy_recursive, file_needs_updated};
use utils::path_join_many::PathJoinMany;

pub mod project;

#[derive(RustcEncodable, RustcDecodable, Clone)]
pub struct DeliveryConfig {
    pub version: String,
    pub build_cookbook: HashMap<String, String>,
    pub skip_phases: Option<Vec<String>>,
    pub build_nodes: Option<HashMap<String, Vec<String>>>,
    pub dependencies: Option<Vec<String>>
}

impl Default for DeliveryConfig {
    fn default() -> DeliveryConfig {
        let mut build_cookbook = HashMap::new();
        build_cookbook.insert("name".to_string(),
                              "build_cookbook".to_string());
        build_cookbook.insert("path".to_string(),
                              ".delivery/build_cookbook".to_string());
        DeliveryConfig {
            version: "2".to_string(),
            build_cookbook: build_cookbook,
            skip_phases: Some(Vec::new()),
            build_nodes: Some(HashMap::new()),
            dependencies: Some(Vec::new()),
        }
    }
}

impl DeliveryConfig {
    /// Copy a provided `config.json` file to `.delivery/` of
    /// the project root path. Also verify that the config is
    /// valid and finally add/commit the changes.
    /// If the config already exists, skip this process.
    pub fn copy_config_file(config_f: &PathBuf,
                            proj_path: &PathBuf) -> DeliveryResult<Option<String>> {
        let write_path = DeliveryConfig::config_file_path(proj_path);

        // If a config.json already exists, check to see if it is exactly
        // the same as what we want to copy to it.
        if !try!(file_needs_updated(config_f, &write_path)) {
            return Ok(None)
        }

        try!(copy_recursive(config_f, &write_path));
        try!(DeliveryConfig::validate_config_file(proj_path));
        let content = try!(read_file(&write_path));
        Ok(Some(content))
    }

    pub fn git_add_commit_config(proj_path: &PathBuf) -> DeliveryResult<bool> {
        let config_path = DeliveryConfig::config_file_path(proj_path);
        let config_path_str = &config_path.to_str().unwrap();
        try!(git::git_command(&["add", &config_path_str], proj_path));

        // Commit the changes made in .delivery but detect if nothing has changed,
        // if that is the case, we are Ok() to continue
        match git::git_commit("Adds custom Delivery config") {
          Ok(_) => Ok(true),
          Err(DeliveryError{ kind: Kind::EmptyGitCommit, .. }) => Ok(false),
          Err(e) => Err(e)
        }
    }

    pub fn config_file_path(proj_path: &PathBuf) -> PathBuf {
        proj_path.join_many(&[".delivery", "config.json"])
    }

    fn find_config_file(proj_path: &PathBuf) -> DeliveryResult<PathBuf> {
        match walk_tree_for_path(proj_path, ".delivery/config.json") {
            Some(p) => {
                debug!("found config: {:?}", p);
                Ok(p)
            },
            None => Err(DeliveryError{kind: Kind::MissingProjectConfig,
                                      detail: None})
        }
    }

    pub fn validate_config_file(proj_path: &PathBuf) -> DeliveryResult<bool> {
        let result = match DeliveryConfig::load_config(proj_path) {
            Ok(_) => Ok(true),
            Err(_) => {
                // Lets try as v1
                match DeliveryConfigV1::load_config(proj_path) {
                    Ok(_) => Ok(true),
                    Err(e) => Err(e)
                }
            }
        };
        // convert any error in a delivery error
        let boolean_result = try!(result);
        Ok(boolean_result)
    }

    pub fn load_config(p_path: &PathBuf) -> DeliveryResult<DeliveryConfig> {
        let config_path = try!(DeliveryConfig::find_config_file(p_path));
        let mut config_file = try!(File::open(&config_path));
        let mut config_json = String::new();
        try!(config_file.read_to_string(&mut config_json));
        let json = try!(json::decode(&config_json));
        Ok(json)
    }
}

// v1 config, deprecated, but still supported
#[derive(RustcDecodable)]
pub struct DeliveryConfigV1 {
    pub version: String,
    pub build_cookbook: String,
    pub skip_phases: Option<Vec<String>>,
    pub build_nodes: Option<HashMap<String, Vec<String>>>
}

impl Default for DeliveryConfigV1 {
    fn default() -> DeliveryConfigV1 {
        DeliveryConfigV1 {
            version: "1".to_string(),
            build_cookbook: "./.delivery/build_cookbook".to_string(),
            skip_phases: Some(Vec::new()),
            build_nodes: Some(HashMap::new()),
        }
    }
}

impl DeliveryConfigV1 {
    pub fn load_config(p_path: &PathBuf) -> DeliveryResult<DeliveryConfigV1> {
        let config_path = try!(DeliveryConfig::find_config_file(p_path));
        let mut config_file = try!(File::open(&config_path));
        let mut config_json = String::new();
        try!(config_file.read_to_string(&mut config_json));
        let json = try!(json::decode(&config_json));
        Ok(json)
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code, unused_variables)]

extern crate glutin_window;
extern crate graphics;
extern crate rebind;
extern crate piston;
extern crate opengl_graphics;
extern crate viewport;

use glutin_window::GlutinWindow;
use graphics::*;
use opengl_graphics::{GlGraphics, OpenGL};
use piston::event_loop::{EventMap, Events};
use piston::input::{
    Event,
    Input,
    Motion,
    RenderArgs,
    RenderEvent,
    UpdateArgs,
    UpdateEvent
};
use piston::input::keyboard::Key;
use piston::input::Button::Keyboard;
use piston::window::WindowSettings;
use rebind::{Action, InputTranslator, RebindBuilder, Translated};
use std::cell::RefCell;
use std::rc::Rc;

struct App {
    window: Rc<RefCell<GlutinWindow>>,
    graphics: Rc<RefCell<GlGraphics>>,
    translator: InputTranslator<CharacterAction>,
    character: Character,
    cursor_pos: [f64; 2],
    bg_color: [f32; 4]
}

impl App {
    fn input(&mut self, input: &Input) {
        if let Some(t) = self.translator.translate(input) {
            match t {
                Translated::Press(action) => {
                    match action {
                        CharacterAction::Jump => {

                        },
                        CharacterAction::MoveLeft => {
                            self.character.current_velocity[0] += 0.5;
                        },
                        CharacterAction::MoveRight => {
                            self.character.current_velocity[0] -= 0.5;
                        }
                    }
                },
                Translated::Release(_) => {
                    self.character.current_velocity = [0.0, 0.0];
                },
                Translated::Move(Motion::MouseCursor(x, y)) => {
                    self.cursor_pos = [x, y];
                }
                _ => { }
            }
        }
    }

    fn update(&mut self, args: &UpdateArgs) {

    }

    fn render(&mut self, args: &RenderArgs) {
        let mut gl_graphics = self.graphics.borrow_mut();

        // draw the background color
        {
            gl_graphics.draw(args.viewport(), |_, gl| clear(self.bg_color, gl));
        }

        // draw the character
        {
            let square = rectangle::square(self.character.topleft[0], self.character.topleft[1], self.character.size);
            let (x, y) = ((args.width / 2) as f64, (args.height / 2) as f64);

            gl_graphics.draw(args.viewport(), |c, gl| {
                let transform = c.transform.trans(x, y);
                rectangle(self.character.color, square, transform, gl);
            });
        }

        // draw the cursor dot
        {
            let dot = ellipse::circle(self.cursor_pos[0], self.cursor_pos[1], 5.0);
            gl_graphics.draw(args.viewport(), |c, gl| ellipse([0.0, 1.0, 0.0, 1.0], dot, c.transform, gl));
        }
    }
}

struct Character {
    color: [f32; 4],
    topleft: [f64; 2],
    current_velocity: [f64; 2],
    size: f64
}

impl Character {
    fn new(col: [f32; 4], tl: [f64; 2], sz: f64) -> Self {
        Character {
            color: col,
            topleft: tl,
            current_velocity: [0.0f64, 0.0],
            size: sz
        }
    }
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum CharacterAction {
    Jump,
    MoveLeft,
    MoveRight
}

impl Action for CharacterAction { }

fn main() {
    const WINDOW_SIZE: (u32, u32)  = (800, 600);
    const OPENGL: OpenGL = OpenGL::V3_2;

    let window = WindowSettings::new("calaxite", WINDOW_SIZE)
        .exit_on_esc(true)
        .fullscreen(false)
        .opengl(OPENGL)
        .vsync(true)
        .build()
        .unwrap_or_else(|e| panic!("Could not create window: {}", e));

    let gl_graphics = GlGraphics::new(OPENGL);

    let translator = RebindBuilder::new(WINDOW_SIZE.into())
        .with_action_mapping(Keyboard(Key::Space), CharacterAction::Jump)
        .with_action_mapping(Keyboard(Key::Left),  CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::A),     CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::Right), CharacterAction::MoveRight)
        .with_action_mapping(Keyboard(Key::D),     CharacterAction::MoveRight)
        .build_translator();

    let character = Character::new([1.0, 0.0, 0.0, 1.0],
                                   [30.0, 30.0],
                                   50.0);

    let mut app = App {
        window: Rc::new(RefCell::new(window)),
        graphics: Rc::new(RefCell::new(gl_graphics)),
        translator: translator,
        character: character,
        cursor_pos: [0.0, 0.0],
        bg_color: [0.0, 0.0, 0.0, 1.0] // black background
    };

    for e in app.window.clone().events() {
        match e {
            Event::Render(r) => { app.render(&r); },
            Event::Update(u) => { app.update(&u); },
            Event::Input(i)  => { app.input(&i); },
            _ => { }
        }
    }
}
<commit_msg>Refactoring<commit_after>#![allow(dead_code, unused_variables)]

extern crate glutin_window;
extern crate graphics;
extern crate rebind;
extern crate piston;
extern crate opengl_graphics;
extern crate viewport;

use glutin_window::GlutinWindow;
use graphics::*;
use opengl_graphics::{GlGraphics, OpenGL};
use piston::event_loop::{EventMap, Events};
use piston::input::{
    Event,
    Input,
    Motion,
    RenderArgs,
    RenderEvent,
    UpdateArgs,
    UpdateEvent
};
use piston::input::keyboard::Key;
use piston::input::Button::Keyboard;
use piston::window::WindowSettings;
use rebind::{Action, InputTranslator, RebindBuilder, Translated};
use std::cell::RefCell;
use std::rc::Rc;

struct App {
    window: Rc<RefCell<GlutinWindow>>,
    graphics: Rc<RefCell<GlGraphics>>,
    translator: InputTranslator<CharacterAction>,
    character: Character,
    cursor_pos: [f64; 2],
    bg_color: [f32; 4]
}

impl App {
    fn input(&mut self, input: &Input) {
        if let Some(t) = self.translator.translate(input) {
            match t {
                Translated::Press(action) => {
                    match action {
                        CharacterAction::Jump => {
                            println!("You jumped! Yay!");
                        },
                        CharacterAction::MoveLeft => {
                            self.character.current_velocity[0] += 0.5;
                        },
                        CharacterAction::MoveRight => {
                            self.character.current_velocity[0] -= 0.5;
                        }
                    }
                },
                Translated::Release(_) => {
                    self.character.current_velocity = [0.0, 0.0];
                },
                Translated::Move(Motion::MouseCursor(x, y)) => {
                    self.cursor_pos = [x, y];
                },
                _ => { }
            }
        }
    }

    fn update(&mut self, args: &UpdateArgs) {

    }

    fn render(&mut self, args: &RenderArgs) {
        let mut gl_graphics = self.graphics.borrow_mut();

        // draw the background color
        {
            gl_graphics.draw(args.viewport(), |_, gl| clear(self.bg_color, gl));
        }

        // draw the character
        {
            let square = rectangle::square(self.character.topleft[0],
                                           self.character.topleft[1],
                                           self.character.size);

            let (x, y) = ((args.width / 2) as f64, (args.height / 2) as f64);

            gl_graphics.draw(args.viewport(), |c, gl| {
                let transform = c.transform.trans(x, y);
                rectangle(self.character.color, square, transform, gl);
            });
        }

        // draw the cursor dot
        {
            let dot = ellipse::circle(self.cursor_pos[0], self.cursor_pos[1], 5.0);
            gl_graphics.draw(args.viewport(), |c, gl| ellipse([0.0, 1.0, 0.0, 1.0], dot, c.transform, gl));
        }
    }
}

struct Character {
    color: [f32; 4],
    topleft: [f64; 2],
    current_velocity: [f64; 2],
    size: f64
}

impl Character {
    fn new(col: [f32; 4], tl: [f64; 2], sz: f64) -> Self {
        Character {
            color: col,
            topleft: tl,
            current_velocity: [0.0f64, 0.0],
            size: sz
        }
    }
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum CharacterAction {
    Jump,
    MoveLeft,
    MoveRight
}

impl Action for CharacterAction { }

fn main() {
    const WINDOW_SIZE: (u32, u32)  = (800, 600);
    const OPENGL: OpenGL = OpenGL::V3_2;

    let window = WindowSettings::new("calaxite", WINDOW_SIZE)
        .exit_on_esc(true)
        .fullscreen(false)
        .opengl(OPENGL)
        .vsync(true)
        .build()
        .unwrap_or_else(|e| panic!("Could not create window: {}", e));

    let gl_graphics = GlGraphics::new(OPENGL);

    let translator = RebindBuilder::new(WINDOW_SIZE.into())
        .with_action_mapping(Keyboard(Key::Space), CharacterAction::Jump)
        .with_action_mapping(Keyboard(Key::Left),  CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::A),     CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::Right), CharacterAction::MoveRight)
        .with_action_mapping(Keyboard(Key::D),     CharacterAction::MoveRight)
        .build_translator();

    let character = Character::new([1.0, 0.0, 0.0, 1.0],
                                   [30.0, 30.0],
                                   50.0);

    let mut app = App {
        window: Rc::new(RefCell::new(window)),
        graphics: Rc::new(RefCell::new(gl_graphics)),
        translator: translator,
        character: character,
        cursor_pos: [0.0, 0.0],
        bg_color: [0.0, 0.0, 0.0, 1.0] // black background
    };

    for e in app.window.clone().events() {
        match e {
            Event::Render(r) => { app.render(&r); },
            Event::Update(u) => { app.update(&u); },
            Event::Input(i)  => { app.input(&i); },
            _ => { }
        }
    }
}
<|endoftext|>


<commit_before>//! Array-based data structures using densely numbered entity references as mapping keys.
//!
//! This module defines a number of data structures based on arrays. The arrays are not indexed by
//! `usize` as usual, but by *entity references* which are integers wrapped in new-types. This has
//! a couple advantages:
//!
//! - Improved type safety. The various map and set types accept a specific key type, so there is
//!   no confusion about the meaning of an array index, as there is with plain arrays.
//! - Smaller indexes. The normal `usize` index is often 64 bits which is way too large for most
//!   purposes. The entity reference types can be smaller, allowing for more compact data
//!   structures.
//!
//! The `EntityRef` trait should be implemented by types to be used as indexed. The `entity_impl!`
//! macro provides convenient defaults for types wrapping `u32` which is common.
//!
//! - [`PrimaryMap`](struct.PrimaryMap.html) is used to keep track of a vector of entities,
//!   assigning a unique entity reference to each.
//! - [`EntityMap`](struct.EntityMap.html) is used to associate secondary information to an entity.
//!   The map is implemented as a simple vector, so it does not keep track of which entities have
//!   been inserted. Instead, any unknown entities map to the default value.
//! - [`SparseMap`](struct.SparseMap.html) is used to associate secondary information to a small
//!   number of entities. It tracks accurately which entities have been inserted. This is a
//!   specialized data structure which can use a lot of memory, so read the documentation before
//!   using it.
//! - [`EntitySet`](struct.EntitySet.html) is used to represent a secondary set of entities.
//!   The set is implemented as a simple vector, so it does not keep track of which entities have
//!   been inserted into the primary map. Instead, any unknown entities are not in the set.
//! - [`EntityList`](struct.EntityList.html) is a compact representation of lists of entity
//!   references allocated from an associated memory pool. It has a much smaller footprint than
//!   `Vec`.

mod keys;
mod list;
mod map;
mod primary;
mod sparse;
mod set;

pub use self::keys::Keys;
pub use self::list::{EntityList, ListPool};
pub use self::map::EntityMap;
pub use self::primary::PrimaryMap;
pub use self::set::EntitySet;
pub use self::sparse::{SparseSet, SparseMap, SparseMapValue};

/// A type wrapping a small integer index should implement `EntityRef` so it can be used as the key
/// of an `EntityMap` or `SparseMap`.
pub trait EntityRef: Copy + Eq {
    /// Create a new entity reference from a small integer.
    /// This should crash if the requested index is not representable.
    fn new(usize) -> Self;

    /// Get the index that was used to create this entity reference.
    fn index(self) -> usize;
}

/// Macro which provides the common implementation of a 32-bit entity reference.
#[macro_export]
macro_rules! entity_impl {
    // Basic traits.
    ($entity:ident) => {
        impl $crate::entity::EntityRef for $entity {
            fn new(index: usize) -> Self {
                assert!(index < (::std::u32::MAX as usize));
                $entity(index as u32)
            }

            fn index(self) -> usize {
                self.0 as usize
            }
        }

        impl $crate::packed_option::ReservedValue for $entity {
            fn reserved_value() -> $entity {
                $entity(::std::u32::MAX)
            }
        }
    };

    // Include basic `Display` impl using the given display prefix.
    // Display an `Ebb` reference as "ebb12".
    ($entity:ident, $display_prefix:expr) => {
        entity_impl!($entity);

        impl ::std::fmt::Display for $entity {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                write!(f, "{}{}", $display_prefix, self.0)
            }
        }

        impl ::std::fmt::Debug for $entity {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
            	(self as &::std::fmt::Display).fmt(f)
			}
		}
    }
}
<commit_msg>Change tabs to spaces, for consistency with rustfmt.<commit_after>//! Array-based data structures using densely numbered entity references as mapping keys.
//!
//! This module defines a number of data structures based on arrays. The arrays are not indexed by
//! `usize` as usual, but by *entity references* which are integers wrapped in new-types. This has
//! a couple advantages:
//!
//! - Improved type safety. The various map and set types accept a specific key type, so there is
//!   no confusion about the meaning of an array index, as there is with plain arrays.
//! - Smaller indexes. The normal `usize` index is often 64 bits which is way too large for most
//!   purposes. The entity reference types can be smaller, allowing for more compact data
//!   structures.
//!
//! The `EntityRef` trait should be implemented by types to be used as indexed. The `entity_impl!`
//! macro provides convenient defaults for types wrapping `u32` which is common.
//!
//! - [`PrimaryMap`](struct.PrimaryMap.html) is used to keep track of a vector of entities,
//!   assigning a unique entity reference to each.
//! - [`EntityMap`](struct.EntityMap.html) is used to associate secondary information to an entity.
//!   The map is implemented as a simple vector, so it does not keep track of which entities have
//!   been inserted. Instead, any unknown entities map to the default value.
//! - [`SparseMap`](struct.SparseMap.html) is used to associate secondary information to a small
//!   number of entities. It tracks accurately which entities have been inserted. This is a
//!   specialized data structure which can use a lot of memory, so read the documentation before
//!   using it.
//! - [`EntitySet`](struct.EntitySet.html) is used to represent a secondary set of entities.
//!   The set is implemented as a simple vector, so it does not keep track of which entities have
//!   been inserted into the primary map. Instead, any unknown entities are not in the set.
//! - [`EntityList`](struct.EntityList.html) is a compact representation of lists of entity
//!   references allocated from an associated memory pool. It has a much smaller footprint than
//!   `Vec`.

mod keys;
mod list;
mod map;
mod primary;
mod sparse;
mod set;

pub use self::keys::Keys;
pub use self::list::{EntityList, ListPool};
pub use self::map::EntityMap;
pub use self::primary::PrimaryMap;
pub use self::set::EntitySet;
pub use self::sparse::{SparseSet, SparseMap, SparseMapValue};

/// A type wrapping a small integer index should implement `EntityRef` so it can be used as the key
/// of an `EntityMap` or `SparseMap`.
pub trait EntityRef: Copy + Eq {
    /// Create a new entity reference from a small integer.
    /// This should crash if the requested index is not representable.
    fn new(usize) -> Self;

    /// Get the index that was used to create this entity reference.
    fn index(self) -> usize;
}

/// Macro which provides the common implementation of a 32-bit entity reference.
#[macro_export]
macro_rules! entity_impl {
    // Basic traits.
    ($entity:ident) => {
        impl $crate::entity::EntityRef for $entity {
            fn new(index: usize) -> Self {
                assert!(index < (::std::u32::MAX as usize));
                $entity(index as u32)
            }

            fn index(self) -> usize {
                self.0 as usize
            }
        }

        impl $crate::packed_option::ReservedValue for $entity {
            fn reserved_value() -> $entity {
                $entity(::std::u32::MAX)
            }
        }
    };

    // Include basic `Display` impl using the given display prefix.
    // Display an `Ebb` reference as "ebb12".
    ($entity:ident, $display_prefix:expr) => {
        entity_impl!($entity);

        impl ::std::fmt::Display for $entity {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                write!(f, "{}{}", $display_prefix, self.0)
            }
        }

        impl ::std::fmt::Debug for $entity {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                (self as &::std::fmt::Display).fmt(f)
            }
        }
    }
}
<|endoftext|>


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

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

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

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

// Temporal flow graph (TFG)

use front::ast::*;
use front::ast::Expr::*;

struct Graph<C, D> {
  vertices: Vec<Vertex<C,D>>,
  edges: Vec<Edge<C,D>>,
  args: Vec<String>,
  entry: usize
}

impl<C,D> Graph<C,D> {
  fn add_empty_vertex(&mut self) -> usize {
    self.vertices.push(Vertex::new_empty());
    self.vertices.len() - 1
  }

  fn add_delay_on(&mut self, source: usize, target: usize, delay: u32) -> usize {
    match self.find_edge(source, target) {
      None => self.add_edge(source, target, vec![delay]),
      Some(edge_id) => {
        self.edges[edge_id].delays.push(delay);
        edge_id
      }
    }
  }

  fn find_edge(&self, source: usize, target: usize) -> Option<usize> {
    for &edge_id in self.vertices[source].next.iter() {
      if self.edges[edge_id].target == target {
        return Some(edge_id);
      }
    }
    None
  }

  fn add_edge(&mut self, source: usize, target: usize, delays: Vec<u32>) -> usize {
    let edge = Edge::new(target, delays);
    self.edges.push(edge);
    let edge_id = self.edges.len() - 1;
    self.vertices[source].next.push(edge_id);
    edge_id
  }

  fn add_seq_edge(&mut self, target: usize) -> usize {
    let edge = Edge::new(target, vec![0]);
    self.edges.push(edge);
    self.edges.len() - 1
  }
}

struct Vertex<C, D> {
  sums: Vec<Vec<ConstraintDependentEdge<C>>>,
  unless: Vec<ConstraintDependentEdge<C>>,
  tell: Vec<C>,
  locals: Vec<(String, D)>,
  next: Vec<usize> // there should only be sequential edge here (after the 'compact' step)
}

impl<C,D> Vertex<C, D> {
  fn new_empty() -> Vertex<C,D> {
    Vertex {
      sums: vec![],
      unless: vec![],
      tell: vec![],
      locals: vec![],
      next: vec![]
    }
  }
}

struct Edge<C,D> {
  target: usize,
  delays: Vec<u32>
}

impl<C,D> Edge<C,D> {
  fn new(target: usize, delays: Vec<u32>) -> Edge<C,D> {
    Edge {
      target: target,
      delays: delays
    }
  }
}

struct ConstraintDependentEdge<C> {
  c: C,
  edge: usize
}

impl<C> ConstraintDependentEdge<C> {
  pub fn new(c: C, edge: usize) -> ConstraintDependentEdge<C> {
    ConstraintDependentEdge {
      c: c,
      edge: edge
    }
  }
}

pub fn compile_program<D,C>(program: Program<C,D>) -> Graph<C,D>
{
  let mut graph: Graph<C,D> = Graph {
    vertices: vec![],
    edges: vec![],
    args: program.args,
    entry: 0
  };
  let current_vertex_id = graph.add_empty_vertex();
  graph.entry = compile_expr(&mut graph, program.def, current_vertex_id);
  graph
}

// Returns the vertex id we just compiled expr into.
pub fn compile_expr<C,D>(graph: &mut Graph<C,D>, expr: Expr<C,D>, current: usize) -> usize
{
  match expr {
    Tell(c) => compile_tell(graph, c, current),
    Parallel(exprs) => compile_par(graph, exprs, current),
    ReactiveSum(whens) => compile_reactive_sum(graph, whens, current),
    _ => panic!("unimplemented")
    // Replicate(Box<Expr<C, D>>),
    // When(C, Box<Expr<C, D>>),
    // Unless(C, Box<Expr<C, D>>),
    // Next(Box<Expr<C, D>>),
    // Async(Box<Expr<C, D>>),
  }
}

fn compile_reactive_sum<C,D>(graph: &mut Graph<C,D>, whens: Vec<Expr<C,D>>, current: usize) -> usize
{
  let mut sum = vec![];
  for when in whens.into_iter() {
    match when {
      When(c, expr) => {
        let empty_vertex = graph.add_empty_vertex();
        let cexpr = compile_expr(graph, *expr, empty_vertex);
        let seq_edge_id = graph.add_seq_edge(cexpr);
        sum.push(ConstraintDependentEdge::new(c, seq_edge_id));
      }
      _ => panic!("The sugar P + P' instead of when true -> P + when true -> P' is not yet supported.")
    }
  }
  graph.vertices[current].sums.push(sum);
  current
}

fn compile_tell<C,D>(graph: &mut Graph<C,D>, c: C, current: usize) -> usize
{
  graph.vertices[current].tell.push(c);
  current
}

fn compile_par<C,D>(graph: &mut Graph<C,D>, exprs: Vec<Expr<C,D>>, current: usize) -> usize
{
  for expr in exprs.into_iter() {
    compile_expr(graph, expr, current);
  }
  current
}

#[cfg(test)]
mod test {
  use super::*;
  use front::constraint_ast::*;
  use front::constraint_ast::Domain::*;
  use front::constraint_ast::Constraint::*;
  use front::ast::*;
  use front::ast::Expr::*;

  #[test]
  fn tell_test() {
    let p: Program<Constraint, Domain> = Program {
      args: vec![],
      def: Tell(make_x_eq_y())
    };
    let g = compile_program(p);
    assert_eq!(g.vertices.len(), 1);
    assert_eq!(g.edges.len(), 0);
    assert_eq!(g.vertices[0].tell.len(), 1);
    assert_eq!(g.vertices[0].tell[0], make_x_eq_y());
  }

  #[test]
  fn par_tell_test() {
    let p: Program<Constraint, Domain> = Program {
      args: vec![],
      def: Parallel(vec![
            Tell(make_x_eq_y()),
            Tell(make_x_neq_z())])
    };
    let g = compile_program(p);
    assert_eq!(g.vertices.len(), 1);
    assert_eq!(g.edges.len(), 0);
    assert_eq!(g.vertices[0].tell.len(), 2);
    assert_eq!(g.vertices[0].tell[0], make_x_eq_y());
    assert_eq!(g.vertices[0].tell[1], make_x_neq_z());
  }

  #[test]
  fn when_tell_test() {
    let p: Program<Constraint, Domain> = Program {
      args: vec![],
      def: ReactiveSum(vec![
            When(make_x_eq_0(), box Tell(make_x_eq_y())),
            When(make_x_eq_1(), box Tell(make_x_neq_z()))])
    };
    let g = compile_program(p);
    assert_eq!(g.vertices.len(), 3);
    assert_eq!(g.vertices[0].tell.len(), 0);
    assert_eq!(g.vertices[1].tell.len(), 1);
    assert_eq!(g.vertices[2].tell.len(), 1);
    assert_eq!(g.vertices[1].tell[0], make_x_eq_y());
    assert_eq!(g.vertices[2].tell[0], make_x_neq_z());

    assert_eq!(g.vertices[0].sums.len(), 1);
    assert_eq!(g.vertices[0].sums[0].len(), 2);
    assert_eq!(g.vertices[0].sums[0][0].c, make_x_eq_0());
    assert_eq!(g.vertices[0].sums[0][1].c, make_x_eq_1());

    assert_eq!(g.edges.len(), 2);
    assert_eq!(g.edges[0].delays, vec![0]);
    assert_eq!(g.edges[0].target, 1);
    assert_eq!(g.edges[1].target, 2);
  }

  fn make_x_eq_y() -> Constraint {
    XEqualY(String::from_str("x"), String::from_str("y"))
  }

  fn make_x_neq_z() -> Constraint {
    XLessThanY(String::from_str("x"), String::from_str("z"))
  }

  fn make_x_eq_0() -> Constraint {
    XEqualC(String::from_str("x"), 0)
  }

  fn make_x_eq_1() -> Constraint {
    XEqualC(String::from_str("x"), 1)
  }
}<commit_msg>Implement when alone, just a sugar for the unary reactive sum. Add many tests.<commit_after>// Copyright 2015 Pierre Talbot (IRCAM)

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

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

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

// Temporal flow graph (TFG)

// TODO: two types to distinguish vertex and edge indexes.

use front::ast::*;
use front::ast::Expr::*;

pub struct Graph<C, D> {
  vertices: Vec<Vertex<C,D>>,
  edges: Vec<Edge<C,D>>,
  args: Vec<String>,
  entry: usize
}

impl<C,D> Graph<C,D> {
  fn add_empty_vertex(&mut self) -> usize {
    self.vertices.push(Vertex::new_empty());
    self.vertices.len() - 1
  }

  fn add_delay_on(&mut self, source: usize, target: usize, delay: u32) -> usize {
    match self.find_edge(source, target) {
      None => self.add_edge(source, target, vec![delay]),
      Some(edge_id) => {
        self.edges[edge_id].delays.push(delay);
        edge_id
      }
    }
  }

  fn find_edge(&self, source: usize, target: usize) -> Option<usize> {
    for &edge_id in self.vertices[source].next.iter() {
      if self.edges[edge_id].target == target {
        return Some(edge_id);
      }
    }
    None
  }

  fn add_edge(&mut self, source: usize, target: usize, delays: Vec<u32>) -> usize {
    let edge = Edge::new(target, delays);
    self.edges.push(edge);
    let edge_id = self.edges.len() - 1;
    self.vertices[source].next.push(edge_id);
    edge_id
  }

  fn add_seq_edge(&mut self, target: usize) -> usize {
    let edge = Edge::new(target, vec![0]);
    self.edges.push(edge);
    self.edges.len() - 1
  }
}

pub struct Vertex<C, D> {
  sums: Vec<Vec<ConstraintDependentEdge<C>>>,
  unless: Vec<ConstraintDependentEdge<C>>,
  tell: Vec<C>,
  locals: Vec<(String, D)>,
  next: Vec<usize> // there should only be sequential edge here (after the 'compact' step)
}

impl<C,D> Vertex<C, D> {
  fn new_empty() -> Vertex<C,D> {
    Vertex {
      sums: vec![],
      unless: vec![],
      tell: vec![],
      locals: vec![],
      next: vec![]
    }
  }
}

pub struct Edge<C,D> {
  target: usize,
  delays: Vec<u32>
}

impl<C,D> Edge<C,D> {
  fn new(target: usize, delays: Vec<u32>) -> Edge<C,D> {
    Edge {
      target: target,
      delays: delays
    }
  }
}

pub struct ConstraintDependentEdge<C> {
  c: C,
  edge: usize
}

impl<C> ConstraintDependentEdge<C> {
  pub fn new(c: C, edge: usize) -> ConstraintDependentEdge<C> {
    ConstraintDependentEdge {
      c: c,
      edge: edge
    }
  }
}

pub fn compile_program<D,C>(program: Program<C,D>) -> Graph<C,D>
{
  let mut graph: Graph<C,D> = Graph {
    vertices: vec![],
    edges: vec![],
    args: program.args,
    entry: 0
  };
  let current_vertex_id = graph.add_empty_vertex();
  graph.entry = compile_expr(&mut graph, program.def, current_vertex_id);
  graph
}

// Returns the vertex id we just compiled expr into.
pub fn compile_expr<C,D>(graph: &mut Graph<C,D>, expr: Expr<C,D>, current: usize) -> usize
{
  match expr {
    Tell(c) => compile_tell(graph, c, current),
    Parallel(exprs) => compile_par(graph, exprs, current),
    when@When(_,_) => compile_reactive_sum(graph, vec![when], current),
    ReactiveSum(whens) => compile_reactive_sum(graph, whens, current),
    _ => panic!("unimplemented")
    // Replicate(Box<Expr<C, D>>),
    // Unless(C, Box<Expr<C, D>>),
    // Next(Box<Expr<C, D>>),
    // Async(Box<Expr<C, D>>),
    // LetIn(String, D, Box<Expr<C, D>>)
  }
}

fn compile_tell<C,D>(graph: &mut Graph<C,D>, c: C, current: usize) -> usize
{
  graph.vertices[current].tell.push(c);
  current
}

fn compile_par<C,D>(graph: &mut Graph<C,D>, exprs: Vec<Expr<C,D>>, current: usize) -> usize
{
  for expr in exprs.into_iter() {
    compile_expr(graph, expr, current);
  }
  current
}

fn compile_reactive_sum<C,D>(graph: &mut Graph<C,D>, whens: Vec<Expr<C,D>>, current: usize) -> usize
{
  let mut sum = vec![];
  for when in whens.into_iter() {
    match when {
      When(c, expr) => {
        let empty_vertex = graph.add_empty_vertex();
        let cexpr = compile_expr(graph, *expr, empty_vertex);
        let seq_edge_id = graph.add_seq_edge(cexpr);
        sum.push(ConstraintDependentEdge::new(c, seq_edge_id));
      }
      _ => panic!("The sugar P + P' instead of when true -> P + when true -> P' is not yet supported.")
    }
  }
  graph.vertices[current].sums.push(sum);
  current
}

#[cfg(test)]
mod test {
  use super::*;
  use front::constraint_ast::*;
  use front::constraint_ast::Domain::*;
  use front::constraint_ast::Constraint::*;
  use front::ast::*;
  use front::ast::Expr::*;

  #[test]
  fn tell_test() {
    let p: Program<Constraint, Domain> = Program {
      args: vec![],
      def: Tell(make_x_eq_y())
    };
    let g = compile_program(p);
    assert_eq!(g.vertices.len(), 1);
    assert_eq!(g.edges.len(), 0);
    assert_eq!(g.vertices[0].tell.len(), 1);
    assert_eq!(g.vertices[0].tell[0], make_x_eq_y());
  }

  #[test]
  fn par_tell_test() {
    let p: Program<Constraint, Domain> = Program {
      args: vec![],
      def: Parallel(vec![
            Tell(make_x_eq_y()),
            Tell(make_x_neq_z())])
    };
    let g = compile_program(p);
    assert_eq!(g.vertices.len(), 1);
    assert_eq!(g.edges.len(), 0);
    assert_eq!(g.vertices[0].tell.len(), 2);
    assert_eq!(g.vertices[0].tell[0], make_x_eq_y());
    assert_eq!(g.vertices[0].tell[1], make_x_neq_z());
  }

  #[test]
  fn when_tell_test() {
    let p: Program<Constraint, Domain> = Program {
      args: vec![],
      def: ReactiveSum(vec![
            When(make_x_eq_0(), box Tell(make_x_eq_y())),
            When(make_x_eq_1(), box Tell(make_x_neq_z()))])
    };
    let g = compile_program(p);
    assert_eq!(g.vertices.len(), 3);
    assert_eq!(g.vertices[0].tell.len(), 0);
    assert_eq!(g.vertices[1].tell.len(), 1);
    assert_eq!(g.vertices[2].tell.len(), 1);
    assert_eq!(g.vertices[1].tell[0], make_x_eq_y());
    assert_eq!(g.vertices[2].tell[0], make_x_neq_z());

    assert_eq!(g.vertices[0].sums.len(), 1);
    assert_eq!(g.vertices[0].sums[0].len(), 2);
    assert_eq!(g.vertices[0].sums[0][0].c, make_x_eq_0());
    assert_eq!(g.vertices[0].sums[0][1].c, make_x_eq_1());

    assert_eq!(g.edges.len(), 2);
    assert_eq!(g.edges[0].delays, vec![0]);
    assert_eq!(g.edges[0].target, 1);
    assert_eq!(g.edges[1].target, 2);
  }

  #[test]
  fn par_when_test() {
    let p: Program<Constraint, Domain> = Program {
      args: vec![],
      def: Parallel(vec![
            ReactiveSum(vec![
              When(make_x_eq_0(), box Tell(make_x_eq_y())),
              When(make_x_eq_1(), box Tell(make_x_neq_z()))]),
            When(make_x_eq_y(), box Tell(make_x_neq_z())),
            When(make_x_neq_z(), box Tell(make_x_eq_y()))])
    };
    let g = compile_program(p);
    assert_eq!(g.vertices.len(), 5);
    assert_eq!(g.vertices[0].sums.len(), 3);
    assert_eq!(g.vertices[0].sums[0].len(), 2);
    assert_eq!(g.vertices[0].sums[1].len(), 1);
    assert_eq!(g.vertices[0].sums[2].len(), 1);

    assert_eq!(g.edges.len(), 4);
    assert_eq!(g.edges[0].target, 1);
    // test the When alone.
    assert_eq!(g.edges[3].target, 4);
    assert_eq!(g.edges[3].delays, vec![0]);
  }

  fn nested_par_equiv(expr: Expr<Constraint, Domain>) {
    let p: Program<Constraint, Domain> = Program {
      args: vec![],
      def: expr
    };
    let g = compile_program(p);
    assert_eq!(g.vertices.len(), 3);
    assert_eq!(g.edges.len(), 2);
    assert_eq!(g.vertices[0].sums.len(), 2);
    assert_eq!(g.vertices[0].tell.len(), 2);
    assert_eq!(g.edges[0].target, 1);
    assert_eq!(g.edges[1].target, 2);
  }

  #[test]
  fn nested_par_test_1() {
    let e = Parallel(vec![
              When(make_x_eq_0(), box Tell(make_x_neq_z())),
              When(make_x_eq_1(), box Tell(make_x_eq_y())),
              Tell(make_x_eq_0()),
              Tell(make_x_eq_1())]);
    nested_par_equiv(e);
  }

  #[test]
  fn nested_par_test_2() {
    let e = Parallel(vec![
              Parallel(vec![
                When(make_x_eq_0(), box Tell(make_x_neq_z())),
                When(make_x_eq_1(), box Tell(make_x_eq_y()))]),
              Tell(make_x_eq_0()),
              Tell(make_x_eq_1())]);
    nested_par_equiv(e);
  }

  #[test]
  fn nested_par_test_3() {
    let e = Parallel(vec![
              Parallel(vec![
                When(make_x_eq_0(), box Tell(make_x_neq_z())),
                When(make_x_eq_1(), box Tell(make_x_eq_y()))]),
              Parallel(vec![
                Tell(make_x_eq_0()),
                Tell(make_x_eq_1())])]);
    nested_par_equiv(e);
  }

  #[test]
  fn nested_par_test_4() {
    let e = Parallel(vec![
              Parallel(vec![
                When(make_x_eq_0(), box Tell(make_x_neq_z())),
                When(make_x_eq_1(), box Tell(make_x_eq_y()))]),
              Parallel(vec![
                Parallel(vec![Tell(make_x_eq_0())]),
                Parallel(vec![Tell(make_x_eq_1())])])]);
    nested_par_equiv(e);
  }

  #[test]
  fn whenwhen_test() {

  }

  fn make_x_eq_y() -> Constraint {
    XEqualY(String::from_str("x"), String::from_str("y"))
  }

  fn make_x_neq_z() -> Constraint {
    XLessThanY(String::from_str("x"), String::from_str("z"))
  }

  fn make_x_eq_0() -> Constraint {
    XEqualC(String::from_str("x"), 0)
  }

  fn make_x_eq_1() -> Constraint {
    XEqualC(String::from_str("x"), 1)
  }
}<|endoftext|>


<commit_before>use std::path::PathBuf;

use crate::externalfiles::ExternalHtml;
use crate::html::render::ensure_trailing_slash;
use crate::html::format::{Buffer, Print};

#[derive(Clone)]
pub struct Layout {
    pub logo: String,
    pub favicon: String,
    pub external_html: ExternalHtml,
    pub krate: String,
    /// The given user css file which allow to customize the generated
    /// documentation theme.
    pub css_file_extension: Option<PathBuf>,
    /// If false, the `select` element to have search filtering by crates on rendered docs
    /// won't be generated.
    pub generate_search_filter: bool,
}

pub struct Page<'a> {
    pub title: &'a str,
    pub css_class: &'a str,
    pub root_path: &'a str,
    pub static_root_path: Option<&'a str>,
    pub description: &'a str,
    pub keywords: &'a str,
    pub resource_suffix: &'a str,
    pub extra_scripts: &'a [&'a str],
    pub static_extra_scripts: &'a [&'a str],
}

pub fn render<T: Print, S: Print>(
    layout: &Layout,
    page: &Page<'_>,
    sidebar: S,
    t: T,
    themes: &[PathBuf],
) -> String {
    let static_root_path = page.static_root_path.unwrap_or(page.root_path);
    format!("<!DOCTYPE html>\
\
\
    <meta charset=\"utf-8\">\
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
    <meta name=\"generator\" content=\"rustdoc\">\
    <meta name=\"description\" content=\"{description}\">\
    <meta name=\"keywords\" content=\"{keywords}\">\
    <title>{title}</title>\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}normalize{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}rustdoc{suffix}.css\" \
          id=\"mainThemeStyle\">\
    {themes}\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}dark{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}light{suffix}.css\" \
          id=\"themeStyle\">\
    \
    <link rel=\"stylesheet\" href=\"{static_root_path}noscript{suffix}.css\">\
    {css_extension}\
    {favicon}\
    {in_header}\
    \
\
\
    \
    {before_content}\
    \

☰
\
        {logo}\
        {sidebar}\
    \

\
        <button id=\"theme-picker\" aria-label=\"Pick another theme!\">\
            \
        </button>\

\

\
    \
    \
        <form class=\"search-form js-only\">\

\

{filter_crates}\
                    <input class=\"search-input\" name=\"search\" \
                           autocomplete=\"off\" \
                           spellcheck=\"false\" \
                           placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
                           type=\"search\">\

\
                \
                    \
                \

\
        </form>\
    \

{content}
\

\

\
    \

\

Help
\

\

Keyboard Shortcuts
\

\

?
\

Show this help dialog
\

S
\

Focus the search field
\

↑
\

Move up in search results
\

↓
\

Move down in search results
\

↹
\

Switch tab
\

⏎
\

Go to active search result
\

+
\

Expand all sections
\

-
\

Collapse all sections
\

\

\

\

Search Tricks
\

\
                    Prefix searches with a type followed by a colon (e.g., \
                    fn:) to restrict the search to a given type.\

\

\
                    Accepted types are: fn, mod, \
                    struct, enum, \
                    trait, type, macro, \
                    and const.\

\

\
                    Search functions by type signature (e.g., \
                    vec -> usize or * -> vec)\

\

\
                    Search multiple things at once by splitting your query with comma (e.g., \
                    str,u8 or String,struct:Vec,test)\

\

\

\
    \
    {after_content}\
    \
    \
    \
    {static_extra_scripts}\
    {extra_scripts}\
    \
\
",
    css_extension = if layout.css_file_extension.is_some() {
        format!("<link rel=\"stylesheet\" \
                       type=\"text/css\" \
                       href=\"{static_root_path}theme{suffix}.css\">",
                static_root_path = static_root_path,
                suffix=page.resource_suffix)
    } else {
        String::new()
    },
    content   = Buffer::html().to_display(t),
    static_root_path = static_root_path,
    root_path = page.root_path,
    css_class = page.css_class,
    logo      = {
        let p = format!("{}{}", page.root_path, layout.krate);
        let p = ensure_trailing_slash(&p);
        if layout.logo.is_empty() {
            format!("\

\

",
                    path=p,
                    static_root_path=static_root_path,
                    suffix=page.resource_suffix)
        } else {
            format!("\

",
                    p,
                    layout.logo)
        }
    },
    title     = page.title,
    description = page.description,
    keywords = page.keywords,
    favicon   = if layout.favicon.is_empty() {
        format!(r#"<link rel="shortcut icon" href="{static_root_path}favicon{suffix}.ico">"#,
                static_root_path=static_root_path,
                suffix=page.resource_suffix)
    } else {
        format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
    },
    in_header = layout.external_html.in_header,
    before_content = layout.external_html.before_content,
    after_content = layout.external_html.after_content,
    sidebar   = Buffer::html().to_display(sidebar),
    krate     = layout.krate,
    themes = themes.iter()
                   .filter_map(|t| t.file_stem())
                   .filter_map(|t| t.to_str())
                   .map(|t| format!(r#"<link rel="stylesheet" type="text/css" href="{}{}{}.css">"#,
                                    static_root_path,
                                    t,
                                    page.resource_suffix))
                   .collect::<String>(),
    suffix=page.resource_suffix,
    static_extra_scripts=page.static_extra_scripts.iter().map(|e| {
        format!("",
                static_root_path=static_root_path,
                extra_script=e)
    }).collect::<String>(),
    extra_scripts=page.extra_scripts.iter().map(|e| {
        format!("",
                root_path=page.root_path,
                extra_script=e)
    }).collect::<String>(),
    filter_crates=if layout.generate_search_filter {
        "<select id=\"crate-search\">\
            <option value=\"All crates\">All crates</option>\
        </select>"
    } else {
        ""
    },
    )
}

pub fn redirect(url: &str) -> String {
    //

"##,
    url = url,
    )
}
<commit_msg>Add more information on search<commit_after>use std::path::PathBuf;

use crate::externalfiles::ExternalHtml;
use crate::html::render::ensure_trailing_slash;
use crate::html::format::{Buffer, Print};

#[derive(Clone)]
pub struct Layout {
    pub logo: String,
    pub favicon: String,
    pub external_html: ExternalHtml,
    pub krate: String,
    /// The given user css file which allow to customize the generated
    /// documentation theme.
    pub css_file_extension: Option<PathBuf>,
    /// If false, the `select` element to have search filtering by crates on rendered docs
    /// won't be generated.
    pub generate_search_filter: bool,
}

pub struct Page<'a> {
    pub title: &'a str,
    pub css_class: &'a str,
    pub root_path: &'a str,
    pub static_root_path: Option<&'a str>,
    pub description: &'a str,
    pub keywords: &'a str,
    pub resource_suffix: &'a str,
    pub extra_scripts: &'a [&'a str],
    pub static_extra_scripts: &'a [&'a str],
}

pub fn render<T: Print, S: Print>(
    layout: &Layout,
    page: &Page<'_>,
    sidebar: S,
    t: T,
    themes: &[PathBuf],
) -> String {
    let static_root_path = page.static_root_path.unwrap_or(page.root_path);
    format!("<!DOCTYPE html>\
\
\
    <meta charset=\"utf-8\">\
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
    <meta name=\"generator\" content=\"rustdoc\">\
    <meta name=\"description\" content=\"{description}\">\
    <meta name=\"keywords\" content=\"{keywords}\">\
    <title>{title}</title>\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}normalize{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}rustdoc{suffix}.css\" \
          id=\"mainThemeStyle\">\
    {themes}\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}dark{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}light{suffix}.css\" \
          id=\"themeStyle\">\
    \
    <link rel=\"stylesheet\" href=\"{static_root_path}noscript{suffix}.css\">\
    {css_extension}\
    {favicon}\
    {in_header}\
    \
\
\
    \
    {before_content}\
    \

☰
\
        {logo}\
        {sidebar}\
    \

\
        <button id=\"theme-picker\" aria-label=\"Pick another theme!\">\
            \
        </button>\

\

\
    \
    \
        <form class=\"search-form js-only\">\

\

{filter_crates}\
                    <input class=\"search-input\" name=\"search\" \
                           autocomplete=\"off\" \
                           spellcheck=\"false\" \
                           placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
                           type=\"search\">\

\
                \
                    \
                \

\
        </form>\
    \

{content}
\

\

\
    \

\

Help
\

\

Keyboard Shortcuts
\

\

?
\

Show this help dialog
\

S
\

Focus the search field
\

↑
\

Move up in search results
\

↓
\

Move down in search results
\

↹
\

Switch tab
\

⏎
\

Go to active search result
\

+
\

Expand all sections
\

-
\

Collapse all sections
\

\

\

\

Search Tricks
\

\
                    Prefix searches with a type followed by a colon (e.g., \
                    fn:) to restrict the search to a given type.\

\

\
                    Accepted types are: fn, mod, \
                    struct, enum, \
                    trait, type, macro, \
                    and const.\

\

\
                    Search functions by type signature (e.g., \
                    vec -> usize or * -> vec)\

\

\
                    Search multiple things at once by splitting your query with comma (e.g., \
                    str,u8 or String,struct:Vec,test)\

\

\
                    You can look for items with an exact name by putting double quotes around \
                    your request: \"string\"\

\

\
                    Look for items inside another one by searching for a path: \
                    vec::Vec\

\

\

\
    \
    {after_content}\
    \
    \
    \
    {static_extra_scripts}\
    {extra_scripts}\
    \
\
",
    css_extension = if layout.css_file_extension.is_some() {
        format!("<link rel=\"stylesheet\" \
                       type=\"text/css\" \
                       href=\"{static_root_path}theme{suffix}.css\">",
                static_root_path = static_root_path,
                suffix=page.resource_suffix)
    } else {
        String::new()
    },
    content   = Buffer::html().to_display(t),
    static_root_path = static_root_path,
    root_path = page.root_path,
    css_class = page.css_class,
    logo      = {
        let p = format!("{}{}", page.root_path, layout.krate);
        let p = ensure_trailing_slash(&p);
        if layout.logo.is_empty() {
            format!("\

\

",
                    path=p,
                    static_root_path=static_root_path,
                    suffix=page.resource_suffix)
        } else {
            format!("\

",
                    p,
                    layout.logo)
        }
    },
    title     = page.title,
    description = page.description,
    keywords = page.keywords,
    favicon   = if layout.favicon.is_empty() {
        format!(r#"<link rel="shortcut icon" href="{static_root_path}favicon{suffix}.ico">"#,
                static_root_path=static_root_path,
                suffix=page.resource_suffix)
    } else {
        format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
    },
    in_header = layout.external_html.in_header,
    before_content = layout.external_html.before_content,
    after_content = layout.external_html.after_content,
    sidebar   = Buffer::html().to_display(sidebar),
    krate     = layout.krate,
    themes = themes.iter()
                   .filter_map(|t| t.file_stem())
                   .filter_map(|t| t.to_str())
                   .map(|t| format!(r#"<link rel="stylesheet" type="text/css" href="{}{}{}.css">"#,
                                    static_root_path,
                                    t,
                                    page.resource_suffix))
                   .collect::<String>(),
    suffix=page.resource_suffix,
    static_extra_scripts=page.static_extra_scripts.iter().map(|e| {
        format!("",
                static_root_path=static_root_path,
                extra_script=e)
    }).collect::<String>(),
    extra_scripts=page.extra_scripts.iter().map(|e| {
        format!("",
                root_path=page.root_path,
                extra_script=e)
    }).collect::<String>(),
    filter_crates=if layout.generate_search_filter {
        "<select id=\"crate-search\">\
            <option value=\"All crates\">All crates</option>\
        </select>"
    } else {
        ""
    },
    )
}

pub fn redirect(url: &str) -> String {
    //

"##,
    url = url,
    )
}
<|endoftext|>


<commit_before>
use packer::{
    Packer,
    patch,
    patch_rotated,
};

use rect::Rect;

use image::{
    ImageRgba8,
    DynamicImage,
    GenericImage,
    ImageBuf,
};

pub struct MaxrectPacker {
    buf: DynamicImage,
    free_areas: Vec<Rect>,
}

impl MaxrectPacker {
    pub fn new(width: u32, height: u32) -> MaxrectPacker {
        let mut free_areas = Vec::new();
        free_areas.push(Rect {
            x: 0,
            y: 0,
            w: width,
            h: height,
        });

        MaxrectPacker {
            buf: ImageRgba8(ImageBuf::new(width, height)),
            free_areas: free_areas,
        }
    }

    fn find_free_area(&self, image: &DynamicImage) -> Option<uint> {
        let (image_width, image_height) = image.dimensions();
        let mut min_x = None;
        let mut min_y = None;
        let mut index = None;

        for i in range(0, self.free_areas.len()) {
            let ref free_area = self.free_areas[i];

            if free_area.w >= image_width && free_area.h >= image_height ||
               free_area.h >= image_width && free_area.w >= image_height {
                if min_y.is_none() || free_area.top() < min_y.unwrap() ||
                   (free_area.top() == min_y.unwrap() && free_area.left() < min_x.unwrap()) {
                    index = Some(i);
                    min_x = Some(free_area.left());
                    min_y = Some(free_area.top());
                }
            }
        }

        index
    }

    fn split(&mut self, index: uint, w: u32, h: u32) {
        let rect = self.free_areas.remove(index).unwrap();
        self.free_areas.push(Rect::new_with_points(rect.left() + w, rect.top(), rect.right(), rect.bottom()));
        self.free_areas.push(Rect::new_with_points(rect.left(), rect.top() + h, rect.right(), rect.bottom()));
    }

    fn divide(&mut self, rect: &Rect) {
        let mut new_free_areas = Vec::new();
        for free_area in self.free_areas.iter() {
            new_free_areas = new_free_areas.append(free_area.crop(rect).as_slice());
        }
        self.free_areas = new_free_areas;

        if self.free_areas.len() > 1 {
            let mut new_free_areas = Vec::new();
            let mut to_be_removed = Vec::new();

            for i in range(0, self.free_areas.len()) {
                for j in range(0, self.free_areas.len()) {
                    if i != j {
                        if self.free_areas[i].contains(&self.free_areas[j]) {
                            to_be_removed.push(j);
                        }
                    }
                }
            }

            for i in range(0, self.free_areas.len()) {
                if !to_be_removed.contains(&i) {
                    new_free_areas.push(self.free_areas[i]);
                }
            }
            self.free_areas = new_free_areas;
        }
    }
}

impl Packer for MaxrectPacker {
    fn pack(&mut self, image: &DynamicImage) {
        let index = self.find_free_area(image);
        if index.is_some() {
            let i = index.unwrap();
            let free_area = self.free_areas[i];
            let (image_width, image_height) = image.dimensions();
            let mut rect = Rect::new(free_area.x, free_area.y, image_width, image_height);

            if image_width <= free_area.w && image_height <= free_area.h {
                patch(&mut self.buf, free_area.x, free_area.y, image);
            } else {
                patch_rotated(&mut self.buf, free_area.x, free_area.y, image);
                rect.w = image_height;
                rect.h = image_width;
            }

            self.split(i, rect.w, rect.h);
            self.divide(&rect);
        }
    }

    fn image(&self) -> &DynamicImage {
        &self.buf
    }
}
<commit_msg>Code cleanup<commit_after>
use packer::{
    Packer,
    patch,
    patch_rotated,
};

use rect::Rect;

use image::{
    ImageRgba8,
    DynamicImage,
    GenericImage,
    ImageBuf,
};

pub struct MaxrectPacker {
    buf: DynamicImage,
    free_areas: Vec<Rect>,
}

impl MaxrectPacker {
    pub fn new(width: u32, height: u32) -> MaxrectPacker {
        let mut free_areas = Vec::new();
        free_areas.push(Rect {
            x: 0,
            y: 0,
            w: width,
            h: height,
        });

        MaxrectPacker {
            buf: ImageRgba8(ImageBuf::new(width, height)),
            free_areas: free_areas,
        }
    }

    fn find_free_area(&self, image: &DynamicImage) -> Option<uint> {
        let (image_width, image_height) = image.dimensions();
        let mut min_x = None;
        let mut min_y = None;
        let mut index = None;

        for i in range(0, self.free_areas.len()) {
            let ref free_area = self.free_areas[i];

            if free_area.w >= image_width && free_area.h >= image_height ||
               free_area.h >= image_width && free_area.w >= image_height {
                if min_y.is_none() || free_area.top() < min_y.unwrap() ||
                   (free_area.top() == min_y.unwrap() && free_area.left() < min_x.unwrap()) {
                    index = Some(i);
                    min_x = Some(free_area.left());
                    min_y = Some(free_area.top());
                }
            }
        }

        index
    }

    fn split(&mut self, index: uint, w: u32, h: u32) {
        let rect = self.free_areas.remove(index).unwrap();
        self.free_areas.push(Rect::new_with_points(rect.left() + w, rect.top(), rect.right(), rect.bottom()));
        self.free_areas.push(Rect::new_with_points(rect.left(), rect.top() + h, rect.right(), rect.bottom()));
    }

    fn divide(&mut self, rect: &Rect) {
        let mut new_free_areas = Vec::new();
        for free_area in self.free_areas.iter() {
            new_free_areas = new_free_areas.append(free_area.crop(rect).as_slice());
        }
        self.free_areas = new_free_areas;
    }

    fn cleanup(&mut self) {
        if self.free_areas.len() > 1 {
            let mut new_free_areas = Vec::new();
            let mut to_be_removed = Vec::new();

            for i in range(0, self.free_areas.len()) {
                for j in range(0, self.free_areas.len()) {
                    if i != j {
                        if self.free_areas[i].contains(&self.free_areas[j]) {
                            to_be_removed.push(j);
                        }
                    }
                }
            }

            for i in range(0, self.free_areas.len()) {
                if !to_be_removed.contains(&i) {
                    new_free_areas.push(self.free_areas[i]);
                }
            }
            self.free_areas = new_free_areas;
        }
    }
}

impl Packer for MaxrectPacker {
    fn pack(&mut self, image: &DynamicImage) {
        let index = self.find_free_area(image);
        if index.is_some() {
            let i = index.unwrap();
            let free_area = self.free_areas[i];
            let (image_width, image_height) = image.dimensions();
            let mut rect = Rect::new(free_area.x, free_area.y, image_width, image_height);

            if image_width <= free_area.w && image_height <= free_area.h {
                patch(&mut self.buf, free_area.x, free_area.y, image);
            } else {
                patch_rotated(&mut self.buf, free_area.x, free_area.y, image);
                rect.w = image_height;
                rect.h = image_width;
            }

            self.split(i, rect.w, rect.h);
            self.divide(&rect);
            self.cleanup();
        }
    }

    fn image(&self) -> &DynamicImage {
        &self.buf
    }
}
<|endoftext|>