<commit_before>extern crate ndarray;
extern crate itertools;

use ndarray::Array;
use ndarray::{Ix, Si, S};
use ndarray::{
    ArrayBase,
    Data,
    Dimension,
};

use itertools::assert_equal;

#[test]
fn double_ended()
{
    let a = Array::linspace(0., 7., 8);
    let mut it = a.iter().map(|x| *x);
    assert_eq!(it.next(), Some(0.));
    assert_eq!(it.next_back(), Some(7.));
    assert_eq!(it.next(), Some(1.));
    assert_eq!(it.rev().last(), Some(2.));
}

#[test]
fn indexed()
{
    let a = Array::linspace(0., 7., 8);
    for (i, elt) in a.indexed_iter() {
        assert_eq!(i, *elt as Ix);
    }
    let a = a.reshape((2, 4, 1));
    let (mut i, mut j, k) = (0, 0, 0);
    for (idx, elt) in a.indexed_iter() {
        assert_eq!(idx, (i, j, k));
        j += 1;
        if j == 4 {
            j = 0;
            i += 1;
        }
        println!("{:?}", (idx, elt));
    }
}

fn assert_slice_correct<A, S, D>(v: &ArrayBase<S, D>)
    where S: Data<Elem=A>,
          D: Dimension,
          A: PartialEq + std::fmt::Debug,
{
    let slc = v.as_slice();
    assert!(slc.is_some());
    let slc = slc.unwrap();
    assert_eq!(v.len(), slc.len());
    assert_equal(v.iter(), slc);
}

#[test]
fn as_slice() {
    let a = Array::linspace(0., 7., 8);
    let a = a.reshape((2, 4, 1));

    assert_slice_correct(&a);

    let a = a.reshape((2, 4));
    assert_slice_correct(&a);

    assert!(a.view().subview(1, 0).as_slice().is_none());

    let v = a.view();
    assert_slice_correct(&v);
    assert_slice_correct(&v.subview(0, 0));
    assert_slice_correct(&v.subview(0, 1));

    assert!(v.slice(&[S, Si(0, Some(1), 1)]).as_slice().is_none());
    println!("{:?}", v.slice(&[Si(0, Some(1), 2), S]));
    assert!(v.slice(&[Si(0, Some(1), 2), S]).as_slice().is_some());

    // `u` is contiguous, because the column stride of `2` doesn't matter
    // when the result is just one row anyway -- length of that dimension is 1
    let u = v.slice(&[Si(0, Some(1), 2), S]);
    println!("{:?}", u.shape());
    println!("{:?}", u.strides());
    println!("{:?}", v.slice(&[Si(0, Some(1), 2), S]));
    assert!(u.as_slice().is_some());
    assert_slice_correct(&u);

    let a = a.reshape((8, 1));
    assert_slice_correct(&a);
    let u = a.view().slice(&[Si(0, None, 2), S]);
    println!("u={:?}, shape={:?}, strides={:?}", u, u.shape(), u.strides());
    assert!(u.as_slice().is_none());
}

#[test]
fn inner_iter() {
    let a = Array::from_iter(0..12);
    let a = a.reshape((2, 3, 2));
    // [[[0, 1],
    //   [2, 3],
    //   [4, 5]],
    //  [[6, 7],
    //   [8, 9],
    //    ...
    assert_equal(a.inner_iter().map(|v| v.iter().cloned().collect::<Vec<_>>()),
                 vec![vec![0, 1], vec![2, 3], vec![4, 5],
                      vec![6, 7], vec![8, 9], vec![10, 11]]);
    let mut b = Array::zeros((2, 3, 2));
    b.swap_axes(0, 2);
    b.assign(&a);
    assert_equal(b.inner_iter().map(|v| v.iter().cloned().collect::<Vec<_>>()),
                 vec![vec![0, 1], vec![2, 3], vec![4, 5],
                      vec![6, 7], vec![8, 9], vec![10, 11]]);
}
<commit_msg>Add more tests for inner_iter<commit_after>extern crate ndarray;
extern crate itertools;

use ndarray::Array;
use ndarray::{Ix, Si, S};
use ndarray::{
    ArrayBase,
    Data,
    Dimension,
    aview1,
};

use itertools::assert_equal;

#[test]
fn double_ended()
{
    let a = Array::linspace(0., 7., 8);
    let mut it = a.iter().map(|x| *x);
    assert_eq!(it.next(), Some(0.));
    assert_eq!(it.next_back(), Some(7.));
    assert_eq!(it.next(), Some(1.));
    assert_eq!(it.rev().last(), Some(2.));
}

#[test]
fn indexed()
{
    let a = Array::linspace(0., 7., 8);
    for (i, elt) in a.indexed_iter() {
        assert_eq!(i, *elt as Ix);
    }
    let a = a.reshape((2, 4, 1));
    let (mut i, mut j, k) = (0, 0, 0);
    for (idx, elt) in a.indexed_iter() {
        assert_eq!(idx, (i, j, k));
        j += 1;
        if j == 4 {
            j = 0;
            i += 1;
        }
        println!("{:?}", (idx, elt));
    }
}

fn assert_slice_correct<A, S, D>(v: &ArrayBase<S, D>)
    where S: Data<Elem=A>,
          D: Dimension,
          A: PartialEq + std::fmt::Debug,
{
    let slc = v.as_slice();
    assert!(slc.is_some());
    let slc = slc.unwrap();
    assert_eq!(v.len(), slc.len());
    assert_equal(v.iter(), slc);
}

#[test]
fn as_slice() {
    let a = Array::linspace(0., 7., 8);
    let a = a.reshape((2, 4, 1));

    assert_slice_correct(&a);

    let a = a.reshape((2, 4));
    assert_slice_correct(&a);

    assert!(a.view().subview(1, 0).as_slice().is_none());

    let v = a.view();
    assert_slice_correct(&v);
    assert_slice_correct(&v.subview(0, 0));
    assert_slice_correct(&v.subview(0, 1));

    assert!(v.slice(&[S, Si(0, Some(1), 1)]).as_slice().is_none());
    println!("{:?}", v.slice(&[Si(0, Some(1), 2), S]));
    assert!(v.slice(&[Si(0, Some(1), 2), S]).as_slice().is_some());

    // `u` is contiguous, because the column stride of `2` doesn't matter
    // when the result is just one row anyway -- length of that dimension is 1
    let u = v.slice(&[Si(0, Some(1), 2), S]);
    println!("{:?}", u.shape());
    println!("{:?}", u.strides());
    println!("{:?}", v.slice(&[Si(0, Some(1), 2), S]));
    assert!(u.as_slice().is_some());
    assert_slice_correct(&u);

    let a = a.reshape((8, 1));
    assert_slice_correct(&a);
    let u = a.view().slice(&[Si(0, None, 2), S]);
    println!("u={:?}, shape={:?}, strides={:?}", u, u.shape(), u.strides());
    assert!(u.as_slice().is_none());
}

#[test]
fn inner_iter() {
    let a = Array::from_iter(0..12);
    let a = a.reshape((2, 3, 2));
    // [[[0, 1],
    //   [2, 3],
    //   [4, 5]],
    //  [[6, 7],
    //   [8, 9],
    //    ...
    assert_equal(a.inner_iter(),
                 vec![aview1(&[0, 1]), aview1(&[2, 3]), aview1(&[4, 5]),
                      aview1(&[6, 7]), aview1(&[8, 9]), aview1(&[10, 11])]);
    let mut b = Array::zeros((2, 3, 2));
    b.swap_axes(0, 2);
    b.assign(&a);
    assert_equal(b.inner_iter(),
                 vec![aview1(&[0, 1]), aview1(&[2, 3]), aview1(&[4, 5]),
                      aview1(&[6, 7]), aview1(&[8, 9]), aview1(&[10, 11])]);
}

#[test]
fn inner_iter_corner_cases() {
    let a0 = Array::zeros(());
    assert_equal(a0.inner_iter(), vec![aview1(&[0])]);

    let a2 = Array::<i32, _>::zeros((0, 3));
    assert_equal(a2.inner_iter(),
                 vec![aview1(&[]); 0]);

    let a2 = Array::<i32, _>::zeros((3, 0));
    assert_equal(a2.inner_iter(),
                 vec![aview1(&[]); 3]);
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// aux-build:roman_numerals.rs
// ignore-stage1
// ignore-android

#![feature(phase)]

#[phase(plugin, link)]
extern crate roman_numerals;

pub fn main() {
    assert_eq!(rn!(MMXV), 2015);
    assert_eq!(rn!(MCMXCIX), 1999);
    assert_eq!(rn!(XXV), 25);
    assert_eq!(rn!(MDCLXVI), 1666);
    assert_eq!(rn!(MMMDCCCLXXXVIII), 3888);
    assert_eq!(rn!(MMXIV), 2014);
}
<commit_msg>test: Fix a test that fails when cross compiling<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// aux-build:roman_numerals.rs
// ignore-stage1

#![feature(phase)]

#[phase(plugin)]
extern crate roman_numerals;

pub fn main() {
    assert_eq!(rn!(MMXV), 2015);
    assert_eq!(rn!(MCMXCIX), 1999);
    assert_eq!(rn!(XXV), 25);
    assert_eq!(rn!(MDCLXVI), 1666);
    assert_eq!(rn!(MMMDCCCLXXXVIII), 3888);
    assert_eq!(rn!(MMXIV), 2014);
}
<|endoftext|>


<commit_before>extern mod linenoise;

fn run_command(command: &~str) -> core::os::Pipe {
    io::println(*command);
    let pipe = core::os::pipe();
    let command_split = str::split_char(*command, ' ');
    let command_name = command_split.head();
    let command_args = command_split.tail();
    core::run::spawn_process(*command_name, command_args, ~None, ~None, pipe.in, pipe.out, pipe.out);
    pipe
}

fn handle_input(line: &str) {
    linenoise::history_add(line);
    linenoise::history_save("history.txt");
    let mut pipes = ~[];
    let commands = str::split_char(line, '|');
    for commands.each |command| {
        pipes.push(run_command(command));
    }
}

fn main() {
    linenoise::set_multiline(true);
    loop {
        let line = linenoise::init("rush: ");
        handle_input(line);
    }
}
<commit_msg>Run each command as a separate task<commit_after>extern mod linenoise;

mod rush {
    extern mod linenoise;
    extern mod core;
    use core::task::spawn;
    use core::comm::{stream,Port,Chan,SharedChan};

    fn write_str(wr: io::Writer, s: &str) { str::byte_slice(s, |v| wr.write(v)) }

    fn exec_command(command: &~str) -> Port<~str> {
        let (strout,strin): (Port<~str>, Chan<~str>) = stream();
        let com = copy *command;
        do spawn {
            let command_split = str::split_char(str::trim(com), ' ');
            let prog = command_split.head();
            let args = command_split.tail();
            let mut prog = core::run::start_program(*prog, args);
            let rd = prog.output();
            let buf = io::with_bytes_writer(|wr| {
                let mut bytes = [0, ..4096];
                while !rd.eof() {
                    let nread = rd.read(bytes, bytes.len());
                    wr.write(bytes.view(0, nread));
                }
            });
            strin.send(str::from_bytes(buf));
        }
        strout
    }

    pub fn handle_input(line: &str) {
        linenoise::history_add(line);
        linenoise::history_save("history.txt");
        let commands = str::split_char(line, '|');
        let mut stdouts : ~[Port<~str>] = core::vec::map(commands, exec_command);
        for stdouts.each |stdout| {
            io::println(stdout.recv());
        }
    }

}

fn main() {
    linenoise::set_multiline(true);
    loop {
        let line = linenoise::init("rush: ");
        rush::handle_input(line);
    }
}
<|endoftext|>


<commit_before>use std::collections::{BTreeMap, HashMap};
use std::iter::FromIterator;
use std::fs::{remove_dir_all, copy, remove_file};
use std::path::{Path, PathBuf};

use glob::glob;
use tera::{Tera, Context};
use slug::slugify;
use walkdir::WalkDir;

use errors::{Result, ResultExt};
use config::{Config, get_config};
use page::{Page};
use utils::{create_file, create_directory};
use section::{Section};

lazy_static! {
    static ref GUTENBERG_TERA: Tera = {
        let mut tera = Tera::default();
        tera.add_raw_templates(vec![
            ("rss.xml", include_str!("templates/rss.xml")),
            ("sitemap.xml", include_str!("templates/sitemap.xml")),
        ]).unwrap();
        tera
    };
}

#[derive(Debug, PartialEq)]
enum RenderList {
    Tags,
    Categories,
}

/// A tag or category
#[derive(Debug, Serialize, PartialEq)]
struct ListItem {
    name: String,
    slug: String,
    count: usize,
}

impl ListItem {
    pub fn new(name: &str, count: usize) -> ListItem {
        ListItem {
            name: name.to_string(),
            slug: slugify(name),
            count: count,
        }
    }
}

#[derive(Debug)]
pub struct Site {
    pub base_path: PathBuf,
    pub config: Config,
    pub pages: HashMap<PathBuf, Page>,
    pub sections: BTreeMap<PathBuf, Section>,
    pub templates: Tera,
    live_reload: bool,
    output_path: PathBuf,
}

impl Site {
    /// Parse a site at the given path. Defaults to the current dir
    /// Passing in a path is only used in tests
    pub fn new<P: AsRef<Path>>(path: P) -> Result<Site> {
        let path = path.as_ref();

        let tpl_glob = format!("{}/{}", path.to_string_lossy().replace("\\", "/"), "templates/**/*");
        let mut tera = Tera::new(&tpl_glob).chain_err(|| "Error parsing templates")?;
        tera.extend(&GUTENBERG_TERA)?;

        let mut site = Site {
            base_path: path.to_path_buf(),
            config: get_config(path),
            pages: HashMap::new(),
            sections: BTreeMap::new(),
            templates: tera,
            live_reload: false,
            output_path: PathBuf::from("public"),
        };
        site.parse_site()?;

        Ok(site)
    }

    /// What the function name says
    pub fn enable_live_reload(&mut self) {
        self.live_reload = true;
    }

    /// Used by tests to change the output path to a tmp dir
    #[doc(hidden)]
    pub fn set_output_path<P: AsRef<Path>>(&mut self, path: P) {
        self.output_path = path.as_ref().to_path_buf();
    }

    /// Reads all .md files in the `content` directory and create pages
    /// out of them
    fn parse_site(&mut self) -> Result<()> {
        let path = self.base_path.to_string_lossy().replace("\\", "/");
        let content_glob = format!("{}/{}", path, "content/**/*.md");

        // parent_dir -> Section
        let mut sections = BTreeMap::new();

        // Glob is giving us the result order so _index will show up first
        // for each directory
        for entry in glob(&content_glob).unwrap().filter_map(|e| e.ok()) {
            let path = entry.as_path();

            if path.file_name().unwrap() == "_index.md" {
                let section = Section::from_file(&path, &self.config)?;
                sections.insert(section.parent_path.clone(), section);
            } else {
                let page = Page::from_file(&path, &self.config)?;
                if sections.contains_key(&page.parent_path) {
                    sections.get_mut(&page.parent_path).unwrap().pages.push(page.clone());
                }
                self.pages.insert(page.file_path.clone(), page);
            }
        }

        // Find out the direct subsections of each subsection if there are some
        let mut grandparent_paths = HashMap::new();
        for section in sections.values() {
            let grand_parent = section.parent_path.parent().unwrap().to_path_buf();
            grandparent_paths.entry(grand_parent).or_insert_with(|| vec![]).push(section.clone());
        }

        for (parent_path, section) in &mut sections {
            match grandparent_paths.get(parent_path) {
                Some(paths) => section.subsections.extend(paths.clone()),
                None => continue,
            };
        }

        self.sections = sections;

        Ok(())
    }

    /// Inject live reload script tag if in live reload mode
    fn inject_livereload(&self, html: String) -> String {
        if self.live_reload {
            return html.replace(
                "",
                r#""#
            );
        }

        html
    }

    /// Copy the content of the `static` folder into the `public` folder
    ///
    /// TODO: only copy one file if possible because that would be a waste
    /// to do re-copy the whole thing. Benchmark first to see if it's a big difference
    pub fn copy_static_directory(&self) -> Result<()> {
        let from = Path::new("static");
        let target = Path::new("public");

        for entry in WalkDir::new(from).into_iter().filter_map(|e| e.ok()) {
            let relative_path = entry.path().strip_prefix(&from).unwrap();
            let target_path = {
                let mut target_path = target.to_path_buf();
                target_path.push(relative_path);
                target_path
            };

            if entry.path().is_dir() {
                if !target_path.exists() {
                    create_directory(&target_path)?;
                }
            } else {
                if target_path.exists() {
                    remove_file(&target_path)?;
                }
                copy(entry.path(), &target_path)?;
            }
        }
        Ok(())
    }

    /// Deletes the `public` directory if it exists
    pub fn clean(&self) -> Result<()> {
        if Path::new("public").exists() {
            // Delete current `public` directory so we can start fresh
            remove_dir_all("public").chain_err(|| "Couldn't delete `public` directory")?;
        }

        Ok(())
    }

    pub fn rebuild_after_content_change(&mut self) -> Result<()> {
        self.parse_site()?;
        self.build()
    }

    pub fn rebuild_after_template_change(&mut self) -> Result<()> {
        self.templates.full_reload()?;
        self.build_pages()
    }

    pub fn build_pages(&self) -> Result<()> {
        let public = self.output_path.clone();
        if !public.exists() {
            create_directory(&public)?;
        }

        let mut pages = vec![];
        let mut category_pages: HashMap<String, Vec<&Page>> = HashMap::new();
        let mut tag_pages: HashMap<String, Vec<&Page>> = HashMap::new();

        // First we render the pages themselves
        for page in self.pages.values() {
            // Copy the nesting of the content directory if we have sections for that page
            let mut current_path = public.to_path_buf();

            for component in page.url.split('/') {
                current_path.push(component);

                if !current_path.exists() {
                    create_directory(&current_path)?;
                }
            }

            // Make sure the folder exists
            create_directory(&current_path)?;

            // Finally, create a index.html file there with the page rendered
            let output = page.render_html(&self.templates, &self.config)?;
            create_file(current_path.join("index.html"), &self.inject_livereload(output))?;

            // Copy any asset we found previously into the same directory as the index.html
            for asset in &page.assets {
                let asset_path = asset.as_path();
                copy(&asset_path, &current_path.join(asset_path.file_name().unwrap()))?;
            }

            pages.push(page);

            if let Some(ref category) = page.meta.category {
                category_pages.entry(category.to_string()).or_insert_with(|| vec![]).push(page);
            }

            if let Some(ref tags) = page.meta.tags {
                for tag in tags {
                    tag_pages.entry(tag.to_string()).or_insert_with(|| vec![]).push(page);
                }
            }
        }

        // Outputting categories and pages
        self.render_categories_and_tags(RenderList::Categories, &category_pages)?;
        self.render_categories_and_tags(RenderList::Tags, &tag_pages)?;

        // And finally the index page
        let mut context = Context::new();
        pages.sort_by(|a, b| a.partial_cmp(b).unwrap());
        context.add("pages", &pages);
        context.add("config", &self.config);
        let index = self.templates.render("index.html", &context)?;
        create_file(public.join("index.html"), &self.inject_livereload(index))?;

        Ok(())
    }

    /// Builds the site to the `public` directory after deleting it
    pub fn build(&self) -> Result<()> {
        self.clean()?;
        self.build_pages()?;
        self.render_sitemap()?;
        if self.config.generate_rss.unwrap() {
            self.render_rss_feed()?;
        }
        self.render_sections()?;
        self.copy_static_directory()
    }

    /// Render the /{categories, list} pages and each individual category/tag page
    fn render_categories_and_tags(&self, kind: RenderList, container: &HashMap<String, Vec<&Page>>) -> Result<()> {
        if container.is_empty() {
            return Ok(());
        }

        let (name, list_tpl_name, single_tpl_name, var_name) = if kind == RenderList::Categories {
            ("categories", "categories.html", "category.html", "category")
        } else {
            ("tags", "tags.html", "tag.html", "tag")
        };

        let public = self.output_path.clone();
        let mut output_path = public.to_path_buf();
        output_path.push(name);
        create_directory(&output_path)?;

        // First we render the list of categories/tags page
        let mut sorted_container = vec![];
        for (item, count) in Vec::from_iter(container).into_iter().map(|(a, b)| (a, b.len())) {
            sorted_container.push(ListItem::new(item, count));
        }
        sorted_container.sort_by(|a, b| b.count.cmp(&a.count));

        let mut context = Context::new();
        context.add(name, &sorted_container);
        context.add("config", &self.config);

        let list_output = self.templates.render(list_tpl_name, &context)?;
        create_file(output_path.join("index.html"), &self.inject_livereload(list_output))?;

        // and then each individual item
        for (item_name, mut pages) in container.clone() {
            let mut context = Context::new();
            pages.sort_by(|a, b| a.partial_cmp(b).unwrap());
            let slug = slugify(&item_name);
            context.add(var_name, &item_name);
            context.add(&format!("{}_slug", var_name), &slug);
            context.add("pages", &pages);
            context.add("config", &self.config);
            let single_output = self.templates.render(single_tpl_name, &context)?;

            create_directory(&output_path.join(&slug))?;
            create_file(
                output_path.join(&slug).join("index.html"),
                &self.inject_livereload(single_output)
            )?;
        }

        Ok(())
    }

    fn render_sitemap(&self) -> Result<()> {
        let mut context = Context::new();
        context.add("pages", &self.pages.values().collect::<Vec<&Page>>());
        context.add("sections", &self.sections.values().collect::<Vec<&Section>>());
        // TODO: add categories and tags pages
        let sitemap = self.templates.render("sitemap.xml", &context)?;

        create_file(self.output_path.join("sitemap.xml"), &sitemap)?;

        Ok(())
    }

    fn render_rss_feed(&self) -> Result<()> {
        let mut context = Context::new();
        let mut pages = self.pages.values()
            .filter(|p| p.meta.date.is_some())
            .take(15) // limit to the last 15 elements
            .collect::<Vec<&Page>>();

        // Don't generate a RSS feed if none of the pages has a date
        if pages.is_empty() {
            return Ok(());
        }

        pages.sort_by(|a, b| a.partial_cmp(b).unwrap());
        context.add("pages", &pages);
        context.add("last_build_date", &pages[0].meta.date);
        context.add("config", &self.config);

        let rss_feed_url = if self.config.base_url.ends_with('/') {
            format!("{}{}", self.config.base_url, "feed.xml")
        } else {
            format!("{}/{}", self.config.base_url, "feed.xml")
        };
        context.add("feed_url", &rss_feed_url);

        let sitemap = self.templates.render("rss.xml", &context)?;

        create_file(self.output_path.join("rss.xml"), &sitemap)?;

        Ok(())
    }

    fn render_sections(&self) -> Result<()> {
        let public = self.output_path.clone();

        for section in self.sections.values() {
            let mut output_path = public.to_path_buf();
            for component in &section.components {
                output_path.push(component);

                if !output_path.exists() {
                    create_directory(&output_path)?;
                }
            }

            let output = section.render_html(&self.templates, &self.config)?;
            create_file(output_path.join("index.html"), &self.inject_livereload(output))?;
        }

        Ok(())
    }
}
<commit_msg>Sort section pages after parsing<commit_after>use std::collections::{BTreeMap, HashMap};
use std::iter::FromIterator;
use std::fs::{remove_dir_all, copy, remove_file};
use std::path::{Path, PathBuf};

use glob::glob;
use tera::{Tera, Context};
use slug::slugify;
use walkdir::WalkDir;

use errors::{Result, ResultExt};
use config::{Config, get_config};
use page::{Page};
use utils::{create_file, create_directory};
use section::{Section};

lazy_static! {
    static ref GUTENBERG_TERA: Tera = {
        let mut tera = Tera::default();
        tera.add_raw_templates(vec![
            ("rss.xml", include_str!("templates/rss.xml")),
            ("sitemap.xml", include_str!("templates/sitemap.xml")),
        ]).unwrap();
        tera
    };
}

#[derive(Debug, PartialEq)]
enum RenderList {
    Tags,
    Categories,
}

/// A tag or category
#[derive(Debug, Serialize, PartialEq)]
struct ListItem {
    name: String,
    slug: String,
    count: usize,
}

impl ListItem {
    pub fn new(name: &str, count: usize) -> ListItem {
        ListItem {
            name: name.to_string(),
            slug: slugify(name),
            count: count,
        }
    }
}

#[derive(Debug)]
pub struct Site {
    pub base_path: PathBuf,
    pub config: Config,
    pub pages: HashMap<PathBuf, Page>,
    pub sections: BTreeMap<PathBuf, Section>,
    pub templates: Tera,
    live_reload: bool,
    output_path: PathBuf,
}

impl Site {
    /// Parse a site at the given path. Defaults to the current dir
    /// Passing in a path is only used in tests
    pub fn new<P: AsRef<Path>>(path: P) -> Result<Site> {
        let path = path.as_ref();

        let tpl_glob = format!("{}/{}", path.to_string_lossy().replace("\\", "/"), "templates/**/*");
        let mut tera = Tera::new(&tpl_glob).chain_err(|| "Error parsing templates")?;
        tera.extend(&GUTENBERG_TERA)?;

        let mut site = Site {
            base_path: path.to_path_buf(),
            config: get_config(path),
            pages: HashMap::new(),
            sections: BTreeMap::new(),
            templates: tera,
            live_reload: false,
            output_path: PathBuf::from("public"),
        };
        site.parse_site()?;

        Ok(site)
    }

    /// What the function name says
    pub fn enable_live_reload(&mut self) {
        self.live_reload = true;
    }

    /// Used by tests to change the output path to a tmp dir
    #[doc(hidden)]
    pub fn set_output_path<P: AsRef<Path>>(&mut self, path: P) {
        self.output_path = path.as_ref().to_path_buf();
    }

    /// Reads all .md files in the `content` directory and create pages
    /// out of them
    fn parse_site(&mut self) -> Result<()> {
        let path = self.base_path.to_string_lossy().replace("\\", "/");
        let content_glob = format!("{}/{}", path, "content/**/*.md");

        // parent_dir -> Section
        let mut sections = BTreeMap::new();

        // Glob is giving us the result order so _index will show up first
        // for each directory
        for entry in glob(&content_glob).unwrap().filter_map(|e| e.ok()) {
            let path = entry.as_path();

            if path.file_name().unwrap() == "_index.md" {
                let section = Section::from_file(&path, &self.config)?;
                sections.insert(section.parent_path.clone(), section);
            } else {
                let page = Page::from_file(&path, &self.config)?;
                if sections.contains_key(&page.parent_path) {
                    sections.get_mut(&page.parent_path).unwrap().pages.push(page.clone());
                }
                self.pages.insert(page.file_path.clone(), page);
            }
        }

        // Find out the direct subsections of each subsection if there are some
        let mut grandparent_paths = HashMap::new();
        for section in sections.values() {
            let grand_parent = section.parent_path.parent().unwrap().to_path_buf();
            grandparent_paths.entry(grand_parent).or_insert_with(|| vec![]).push(section.clone());
        }

        for (parent_path, section) in &mut sections {
            section.pages.sort_by(|a, b| a.partial_cmp(b).unwrap());

            match grandparent_paths.get(parent_path) {
                Some(paths) => section.subsections.extend(paths.clone()),
                None => continue,
            };
        }

        self.sections = sections;

        Ok(())
    }

    /// Inject live reload script tag if in live reload mode
    fn inject_livereload(&self, html: String) -> String {
        if self.live_reload {
            return html.replace(
                "",
                r#""#
            );
        }

        html
    }

    /// Copy the content of the `static` folder into the `public` folder
    ///
    /// TODO: only copy one file if possible because that would be a waste
    /// to do re-copy the whole thing. Benchmark first to see if it's a big difference
    pub fn copy_static_directory(&self) -> Result<()> {
        let from = Path::new("static");
        let target = Path::new("public");

        for entry in WalkDir::new(from).into_iter().filter_map(|e| e.ok()) {
            let relative_path = entry.path().strip_prefix(&from).unwrap();
            let target_path = {
                let mut target_path = target.to_path_buf();
                target_path.push(relative_path);
                target_path
            };

            if entry.path().is_dir() {
                if !target_path.exists() {
                    create_directory(&target_path)?;
                }
            } else {
                if target_path.exists() {
                    remove_file(&target_path)?;
                }
                copy(entry.path(), &target_path)?;
            }
        }
        Ok(())
    }

    /// Deletes the `public` directory if it exists
    pub fn clean(&self) -> Result<()> {
        if Path::new("public").exists() {
            // Delete current `public` directory so we can start fresh
            remove_dir_all("public").chain_err(|| "Couldn't delete `public` directory")?;
        }

        Ok(())
    }

    pub fn rebuild_after_content_change(&mut self) -> Result<()> {
        self.parse_site()?;
        self.build()
    }

    pub fn rebuild_after_template_change(&mut self) -> Result<()> {
        self.templates.full_reload()?;
        self.build_pages()
    }

    pub fn build_pages(&self) -> Result<()> {
        let public = self.output_path.clone();
        if !public.exists() {
            create_directory(&public)?;
        }

        let mut pages = vec![];
        let mut category_pages: HashMap<String, Vec<&Page>> = HashMap::new();
        let mut tag_pages: HashMap<String, Vec<&Page>> = HashMap::new();

        // First we render the pages themselves
        for page in self.pages.values() {
            // Copy the nesting of the content directory if we have sections for that page
            let mut current_path = public.to_path_buf();

            for component in page.url.split('/') {
                current_path.push(component);

                if !current_path.exists() {
                    create_directory(&current_path)?;
                }
            }

            // Make sure the folder exists
            create_directory(&current_path)?;

            // Finally, create a index.html file there with the page rendered
            let output = page.render_html(&self.templates, &self.config)?;
            create_file(current_path.join("index.html"), &self.inject_livereload(output))?;

            // Copy any asset we found previously into the same directory as the index.html
            for asset in &page.assets {
                let asset_path = asset.as_path();
                copy(&asset_path, &current_path.join(asset_path.file_name().unwrap()))?;
            }

            pages.push(page);

            if let Some(ref category) = page.meta.category {
                category_pages.entry(category.to_string()).or_insert_with(|| vec![]).push(page);
            }

            if let Some(ref tags) = page.meta.tags {
                for tag in tags {
                    tag_pages.entry(tag.to_string()).or_insert_with(|| vec![]).push(page);
                }
            }
        }

        // Outputting categories and pages
        self.render_categories_and_tags(RenderList::Categories, &category_pages)?;
        self.render_categories_and_tags(RenderList::Tags, &tag_pages)?;

        // And finally the index page
        let mut context = Context::new();
        pages.sort_by(|a, b| a.partial_cmp(b).unwrap());
        context.add("pages", &pages);
        context.add("config", &self.config);
        let index = self.templates.render("index.html", &context)?;
        create_file(public.join("index.html"), &self.inject_livereload(index))?;

        Ok(())
    }

    /// Builds the site to the `public` directory after deleting it
    pub fn build(&self) -> Result<()> {
        self.clean()?;
        self.build_pages()?;
        self.render_sitemap()?;
        if self.config.generate_rss.unwrap() {
            self.render_rss_feed()?;
        }
        self.render_sections()?;
        self.copy_static_directory()
    }

    /// Render the /{categories, list} pages and each individual category/tag page
    fn render_categories_and_tags(&self, kind: RenderList, container: &HashMap<String, Vec<&Page>>) -> Result<()> {
        if container.is_empty() {
            return Ok(());
        }

        let (name, list_tpl_name, single_tpl_name, var_name) = if kind == RenderList::Categories {
            ("categories", "categories.html", "category.html", "category")
        } else {
            ("tags", "tags.html", "tag.html", "tag")
        };

        let public = self.output_path.clone();
        let mut output_path = public.to_path_buf();
        output_path.push(name);
        create_directory(&output_path)?;

        // First we render the list of categories/tags page
        let mut sorted_container = vec![];
        for (item, count) in Vec::from_iter(container).into_iter().map(|(a, b)| (a, b.len())) {
            sorted_container.push(ListItem::new(item, count));
        }
        sorted_container.sort_by(|a, b| b.count.cmp(&a.count));

        let mut context = Context::new();
        context.add(name, &sorted_container);
        context.add("config", &self.config);

        let list_output = self.templates.render(list_tpl_name, &context)?;
        create_file(output_path.join("index.html"), &self.inject_livereload(list_output))?;

        // and then each individual item
        for (item_name, mut pages) in container.clone() {
            let mut context = Context::new();
            pages.sort_by(|a, b| a.partial_cmp(b).unwrap());
            let slug = slugify(&item_name);
            context.add(var_name, &item_name);
            context.add(&format!("{}_slug", var_name), &slug);
            context.add("pages", &pages);
            context.add("config", &self.config);
            let single_output = self.templates.render(single_tpl_name, &context)?;

            create_directory(&output_path.join(&slug))?;
            create_file(
                output_path.join(&slug).join("index.html"),
                &self.inject_livereload(single_output)
            )?;
        }

        Ok(())
    }

    fn render_sitemap(&self) -> Result<()> {
        let mut context = Context::new();
        context.add("pages", &self.pages.values().collect::<Vec<&Page>>());
        context.add("sections", &self.sections.values().collect::<Vec<&Section>>());
        // TODO: add categories and tags pages
        let sitemap = self.templates.render("sitemap.xml", &context)?;

        create_file(self.output_path.join("sitemap.xml"), &sitemap)?;

        Ok(())
    }

    fn render_rss_feed(&self) -> Result<()> {
        let mut context = Context::new();
        let mut pages = self.pages.values()
            .filter(|p| p.meta.date.is_some())
            .take(15) // limit to the last 15 elements
            .collect::<Vec<&Page>>();

        // Don't generate a RSS feed if none of the pages has a date
        if pages.is_empty() {
            return Ok(());
        }

        pages.sort_by(|a, b| a.partial_cmp(b).unwrap());
        context.add("pages", &pages);
        context.add("last_build_date", &pages[0].meta.date);
        context.add("config", &self.config);

        let rss_feed_url = if self.config.base_url.ends_with('/') {
            format!("{}{}", self.config.base_url, "feed.xml")
        } else {
            format!("{}/{}", self.config.base_url, "feed.xml")
        };
        context.add("feed_url", &rss_feed_url);

        let sitemap = self.templates.render("rss.xml", &context)?;

        create_file(self.output_path.join("rss.xml"), &sitemap)?;

        Ok(())
    }

    fn render_sections(&self) -> Result<()> {
        let public = self.output_path.clone();

        for section in self.sections.values() {
            let mut output_path = public.to_path_buf();
            for component in &section.components {
                output_path.push(component);

                if !output_path.exists() {
                    create_directory(&output_path)?;
                }
            }

            let output = section.render_html(&self.templates, &self.config)?;
            create_file(output_path.join("index.html"), &self.inject_livereload(output))?;
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::{fmt, mem};
use std::rc::Rc;
use std::cell::RefCell;

use futures::{Async, Future, Poll};
use futures::task::{Task as FutureTask, current as current_task};

use body::{Body, BodyStream, Binary};
use context::Frame;
use h1writer::{Writer, WriterState};
use error::{Error, UnexpectedTaskFrame};
use pipeline::MiddlewaresResponse;
use httprequest::HttpRequest;
use httpresponse::HttpResponse;

#[derive(PartialEq, Debug)]
enum TaskRunningState {
    Paused,
    Running,
    Done,
}

impl TaskRunningState {
    fn is_done(&self) -> bool {
        *self == TaskRunningState::Done
    }
    fn pause(&mut self) {
        if *self != TaskRunningState::Done {
            *self = TaskRunningState::Paused
        }
    }
    fn resume(&mut self) {
        if *self != TaskRunningState::Done {
            *self = TaskRunningState::Running
        }
    }
}

enum ResponseState {
    Reading,
    Ready(HttpResponse),
    Middlewares(MiddlewaresResponse),
    Prepared(Option<HttpResponse>),
}

enum IOState {
    Response,
    Payload(BodyStream),
    Context,
    Done,
}

enum TaskStream {
    None,
    Context(Box<IoContext>),
    Response(Box<Future<Item=HttpResponse, Error=Error>>),
}

impl IOState {
    fn is_done(&self) -> bool {
        match *self {
            IOState::Done => true,
            _ => false
        }
    }
}

impl ResponseState {
    fn is_reading(&self) -> bool {
        match *self {
            ResponseState::Reading => true,
            _ => false
        }
    }
}

impl fmt::Debug for ResponseState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ResponseState::Reading => write!(f, "ResponseState::Reading"),
            ResponseState::Ready(_) => write!(f, "ResponseState::Ready"),
            ResponseState::Middlewares(_) => write!(f, "ResponseState::Middlewares"),
            ResponseState::Prepared(_) => write!(f, "ResponseState::Prepared"),
        }
    }
}

impl fmt::Debug for IOState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            IOState::Response => write!(f, "IOState::Response"),
            IOState::Payload(_) => write!(f, "IOState::Payload"),
            IOState::Context => write!(f, "IOState::Context"),
            IOState::Done => write!(f, "IOState::Done"),
        }
    }
}

pub(crate) trait IoContext: 'static {
    fn disconnected(&mut self);
    fn poll(&mut self) -> Poll<Option<Frame>, Error>;
}

/// Future that resolves when all buffered data get sent
#[doc(hidden)]
#[derive(Debug)]
pub struct DrainFut {
    drained: bool,
    task: Option<FutureTask>,
}

impl Default for DrainFut {

    fn default() -> DrainFut {
        DrainFut {
            drained: false,
            task: None,
        }
    }
}

impl DrainFut {

    fn set(&mut self) {
        self.drained = true;
        if let Some(task) = self.task.take() {
            task.notify()
        }
    }
}

impl Future for DrainFut {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        if self.drained {
            Ok(Async::Ready(()))
        } else {
            self.task = Some(current_task());
            Ok(Async::NotReady)
        }
    }
}

pub struct Task {
    running: TaskRunningState,
    response: ResponseState,
    iostate: IOState,
    stream: TaskStream,
    drain: Vec<Rc<RefCell<DrainFut>>>,
    disconnected: bool,
    middlewares: Option<MiddlewaresResponse>,
}

#[doc(hidden)]
impl Default for Task {

    fn default() -> Task {
        Task { running: TaskRunningState::Running,
               response: ResponseState::Reading,
               iostate: IOState::Response,
               drain: Vec::new(),
               stream: TaskStream::None,
               disconnected: false,
               middlewares: None }
    }
}

impl Task {

    pub(crate) fn from_response<R: Into<HttpResponse>>(response: R) -> Task {
        Task { running: TaskRunningState::Running,
               response: ResponseState::Ready(response.into()),
               iostate: IOState::Response,
               drain: Vec::new(),
               stream: TaskStream::None,
               disconnected: false,
               middlewares: None }
    }

    pub(crate) fn from_error<E: Into<Error>>(err: E) -> Task {
        Task::from_response(err.into())
    }

    pub fn reply<R: Into<HttpResponse>>(&mut self, response: R) {
        let state = &mut self.response;
        match *state {
            ResponseState::Reading =>
                *state = ResponseState::Ready(response.into()),
            _ => panic!("Internal task state is broken"),
        }
    }

    pub fn error<E: Into<Error>>(&mut self, err: E) {
        self.reply(err.into())
    }

    pub(crate) fn context(&mut self, ctx: Box<IoContext>) {
        self.stream = TaskStream::Context(ctx);
    }

    pub fn async<F>(&mut self, fut: F)
        where F: Future<Item=HttpResponse, Error=Error> + 'static
    {
        self.stream = TaskStream::Response(Box::new(fut));
    }

    pub(crate) fn response(&mut self) -> HttpResponse {
        match self.response {
            ResponseState::Prepared(ref mut state) => state.take().unwrap(),
            _ => panic!("Internal state is broken"),
        }
    }

    pub(crate) fn set_middlewares(&mut self, middlewares: MiddlewaresResponse) {
        self.middlewares = Some(middlewares)
    }

    pub(crate) fn disconnected(&mut self) {
        self.disconnected = true;
        if let TaskStream::Context(ref mut ctx) = self.stream {
            ctx.disconnected();
        }
    }

    pub(crate) fn poll_io<T>(&mut self, io: &mut T, req: &mut HttpRequest) -> Poll<bool, Error>
        where T: Writer
    {
        trace!("POLL-IO frames resp: {:?}, io: {:?}, running: {:?}",
               self.response, self.iostate, self.running);

        if self.iostate.is_done() {  // response is completed
            return Ok(Async::Ready(self.running.is_done()));
        } else if self.drain.is_empty() && self.running != TaskRunningState::Paused {
            // if task is paused, write buffer is probably full

            loop {
                let result = match mem::replace(&mut self.iostate, IOState::Done) {
                    IOState::Response => {
                        match self.poll_response(req) {
                            Ok(Async::Ready(mut resp)) => {
                                let result = io.start(req, &mut resp)?;

                                match resp.replace_body(Body::Empty) {
                                    Body::Streaming(stream) | Body::Upgrade(stream) =>
                                        self.iostate = IOState::Payload(stream),
                                    Body::StreamingContext | Body::UpgradeContext =>
                                        self.iostate = IOState::Context,
                                    _ => (),
                                }
                                self.response = ResponseState::Prepared(Some(resp));
                                result
                            },
                            Ok(Async::NotReady) => {
                                self.iostate = IOState::Response;
                                return Ok(Async::NotReady)
                            }
                            Err(err) => {
                                let mut resp = err.into();
                                let result = io.start(req, &mut resp)?;

                                match resp.replace_body(Body::Empty) {
                                    Body::Streaming(stream) | Body::Upgrade(stream) =>
                                        self.iostate = IOState::Payload(stream),
                                    _ => (),
                                }
                                self.response = ResponseState::Prepared(Some(resp));
                                result
                            }
                        }
                    },
                    IOState::Payload(mut body) => {
                        // always poll stream
                        if self.running == TaskRunningState::Running {
                            match self.poll()? {
                                Async::Ready(_) =>
                                    self.running = TaskRunningState::Done,
                                Async::NotReady => (),
                            }
                        }

                        match body.poll() {
                            Ok(Async::Ready(None)) => {
                                self.iostate = IOState::Done;
                                io.write_eof()?;
                                break
                            },
                            Ok(Async::Ready(Some(chunk))) => {
                                self.iostate = IOState::Payload(body);
                                io.write(chunk.as_ref())?
                            }
                            Ok(Async::NotReady) => {
                                self.iostate = IOState::Payload(body);
                                break
                            },
                            Err(err) => return Err(err),
                        }
                    }
                    IOState::Context => {
                        match self.poll_context() {
                            Ok(Async::Ready(None)) => {
                                self.iostate = IOState::Done;
                                self.running = TaskRunningState::Done;
                                io.write_eof()?;
                                break
                            },
                            Ok(Async::Ready(Some(chunk))) => {
                                self.iostate = IOState::Context;
                                io.write(chunk.as_ref())?
                            }
                            Ok(Async::NotReady) => {
                                self.iostate = IOState::Context;
                                break
                            }
                            Err(err) => return Err(err),
                        }
                    }
                    IOState::Done => break,
                };

                match result {
                    WriterState::Pause => {
                        self.running.pause();
                        break
                    }
                    WriterState::Done =>
                        self.running.resume(),
                }
            }
        }

        // flush io
        match io.poll_complete() {
            Ok(Async::Ready(_)) => self.running.resume(),
            Ok(Async::NotReady) => return Ok(Async::NotReady),
            Err(err) => {
                debug!("Error sending data: {}", err);
                return Err(err.into())
            }
        }

        // drain futures
        if !self.drain.is_empty() {
            for fut in &mut self.drain {
                fut.borrow_mut().set()
            }
            self.drain.clear();
        }

        // response is completed
        if self.iostate.is_done() {
            if let ResponseState::Prepared(Some(ref mut resp)) = self.response {
                resp.set_response_size(io.written())
            }
            Ok(Async::Ready(self.running.is_done()))
        } else {
            Ok(Async::NotReady)
        }
    }

    pub(crate) fn poll_response(&mut self, req: &mut HttpRequest) -> Poll<HttpResponse, Error> {
        loop {
            let state = mem::replace(&mut self.response, ResponseState::Prepared(None));
            match state {
                ResponseState::Ready(response) => {
                    // run middlewares
                    if let Some(mut middlewares) = self.middlewares.take() {
                        match middlewares.response(req, response) {
                            Ok(Some(response)) =>
                                return Ok(Async::Ready(response)),
                            Ok(None) => {
                                // middlewares need to run some futures
                                self.response = ResponseState::Middlewares(middlewares);
                                continue
                            }
                            Err(err) => return Err(err),
                        }
                    } else {
                        return Ok(Async::Ready(response))
                    }
                }
                ResponseState::Middlewares(mut middlewares) => {
                    // process middlewares
                    match middlewares.poll(req) {
                        Ok(Async::NotReady) => {
                            self.response = ResponseState::Middlewares(middlewares);
                            return Ok(Async::NotReady)
                        },
                        Ok(Async::Ready(response)) =>
                            return Ok(Async::Ready(response)),
                        Err(err) =>
                            return Err(err),
                    }
                }
                _ => (),
            }
            self.response = state;

            match mem::replace(&mut self.stream, TaskStream::None) {
                TaskStream::None =>
                    return Ok(Async::NotReady),
                TaskStream::Context(mut context) => {
                    loop {
                        match context.poll() {
                            Ok(Async::Ready(Some(frame))) => {
                                match frame {
                                    Frame::Message(msg) => {
                                        if !self.response.is_reading() {
                                            error!("Unexpected message frame {:?}", msg);
                                            return Err(UnexpectedTaskFrame.into())
                                        }
                                        self.stream = TaskStream::Context(context);
                                        self.response = ResponseState::Ready(msg);
                                        break
                                    },
                                    Frame::Payload(_) => (),
                                    Frame::Drain(fut) => {
                                        self.drain.push(fut);
                                        self.stream = TaskStream::Context(context);
                                        break
                                    }
                                }
                            },
                            Ok(Async::Ready(None)) => {
                                error!("Unexpected eof");
                                return Err(UnexpectedTaskFrame.into())
                            },
                            Ok(Async::NotReady) => {
                                self.stream = TaskStream::Context(context);
                                return Ok(Async::NotReady)
                            },
                            Err(err) =>
                                return Err(err),
                        }
                    }
                },
                TaskStream::Response(mut fut) => {
                    match fut.poll() {
                        Ok(Async::NotReady) => {
                            self.stream = TaskStream::Response(fut);
                            return Ok(Async::NotReady);
                        },
                        Ok(Async::Ready(response)) => {
                            self.response = ResponseState::Ready(response);
                        }
                        Err(err) =>
                            return Err(err)
                    }
                }
            }
        }
    }

    pub(crate) fn poll(&mut self) -> Poll<(), Error> {
        match self.stream {
            TaskStream::None | TaskStream::Response(_) =>
                Ok(Async::Ready(())),
            TaskStream::Context(ref mut context) => {
                loop {
                    match context.poll() {
                        Ok(Async::Ready(Some(_))) => (),
                        Ok(Async::Ready(None)) =>
                            return Ok(Async::Ready(())),
                        Ok(Async::NotReady) =>
                            return Ok(Async::NotReady),
                        Err(err) =>
                            return Err(err),
                    }
                }
            },
        }
    }

    fn poll_context(&mut self) -> Poll<Option<Binary>, Error> {
        match self.stream {
            TaskStream::None | TaskStream::Response(_) =>
                Err(UnexpectedTaskFrame.into()),
            TaskStream::Context(ref mut context) => {
                match context.poll() {
                    Ok(Async::Ready(Some(frame))) => {
                        match frame {
                            Frame::Message(msg) => {
                                error!("Unexpected message frame {:?}", msg);
                                Err(UnexpectedTaskFrame.into())
                            },
                            Frame::Payload(payload) => {
                                Ok(Async::Ready(payload))
                            },
                            Frame::Drain(fut) => {
                                self.drain.push(fut);
                                Ok(Async::NotReady)
                            }
                        }
                    },
                    Ok(Async::Ready(None)) => Ok(Async::Ready(None)),
                    Ok(Async::NotReady) => Ok(Async::NotReady),
                    Err(err) => Err(err),
                }
            },
        }
    }
}
<commit_msg>no need to store disconnected state on task<commit_after>use std::{fmt, mem};
use std::rc::Rc;
use std::cell::RefCell;

use futures::{Async, Future, Poll};
use futures::task::{Task as FutureTask, current as current_task};

use body::{Body, BodyStream, Binary};
use context::Frame;
use h1writer::{Writer, WriterState};
use error::{Error, UnexpectedTaskFrame};
use pipeline::MiddlewaresResponse;
use httprequest::HttpRequest;
use httpresponse::HttpResponse;

#[derive(PartialEq, Debug)]
enum TaskRunningState {
    Paused,
    Running,
    Done,
}

impl TaskRunningState {
    fn is_done(&self) -> bool {
        *self == TaskRunningState::Done
    }
    fn pause(&mut self) {
        if *self != TaskRunningState::Done {
            *self = TaskRunningState::Paused
        }
    }
    fn resume(&mut self) {
        if *self != TaskRunningState::Done {
            *self = TaskRunningState::Running
        }
    }
}

enum ResponseState {
    Reading,
    Ready(HttpResponse),
    Middlewares(MiddlewaresResponse),
    Prepared(Option<HttpResponse>),
}

enum IOState {
    Response,
    Payload(BodyStream),
    Context,
    Done,
}

enum TaskStream {
    None,
    Context(Box<IoContext>),
    Response(Box<Future<Item=HttpResponse, Error=Error>>),
}

impl IOState {
    fn is_done(&self) -> bool {
        match *self {
            IOState::Done => true,
            _ => false
        }
    }
}

impl ResponseState {
    fn is_reading(&self) -> bool {
        match *self {
            ResponseState::Reading => true,
            _ => false
        }
    }
}

impl fmt::Debug for ResponseState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ResponseState::Reading => write!(f, "ResponseState::Reading"),
            ResponseState::Ready(_) => write!(f, "ResponseState::Ready"),
            ResponseState::Middlewares(_) => write!(f, "ResponseState::Middlewares"),
            ResponseState::Prepared(_) => write!(f, "ResponseState::Prepared"),
        }
    }
}

impl fmt::Debug for IOState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            IOState::Response => write!(f, "IOState::Response"),
            IOState::Payload(_) => write!(f, "IOState::Payload"),
            IOState::Context => write!(f, "IOState::Context"),
            IOState::Done => write!(f, "IOState::Done"),
        }
    }
}

pub(crate) trait IoContext: 'static {
    fn disconnected(&mut self);
    fn poll(&mut self) -> Poll<Option<Frame>, Error>;
}

/// Future that resolves when all buffered data get sent
#[doc(hidden)]
#[derive(Debug)]
pub struct DrainFut {
    drained: bool,
    task: Option<FutureTask>,
}

impl Default for DrainFut {

    fn default() -> DrainFut {
        DrainFut {
            drained: false,
            task: None,
        }
    }
}

impl DrainFut {

    fn set(&mut self) {
        self.drained = true;
        if let Some(task) = self.task.take() {
            task.notify()
        }
    }
}

impl Future for DrainFut {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        if self.drained {
            Ok(Async::Ready(()))
        } else {
            self.task = Some(current_task());
            Ok(Async::NotReady)
        }
    }
}

pub struct Task {
    running: TaskRunningState,
    response: ResponseState,
    iostate: IOState,
    stream: TaskStream,
    drain: Vec<Rc<RefCell<DrainFut>>>,
    middlewares: Option<MiddlewaresResponse>,
}

#[doc(hidden)]
impl Default for Task {

    fn default() -> Task {
        Task { running: TaskRunningState::Running,
               response: ResponseState::Reading,
               iostate: IOState::Response,
               drain: Vec::new(),
               stream: TaskStream::None,
               middlewares: None }
    }
}

impl Task {

    pub(crate) fn from_response<R: Into<HttpResponse>>(response: R) -> Task {
        Task { running: TaskRunningState::Running,
               response: ResponseState::Ready(response.into()),
               iostate: IOState::Response,
               drain: Vec::new(),
               stream: TaskStream::None,
               middlewares: None }
    }

    pub(crate) fn from_error<E: Into<Error>>(err: E) -> Task {
        Task::from_response(err.into())
    }

    pub fn reply<R: Into<HttpResponse>>(&mut self, response: R) {
        let state = &mut self.response;
        match *state {
            ResponseState::Reading =>
                *state = ResponseState::Ready(response.into()),
            _ => panic!("Internal task state is broken"),
        }
    }

    pub fn error<E: Into<Error>>(&mut self, err: E) {
        self.reply(err.into())
    }

    pub(crate) fn context(&mut self, ctx: Box<IoContext>) {
        self.stream = TaskStream::Context(ctx);
    }

    pub fn async<F>(&mut self, fut: F)
        where F: Future<Item=HttpResponse, Error=Error> + 'static
    {
        self.stream = TaskStream::Response(Box::new(fut));
    }

    pub(crate) fn response(&mut self) -> HttpResponse {
        match self.response {
            ResponseState::Prepared(ref mut state) => state.take().unwrap(),
            _ => panic!("Internal state is broken"),
        }
    }

    pub(crate) fn set_middlewares(&mut self, middlewares: MiddlewaresResponse) {
        self.middlewares = Some(middlewares)
    }

    pub(crate) fn disconnected(&mut self) {
        if let TaskStream::Context(ref mut ctx) = self.stream {
            ctx.disconnected();
        }
    }

    pub(crate) fn poll_io<T>(&mut self, io: &mut T, req: &mut HttpRequest) -> Poll<bool, Error>
        where T: Writer
    {
        trace!("POLL-IO frames resp: {:?}, io: {:?}, running: {:?}",
               self.response, self.iostate, self.running);

        if self.iostate.is_done() {  // response is completed
            return Ok(Async::Ready(self.running.is_done()));
        } else if self.drain.is_empty() && self.running != TaskRunningState::Paused {
            // if task is paused, write buffer is probably full

            loop {
                let result = match mem::replace(&mut self.iostate, IOState::Done) {
                    IOState::Response => {
                        match self.poll_response(req) {
                            Ok(Async::Ready(mut resp)) => {
                                let result = io.start(req, &mut resp)?;

                                match resp.replace_body(Body::Empty) {
                                    Body::Streaming(stream) | Body::Upgrade(stream) =>
                                        self.iostate = IOState::Payload(stream),
                                    Body::StreamingContext | Body::UpgradeContext =>
                                        self.iostate = IOState::Context,
                                    _ => (),
                                }
                                self.response = ResponseState::Prepared(Some(resp));
                                result
                            },
                            Ok(Async::NotReady) => {
                                self.iostate = IOState::Response;
                                return Ok(Async::NotReady)
                            }
                            Err(err) => {
                                let mut resp = err.into();
                                let result = io.start(req, &mut resp)?;

                                match resp.replace_body(Body::Empty) {
                                    Body::Streaming(stream) | Body::Upgrade(stream) =>
                                        self.iostate = IOState::Payload(stream),
                                    _ => (),
                                }
                                self.response = ResponseState::Prepared(Some(resp));
                                result
                            }
                        }
                    },
                    IOState::Payload(mut body) => {
                        // always poll stream
                        if self.running == TaskRunningState::Running {
                            match self.poll()? {
                                Async::Ready(_) =>
                                    self.running = TaskRunningState::Done,
                                Async::NotReady => (),
                            }
                        }

                        match body.poll() {
                            Ok(Async::Ready(None)) => {
                                self.iostate = IOState::Done;
                                io.write_eof()?;
                                break
                            },
                            Ok(Async::Ready(Some(chunk))) => {
                                self.iostate = IOState::Payload(body);
                                io.write(chunk.as_ref())?
                            }
                            Ok(Async::NotReady) => {
                                self.iostate = IOState::Payload(body);
                                break
                            },
                            Err(err) => return Err(err),
                        }
                    }
                    IOState::Context => {
                        match self.poll_context() {
                            Ok(Async::Ready(None)) => {
                                self.iostate = IOState::Done;
                                self.running = TaskRunningState::Done;
                                io.write_eof()?;
                                break
                            },
                            Ok(Async::Ready(Some(chunk))) => {
                                self.iostate = IOState::Context;
                                io.write(chunk.as_ref())?
                            }
                            Ok(Async::NotReady) => {
                                self.iostate = IOState::Context;
                                break
                            }
                            Err(err) => return Err(err),
                        }
                    }
                    IOState::Done => break,
                };

                match result {
                    WriterState::Pause => {
                        self.running.pause();
                        break
                    }
                    WriterState::Done =>
                        self.running.resume(),
                }
            }
        }

        // flush io
        match io.poll_complete() {
            Ok(Async::Ready(_)) => self.running.resume(),
            Ok(Async::NotReady) => return Ok(Async::NotReady),
            Err(err) => {
                debug!("Error sending data: {}", err);
                return Err(err.into())
            }
        }

        // drain futures
        if !self.drain.is_empty() {
            for fut in &mut self.drain {
                fut.borrow_mut().set()
            }
            self.drain.clear();
        }

        // response is completed
        if self.iostate.is_done() {
            if let ResponseState::Prepared(Some(ref mut resp)) = self.response {
                resp.set_response_size(io.written())
            }
            Ok(Async::Ready(self.running.is_done()))
        } else {
            Ok(Async::NotReady)
        }
    }

    pub(crate) fn poll_response(&mut self, req: &mut HttpRequest) -> Poll<HttpResponse, Error> {
        loop {
            let state = mem::replace(&mut self.response, ResponseState::Prepared(None));
            match state {
                ResponseState::Ready(response) => {
                    // run middlewares
                    if let Some(mut middlewares) = self.middlewares.take() {
                        match middlewares.response(req, response) {
                            Ok(Some(response)) =>
                                return Ok(Async::Ready(response)),
                            Ok(None) => {
                                // middlewares need to run some futures
                                self.response = ResponseState::Middlewares(middlewares);
                                continue
                            }
                            Err(err) => return Err(err),
                        }
                    } else {
                        return Ok(Async::Ready(response))
                    }
                }
                ResponseState::Middlewares(mut middlewares) => {
                    // process middlewares
                    match middlewares.poll(req) {
                        Ok(Async::NotReady) => {
                            self.response = ResponseState::Middlewares(middlewares);
                            return Ok(Async::NotReady)
                        },
                        Ok(Async::Ready(response)) =>
                            return Ok(Async::Ready(response)),
                        Err(err) =>
                            return Err(err),
                    }
                }
                _ => (),
            }
            self.response = state;

            match mem::replace(&mut self.stream, TaskStream::None) {
                TaskStream::None =>
                    return Ok(Async::NotReady),
                TaskStream::Context(mut context) => {
                    loop {
                        match context.poll() {
                            Ok(Async::Ready(Some(frame))) => {
                                match frame {
                                    Frame::Message(msg) => {
                                        if !self.response.is_reading() {
                                            error!("Unexpected message frame {:?}", msg);
                                            return Err(UnexpectedTaskFrame.into())
                                        }
                                        self.stream = TaskStream::Context(context);
                                        self.response = ResponseState::Ready(msg);
                                        break
                                    },
                                    Frame::Payload(_) => (),
                                    Frame::Drain(fut) => {
                                        self.drain.push(fut);
                                        self.stream = TaskStream::Context(context);
                                        break
                                    }
                                }
                            },
                            Ok(Async::Ready(None)) => {
                                error!("Unexpected eof");
                                return Err(UnexpectedTaskFrame.into())
                            },
                            Ok(Async::NotReady) => {
                                self.stream = TaskStream::Context(context);
                                return Ok(Async::NotReady)
                            },
                            Err(err) =>
                                return Err(err),
                        }
                    }
                },
                TaskStream::Response(mut fut) => {
                    match fut.poll() {
                        Ok(Async::NotReady) => {
                            self.stream = TaskStream::Response(fut);
                            return Ok(Async::NotReady);
                        },
                        Ok(Async::Ready(response)) => {
                            self.response = ResponseState::Ready(response);
                        }
                        Err(err) =>
                            return Err(err)
                    }
                }
            }
        }
    }

    pub(crate) fn poll(&mut self) -> Poll<(), Error> {
        match self.stream {
            TaskStream::None | TaskStream::Response(_) =>
                Ok(Async::Ready(())),
            TaskStream::Context(ref mut context) => {
                loop {
                    match context.poll() {
                        Ok(Async::Ready(Some(_))) => (),
                        Ok(Async::Ready(None)) =>
                            return Ok(Async::Ready(())),
                        Ok(Async::NotReady) =>
                            return Ok(Async::NotReady),
                        Err(err) =>
                            return Err(err),
                    }
                }
            },
        }
    }

    fn poll_context(&mut self) -> Poll<Option<Binary>, Error> {
        match self.stream {
            TaskStream::None | TaskStream::Response(_) =>
                Err(UnexpectedTaskFrame.into()),
            TaskStream::Context(ref mut context) => {
                match context.poll() {
                    Ok(Async::Ready(Some(frame))) => {
                        match frame {
                            Frame::Message(msg) => {
                                error!("Unexpected message frame {:?}", msg);
                                Err(UnexpectedTaskFrame.into())
                            },
                            Frame::Payload(payload) => {
                                Ok(Async::Ready(payload))
                            },
                            Frame::Drain(fut) => {
                                self.drain.push(fut);
                                Ok(Async::NotReady)
                            }
                        }
                    },
                    Ok(Async::Ready(None)) => Ok(Async::Ready(None)),
                    Ok(Async::NotReady) => Ok(Async::NotReady),
                    Err(err) => Err(err),
                }
            },
        }
    }
}
<|endoftext|>


<commit_before>use words::{Words, Word};

pub struct Tens(u8, u8);

impl Tens
{
    pub fn new(val: usize) -> Tens
    {
        assert!(val < 100);

        let val = val as u8;

        let tens_place = val / 10;
        let ones_place = val % 10;

        Tens(tens_place, ones_place)
    }

    pub fn build(&self) -> Words
    {
        if self.0 * 10 + self.1 < 20
        {
            return Words::new(vec![Word::Number(match self.0 * 10 + self.1
            {
                0 => "zero",
                1 => "one",
                2 => "two",
                3 => "three",
                4 => "four",
                5 => "five",
                6 => "six",
                7 => "seven",
                8 => "eight",
                9 => "nine",
                10 => "ten",
                11 => "eleven",
                12 => "twelve",
                13 => "thirteen",
                14 => "fourteen",
                15 => "fifteen",
                16 => "sixteen",
                17 => "seventeen",
                18 => "eighteen",
                19 => "nineteen",
                _ => unreachable!()
            }.to_owned())])
        }
        else
        {
            let tens = match self.0
            {
                2 => "twenty",
                3 => "thirty",
                4 => "fourty",
                5 => "fifty",
                6 => "sixty",
                7 => "seventy",
                8 => "eighty",
                9 => "ninety",
                _ => unreachable!()
            };

            if self.1 == 0
            {
                return Words::new(vec![Word::Number(tens.to_owned())])
            }
            else
            {
                let ones = match self.1
                {
                    0 => "zero",
                    1 => "one",
                    2 => "two",
                    3 => "three",
                    4 => "four",
                    5 => "five",
                    6 => "six",
                    7 => "seven",
                    8 => "eight",
                    9 => "nine",
                    _ => unreachable!()
                };

                return Words::new(vec![
                    Word::Number(tens.to_owned()),
                    Word::Dash,
                    Word::Number(ones.to_owned())
                ])
            }
        }
    }
}<commit_msg>spelling<commit_after>use words::{Words, Word};

pub struct Tens(u8, u8);

impl Tens
{
    pub fn new(val: usize) -> Tens
    {
        assert!(val < 100);

        let val = val as u8;

        let tens_place = val / 10;
        let ones_place = val % 10;

        Tens(tens_place, ones_place)
    }

    pub fn build(&self) -> Words
    {
        if self.0 * 10 + self.1 < 20
        {
            return Words::new(vec![Word::Number(match self.0 * 10 + self.1
            {
                0 => "zero",
                1 => "one",
                2 => "two",
                3 => "three",
                4 => "four",
                5 => "five",
                6 => "six",
                7 => "seven",
                8 => "eight",
                9 => "nine",
                10 => "ten",
                11 => "eleven",
                12 => "twelve",
                13 => "thirteen",
                14 => "fourteen",
                15 => "fifteen",
                16 => "sixteen",
                17 => "seventeen",
                18 => "eighteen",
                19 => "nineteen",
                _ => unreachable!()
            }.to_owned())])
        }
        else
        {
            let tens = match self.0
            {
                2 => "twenty",
                3 => "thirty",
                4 => "forty",
                5 => "fifty",
                6 => "sixty",
                7 => "seventy",
                8 => "eighty",
                9 => "ninety",
                _ => unreachable!()
            };

            if self.1 == 0
            {
                return Words::new(vec![Word::Number(tens.to_owned())])
            }
            else
            {
                let ones = match self.1
                {
                    0 => "zero",
                    1 => "one",
                    2 => "two",
                    3 => "three",
                    4 => "four",
                    5 => "five",
                    6 => "six",
                    7 => "seven",
                    8 => "eight",
                    9 => "nine",
                    _ => unreachable!()
                };

                return Words::new(vec![
                    Word::Number(tens.to_owned()),
                    Word::Dash,
                    Word::Number(ones.to_owned())
                ])
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io::MemWriter;
use std::fmt::Show;
use std::io::MemReader;
use std::io::IoError;
use std::collections::hashmap::HashMap;

use serialize::{
    Encoder,
    Decoder,
    Encodable,
    Decodable
};

use super::EncoderWriter;
use super::DecoderReader;
use super::encode;
use super::decode;

fn the_same<
            V: Encodable<EncoderWriter<MemWriter>, IoError>  +
               Decodable<DecoderReader<MemReader>, IoError> +
               PartialEq + Show>(element: V) {
    assert!(element == decode(encode(&element).unwrap()).unwrap());
}

#[test]
fn test_numbers() {
    // unsigned positive
    the_same(5u8);
    the_same(5u16);
    the_same(5u32);
    the_same(5u64);
    // signed positive
    the_same(5i8);
    the_same(5i16);
    the_same(5i32);
    the_same(5i64);
    // signed negative
    the_same(-5i8);
    the_same(-5i16);
    the_same(-5i32);
    the_same(-5i64);
    // floating
    the_same(-100f32);
    the_same(0f32);
    the_same(5f32);
    the_same(-100f64);
    the_same(5f64);
}

#[test]
fn test_string() {
    the_same("".to_string());
    the_same("a".to_string());
}

#[test]
fn test_tuple() {
    the_same((1i,));
    the_same((1i,2i,3i));
    the_same((1i,"foo".to_string(),()));
}

#[test]
fn test_basic_struct() {
    #[deriving(Encodable, Decodable, PartialEq, Show)]
    struct Easy {
        x: int,
        s: String,
        y: uint
    }
    the_same(Easy{x: -4, s: "foo".to_string(), y: 10});
}

#[test]
fn test_nested_struct() {
    #[deriving(Encodable, Decodable, PartialEq, Show)]
    struct Easy {
        x: int,
        s: String,
        y: uint
    }
    #[deriving(Encodable, Decodable, PartialEq, Show)]
    struct Nest {
        f: Easy,
        b: uint,
        s: Easy
    }

    the_same(Nest {
        f: Easy {x: -1, s: "foo".to_string(), y: 20},
        b: 100,
        s: Easy {x: -100, s: "bar".to_string(), y: 20}
    });
}

#[test]
fn test_struct_tuple() {
    #[deriving(Encodable, Decodable, PartialEq, Show)]
    struct TubStr(uint, String, f32);

    the_same(TubStr(5, "hello".to_string(), 3.2));
}

#[test]
fn option() {
    the_same(Some(5u));
    the_same(Some("foo bar".to_string()));
    the_same(None::<uint>);
}

#[test]
fn enm() {
    #[deriving(Encodable, Decodable, PartialEq, Show)]
    enum TestEnum {
        NoArg,
        OneArg(uint),
        AnotherNoArg
    }
    the_same(NoArg);
    the_same(OneArg(4));
    the_same(AnotherNoArg);
}

#[test]
fn struct_enum() {
    #[deriving(Encodable, Decodable, PartialEq, Show)]
    enum TestEnum {
        NoArg,
        OneArg(uint),
        AnotherNoArg,
        StructLike{x: uint, y: f32}
    }
    the_same(NoArg);
    the_same(OneArg(4));
    the_same(AnotherNoArg);
    the_same(StructLike{x: 4, y: 3.14159});
}

#[test]
fn many() {
    let v: Vec<u8> = vec![];
    the_same(v);
    the_same(vec![1u]);
    the_same(vec![1u,2,3,4,5,6]);
}

#[test]
fn map(){
    let mut m = HashMap::new();
    m.insert(4u, "foo".to_string());
    m.insert(0u, "bar".to_string());
    the_same(m);
}

#[test]
fn boole(){
    the_same(true);
    the_same(false);
}
<commit_msg>test vec of enums<commit_after>use std::io::MemWriter;
use std::fmt::Show;
use std::io::MemReader;
use std::io::IoError;
use std::collections::hashmap::HashMap;

use serialize::{
    Encoder,
    Decoder,
    Encodable,
    Decodable
};

use super::EncoderWriter;
use super::DecoderReader;
use super::encode;
use super::decode;

fn the_same<
            V: Encodable<EncoderWriter<MemWriter>, IoError>  +
               Decodable<DecoderReader<MemReader>, IoError> +
               PartialEq + Show>(element: V) {
    assert!(element == decode(encode(&element).unwrap()).unwrap());
}

#[test]
fn test_numbers() {
    // unsigned positive
    the_same(5u8);
    the_same(5u16);
    the_same(5u32);
    the_same(5u64);
    // signed positive
    the_same(5i8);
    the_same(5i16);
    the_same(5i32);
    the_same(5i64);
    // signed negative
    the_same(-5i8);
    the_same(-5i16);
    the_same(-5i32);
    the_same(-5i64);
    // floating
    the_same(-100f32);
    the_same(0f32);
    the_same(5f32);
    the_same(-100f64);
    the_same(5f64);
}

#[test]
fn test_string() {
    the_same("".to_string());
    the_same("a".to_string());
}

#[test]
fn test_tuple() {
    the_same((1i,));
    the_same((1i,2i,3i));
    the_same((1i,"foo".to_string(),()));
}

#[test]
fn test_basic_struct() {
    #[deriving(Encodable, Decodable, PartialEq, Show)]
    struct Easy {
        x: int,
        s: String,
        y: uint
    }
    the_same(Easy{x: -4, s: "foo".to_string(), y: 10});
}

#[test]
fn test_nested_struct() {
    #[deriving(Encodable, Decodable, PartialEq, Show)]
    struct Easy {
        x: int,
        s: String,
        y: uint
    }
    #[deriving(Encodable, Decodable, PartialEq, Show)]
    struct Nest {
        f: Easy,
        b: uint,
        s: Easy
    }

    the_same(Nest {
        f: Easy {x: -1, s: "foo".to_string(), y: 20},
        b: 100,
        s: Easy {x: -100, s: "bar".to_string(), y: 20}
    });
}

#[test]
fn test_struct_tuple() {
    #[deriving(Encodable, Decodable, PartialEq, Show)]
    struct TubStr(uint, String, f32);

    the_same(TubStr(5, "hello".to_string(), 3.2));
}

#[test]
fn option() {
    the_same(Some(5u));
    the_same(Some("foo bar".to_string()));
    the_same(None::<uint>);
}

#[test]
fn enm() {
    #[deriving(Encodable, Decodable, PartialEq, Show)]
    enum TestEnum {
        NoArg,
        OneArg(uint),
        AnotherNoArg
    }
    the_same(NoArg);
    the_same(OneArg(4));
    the_same(AnotherNoArg);
}

#[test]
fn struct_enum() {
    #[deriving(Encodable, Decodable, PartialEq, Show)]
    enum TestEnum {
        NoArg,
        OneArg(uint),
        AnotherNoArg,
        StructLike{x: uint, y: f32}
    }
    the_same(NoArg);
    the_same(OneArg(4));
    the_same(AnotherNoArg);
    the_same(StructLike{x: 4, y: 3.14159});
    the_same(vec![NoArg, OneArg(5), AnotherNoArg, StructLike{x: 4, y:1.4}]);
}

#[test]
fn many() {
    let v: Vec<u8> = vec![];
    the_same(v);
    the_same(vec![1u]);
    the_same(vec![1u,2,3,4,5,6]);
}

#[test]
fn map(){
    let mut m = HashMap::new();
    m.insert(4u, "foo".to_string());
    m.insert(0u, "bar".to_string());
    the_same(m);
}

#[test]
fn boole(){
    the_same(true);
    the_same(false);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

#[macro_use]
extern crate lazy_static;

extern crate regex;

use std::io::prelude::*;
use std::fs::File;
use regex::Regex;

type Register = usize;

#[derive(Debug, Clone, Copy)]
enum Value {
    Reg(Register),
    Lit(i64),
}

#[derive(Debug, Clone, Copy)]
enum Instruction {
    Cpy(Value, Register),
    Inc(Register),
    Dec(Register),
    Jnz(Value, isize),
}

impl std::str::FromStr for Instruction {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Instruction::*;
        lazy_static! {
            static ref CPY_RE: Regex =
                Regex::new(r"cpy (?P<val>[a-d]|\d+) (?P<reg>[a-d])").unwrap();
            static ref INC_RE: Regex =
                Regex::new(r"inc (?P<reg>[a-d])").unwrap();
            static ref DEC_RE: Regex =
                Regex::new(r"dec (?P<reg>[a-d])").unwrap();
            static ref JNZ_RE: Regex =
                Regex::new(r"jnz (?P<val>[a-d]|\d+) (?P<shift>-?\d+)").unwrap();
        }
        fn read_reg(s: &str) -> Register {
            (s.as_bytes()[0] - b'a') as usize
        }
        fn read_val(s: &str) -> Value {
            if let Ok(lit) = s.parse() {
                Value::Lit(lit)
            } else {
                Value::Reg(read_reg(s))
            }
        }
        if let Some(cap) = CPY_RE.captures(s) {
            let val = read_val(&cap["val"]);
            let reg = read_reg(&cap["reg"]);
            Ok(Cpy(val, reg))
        } else if let Some(cap) = INC_RE.captures(s) {
            let reg = read_reg(&cap["reg"]);
            Ok(Inc(reg))
        } else if let Some(cap) = DEC_RE.captures(s) {
            let reg = read_reg(&cap["reg"]);
            Ok(Dec(reg))
        } else if let Some(cap) = JNZ_RE.captures(s) {
            let val = read_val(&cap["val"]);
            let shift = cap["shift"].parse().unwrap();
            Ok(Jnz(val, shift))
        } else {
            Err(format!("Invalid instruction: {}", s))
        }
    }
}

fn compute(tape: &[Instruction]) -> [i64; 4] {
    use Instruction::*;
    use Value::*;
    let mut registers = [0i64; 4];
    let mut ip = 0; // instruction pointer
    while ip < tape.len() {
        match tape[ip] {
            Cpy(Reg(src), dst) => registers[dst] = registers[src],
            Cpy(Lit(val), dst) => registers[dst] = val,
            Inc(reg) => registers[reg] += 1,
            Dec(reg) => registers[reg] -= 1,
            Jnz(val, shift) => {
                let cmp = match val {
                    Reg(reg) => registers[reg],
                    Lit(lit) => lit,
                };
                if cmp != 0 {
                    if shift < 0 {
                        ip -= (-shift) as usize;
                    } else {
                        ip += shift as usize;
                    }
                    continue;
                }
            }
        }
        ip += 1;
    }
    registers
}

fn parse_args() -> std::io::Result<String> {
    let matches = clap::App::new("Day 12")
        .author("Devon Hollowood")
        .arg(clap::Arg::with_name("instructions")
            .index(1)
            .short("f")
            .long("instructions")
            .help("file containing instructions to compute. Reads from stdin otherwise")
            .takes_value(true))
        .get_matches();
    let source = matches.value_of_os("instructions");
    let mut contents = String::new();
    match source {
        Some(filename) => {
            let mut input = File::open(filename)?;
            input.read_to_string(&mut contents)?;
        }
        None => {
            let mut input = std::io::stdin();
            input.read_to_string(&mut contents)?;
        }
    }
    Ok(contents)
}

fn main() {
    let input = parse_args().unwrap_or_else(|err| panic!("Error reading args: {}", err));
    let instructions: Vec<_> = input.lines()
        .map(|line| line.trim().parse())
        .collect::<Result<_, _>>()
        .unwrap_or_else(|err| panic!("Error parsing instructions: {}", err));
    let final_state = compute(&instructions);
    println!("part 1 final state: {:?}", final_state);
}
<commit_msg>Day 12 part 2<commit_after>#[macro_use]
extern crate clap;

#[macro_use]
extern crate lazy_static;

extern crate regex;

use std::io::prelude::*;
use std::fs::File;
use regex::Regex;

type Register = usize;

#[derive(Debug, Clone, Copy)]
enum Value {
    Reg(Register),
    Lit(i64),
}

#[derive(Debug, Clone, Copy)]
enum Instruction {
    Cpy(Value, Register),
    Inc(Register),
    Dec(Register),
    Jnz(Value, isize),
}

impl std::str::FromStr for Instruction {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Instruction::*;
        lazy_static! {
            static ref CPY_RE: Regex =
                Regex::new(r"cpy (?P<val>[a-d]|\d+) (?P<reg>[a-d])").unwrap();
            static ref INC_RE: Regex =
                Regex::new(r"inc (?P<reg>[a-d])").unwrap();
            static ref DEC_RE: Regex =
                Regex::new(r"dec (?P<reg>[a-d])").unwrap();
            static ref JNZ_RE: Regex =
                Regex::new(r"jnz (?P<val>[a-d]|\d+) (?P<shift>-?\d+)").unwrap();
        }
        fn read_reg(s: &str) -> Register {
            (s.as_bytes()[0] - b'a') as usize
        }
        fn read_val(s: &str) -> Value {
            if let Ok(lit) = s.parse() {
                Value::Lit(lit)
            } else {
                Value::Reg(read_reg(s))
            }
        }
        if let Some(cap) = CPY_RE.captures(s) {
            let val = read_val(&cap["val"]);
            let reg = read_reg(&cap["reg"]);
            Ok(Cpy(val, reg))
        } else if let Some(cap) = INC_RE.captures(s) {
            let reg = read_reg(&cap["reg"]);
            Ok(Inc(reg))
        } else if let Some(cap) = DEC_RE.captures(s) {
            let reg = read_reg(&cap["reg"]);
            Ok(Dec(reg))
        } else if let Some(cap) = JNZ_RE.captures(s) {
            let val = read_val(&cap["val"]);
            let shift = cap["shift"].parse().unwrap();
            Ok(Jnz(val, shift))
        } else {
            Err(format!("Invalid instruction: {}", s))
        }
    }
}

fn compute(tape: &[Instruction]) -> [i64; 4] {
    use Instruction::*;
    use Value::*;
    let mut registers = [0i64; 4];
    let mut ip = 0; // instruction pointer
    while ip < tape.len() {
        match tape[ip] {
            Cpy(Reg(src), dst) => registers[dst] = registers[src],
            Cpy(Lit(val), dst) => registers[dst] = val,
            Inc(reg) => registers[reg] += 1,
            Dec(reg) => registers[reg] -= 1,
            Jnz(val, shift) => {
                let cmp = match val {
                    Reg(reg) => registers[reg],
                    Lit(lit) => lit,
                };
                if cmp != 0 {
                    if shift < 0 {
                        ip -= (-shift) as usize;
                    } else {
                        ip += shift as usize;
                    }
                    continue;
                }
            }
        }
        ip += 1;
    }
    registers
}

fn parse_args() -> std::io::Result<String> {
    let matches = clap::App::new("Day 12")
        .author("Devon Hollowood")
        .arg(clap::Arg::with_name("instructions")
            .index(1)
            .short("f")
            .long("instructions")
            .help("file containing instructions to compute. Reads from stdin otherwise")
            .takes_value(true))
        .get_matches();
    let source = matches.value_of_os("instructions");
    let mut contents = String::new();
    match source {
        Some(filename) => {
            let mut input = File::open(filename)?;
            input.read_to_string(&mut contents)?;
        }
        None => {
            let mut input = std::io::stdin();
            input.read_to_string(&mut contents)?;
        }
    }
    Ok(contents)
}

fn main() {
    let input = parse_args().unwrap_or_else(|err| panic!("Error reading args: {}", err));
    let mut instructions: Vec<_> = input.lines()
        .map(|line| line.trim().parse())
        .collect::<Result<_, _>>()
        .unwrap_or_else(|err| panic!("Error parsing instructions: {}", err));
    let final_state_1 = compute(&instructions);
    println!("part 1 final state: {:?}", final_state_1);
    instructions.insert(0, Instruction::Cpy(Value::Lit(1), 2));
    let final_state_2 = compute(&instructions);
    println!("part 2 final state: {:?}", final_state_2);
}
<|endoftext|>