<commit_before>#![allow(trivial_casts)]
#![cfg_attr(test, deny(warnings))]

extern crate conduit;
extern crate conduit_mime_types as mime;
extern crate time;
extern crate filetime;
#[cfg(test)] extern crate tempdir;

use std::collections::HashMap;
use std::error::Error;
use std::io;
use std::path::{PathBuf, Path};
use std::fs::File;
use conduit::{Request, Response, Handler};
use filetime::FileTime;

pub struct Static {
    path: PathBuf,
    types: mime::Types
}

impl Static {
    pub fn new<P: AsRef<Path>>(path: P) -> Static {
        Static {
            path: path.as_ref().to_path_buf(),
            types: mime::Types::new()
                .ok().expect("Couldn't load mime-types")
        }
    }
}

impl Handler for Static {
    #[allow(deprecated)]
    fn call(&self, request: &mut Request) -> Result<Response, Box<Error+Send>> {
        let request_path = &request.path()[1..];
        if request_path.contains("..") { return Ok(not_found()) }

        let path = self.path.join(request_path);
        let mime = self.types.mime_for_path(&path);
        let file = match File::open(&path) {
            Ok(f) => f,
            Err(..) => return Ok(not_found()),
        };
        let data = try!(file.metadata().map_err(|e| Box::new(e) as Box<Error+Send>));
        if data.is_dir() {
            return Ok(not_found())
        }
        let mtime = FileTime::from_last_modification_time(&data);
        let ts = time::Timespec {
            sec: mtime.seconds_relative_to_1970() as i64,
            nsec: mtime.nanoseconds() as i32,
        };
        let tm = time::at(ts).to_utc();

        let mut headers = HashMap::new();
        headers.insert("Content-Type".to_string(), vec![mime.to_string()]);
        headers.insert("Content-Length".to_string(),
                       vec![data.len().to_string()]);
        headers.insert("Last-Modified".to_string(),
                       vec![tm.strftime("%a, %d %b %Y %T GMT").unwrap()
                              .to_string()]);

        Ok(Response {
            status: (200, "OK"),
            headers: headers,
            body: Box::new(file),
        })
    }
}

fn not_found() -> Response {
    let mut headers = HashMap::new();
    headers.insert("Content-Length".to_string(), vec!["0".to_string()]);
    headers.insert("Content-Type".to_string(), vec!["text/plain".to_string()]);
    Response {
        status: (404, "Not Found"),
        headers: headers,
        body: Box::new(io::empty()),
    }
}

#[cfg(test)]
mod tests {
    extern crate conduit_test as test;

    use std::fs::{self, File};
    use std::io::prelude::*;
    use tempdir::TempDir;

    use conduit::{Handler, Method};
    use Static;

    #[test]
    fn test_static() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();
        let handler = Static::new(root.clone());
        File::create(&root.join("Cargo.toml")).unwrap()
             .write_all(b"[package]").unwrap();
        let mut req = test::MockRequest::new(Method::Get, "/Cargo.toml");
        let mut res = handler.call(&mut req).ok().expect("No response");
        let mut body = String::new();
        res.body.read_to_string(&mut body).unwrap();
        assert_eq!(body, "[package]");
        assert_eq!(res.headers.get("Content-Type"),
                   Some(&vec!("text/plain".to_string())));
        assert_eq!(res.headers.get("Content-Length"),
                   Some(&vec!["9".to_string()]));
    }

    #[test]
    fn test_mime_types() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();
        fs::create_dir(&root.join("src")).unwrap();
        File::create(&root.join("src/fixture.css")).unwrap();

        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(Method::Get, "/src/fixture.css");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.headers.get("Content-Type"),
                   Some(&vec!("text/css".to_string())));
        assert_eq!(res.headers.get("Content-Length"),
                   Some(&vec!["0".to_string()]));
    }

    #[test]
    fn test_missing() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();

        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(Method::Get, "/nope");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.status.0, 404);
    }

    #[test]
    fn test_dir() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();

        fs::create_dir(&root.join("foo")).unwrap();

        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(Method::Get, "/foo");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.status.0, 404);
    }

    #[test]
    fn last_modified() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();
        File::create(&root.join("test")).unwrap();
        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(Method::Get, "/test");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.status.0, 200);
        assert!(res.headers.get("Last-Modified").is_some());
    }
}
<commit_msg>Fix tests<commit_after>#![allow(trivial_casts)]
#![cfg_attr(test, deny(warnings))]

extern crate conduit;
extern crate conduit_mime_types as mime;
extern crate time;
extern crate filetime;
#[cfg(test)] extern crate tempdir;

use std::collections::HashMap;
use std::error::Error;
use std::io;
use std::path::{PathBuf, Path};
use std::fs::File;
use conduit::{Request, Response, Handler};
use filetime::FileTime;

pub struct Static {
    path: PathBuf,
    types: mime::Types
}

impl Static {
    pub fn new<P: AsRef<Path>>(path: P) -> Static {
        Static {
            path: path.as_ref().to_path_buf(),
            types: mime::Types::new()
                .ok().expect("Couldn't load mime-types")
        }
    }
}

impl Handler for Static {
    #[allow(deprecated)]
    fn call(&self, request: &mut Request) -> Result<Response, Box<Error+Send>> {
        let request_path = &request.path()[1..];
        if request_path.contains("..") { return Ok(not_found()) }

        let path = self.path.join(request_path);
        let mime = self.types.mime_for_path(&path);
        let file = match File::open(&path) {
            Ok(f) => f,
            Err(..) => return Ok(not_found()),
        };
        let data = try!(file.metadata().map_err(|e| Box::new(e) as Box<Error+Send>));
        if data.is_dir() {
            return Ok(not_found())
        }
        let mtime = FileTime::from_last_modification_time(&data);
        let ts = time::Timespec {
            sec: mtime.seconds_relative_to_1970() as i64,
            nsec: mtime.nanoseconds() as i32,
        };
        let tm = time::at(ts).to_utc();

        let mut headers = HashMap::new();
        headers.insert("Content-Type".to_string(), vec![mime.to_string()]);
        headers.insert("Content-Length".to_string(),
                       vec![data.len().to_string()]);
        headers.insert("Last-Modified".to_string(),
                       vec![tm.strftime("%a, %d %b %Y %T GMT").unwrap()
                              .to_string()]);

        Ok(Response {
            status: (200, "OK"),
            headers: headers,
            body: Box::new(file),
        })
    }
}

fn not_found() -> Response {
    let mut headers = HashMap::new();
    headers.insert("Content-Length".to_string(), vec!["0".to_string()]);
    headers.insert("Content-Type".to_string(), vec!["text/plain".to_string()]);
    Response {
        status: (404, "Not Found"),
        headers: headers,
        body: Box::new(io::empty()),
    }
}

#[cfg(test)]
mod tests {
    extern crate conduit_test as test;

    use std::fs::{self, File};
    use std::io::prelude::*;
    use tempdir::TempDir;

    use conduit::{Handler, Method};
    use Static;

    #[test]
    fn test_static() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();
        let handler = Static::new(root.clone());
        File::create(&root.join("Cargo.toml")).unwrap()
             .write_all(b"[package]").unwrap();
        let mut req = test::MockRequest::new(Method::Get, "/Cargo.toml");
        let mut res = handler.call(&mut req).ok().expect("No response");
        let mut body = Vec::new();
        res.body.write_body(&mut body).unwrap();
        assert_eq!(body, b"[package]");
        assert_eq!(res.headers.get("Content-Type"),
                   Some(&vec!("text/plain".to_string())));
        assert_eq!(res.headers.get("Content-Length"),
                   Some(&vec!["9".to_string()]));
    }

    #[test]
    fn test_mime_types() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();
        fs::create_dir(&root.join("src")).unwrap();
        File::create(&root.join("src/fixture.css")).unwrap();

        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(Method::Get, "/src/fixture.css");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.headers.get("Content-Type"),
                   Some(&vec!("text/css".to_string())));
        assert_eq!(res.headers.get("Content-Length"),
                   Some(&vec!["0".to_string()]));
    }

    #[test]
    fn test_missing() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();

        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(Method::Get, "/nope");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.status.0, 404);
    }

    #[test]
    fn test_dir() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();

        fs::create_dir(&root.join("foo")).unwrap();

        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(Method::Get, "/foo");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.status.0, 404);
    }

    #[test]
    fn last_modified() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();
        File::create(&root.join("test")).unwrap();
        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(Method::Get, "/test");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.status.0, 200);
        assert!(res.headers.get("Last-Modified").is_some());
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 FaultyRAM
//
// 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.

//! A helper library for Google Code Jam solutions.
//!
//! In the Google Code Jam, solving a problem typically requires the following steps:
//!
//! 1. Open an input file containing a series of test cases.
//! 2. Open an output file where solutions will be written.
//! 2. Read the first line from the input file, which consists solely of an unsigned integer
//!    specifying the number of test cases in the input file.
//! 3. For each test case, perform the following steps:
//!    1. Obtain the corresponding test data by reading one or more lines from the input file (it
//!       may be a fixed number, or specified within the test data itself).
//!    2. Perform some logic using the test data, in order to obtain a set of results.
//!    3. Write the string `"Case #N:"` (where `N` is the number of completed test cases) followed
//!       by the results obtained in the previous step, formatted as the problem requires.
//!
//! Writing code to handle all of the above is tedious and time-consuming, in a situation where
//! every microsecond counts. `gcj-helper` is designed to handle the boilerplate, so you can focus
//! on writing solutions instead.
//!
//! # The `TestEngine` type
//!
//! To execute test cases, you need to create a `TestEngine` and call `TestEngine::run()`.
//! `TestEngine::run()` accepts two closures:
//!
//! 1. A `parser` that reads from an input file and returns the data for one test case.
//! 2. A `solver` that performs logic on the data for one test case and returns a result, encoded
//!    as a `Display` type.
//!
//! This two-step process to writing solutions is useful for two reasons:
//!
//! * It seperates parsing from the solution itself, making your code easier to read;
//! * It enables test case parallelisation if the `parallel` feature is enabled, improving
//!   run-time performance at the cost of increased build times.
//!
//! # The `InputReader` type
//!
//! `gcj-helper` provides parsers with access to an `InputReader`, a simple wrapper around a
//! `std::fs::File`. `InputReader` implements `io::BufRead` and also provides a convenience
//! method, `read_next_line()`, which reads a line of text from an input file and truncates the
//! end-of-line marker if one is present.
//!
//! # Formatting test results
//!
//! Before each test case, the `TestEngine` writes the string `"Case #N:"`, where `N` is the
//! current test case. This does not prepend or append any whitespace. This means that if the
//! colon must be followed by a space, your result should begin with one, and that the result must
//! end with a newline.

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(feature = "clippy", forbid(clippy))]
#![cfg_attr(feature = "clippy", forbid(clippy_internal))]
#![cfg_attr(feature = "clippy", forbid(clippy_pedantic))]
#![forbid(warnings)]
#![forbid(box_pointers)]
#![forbid(fat_ptr_transmutes)]
#![forbid(missing_copy_implementations)]
#![forbid(missing_debug_implementations)]
#![forbid(missing_docs)]
#![forbid(trivial_casts)]
#![forbid(trivial_numeric_casts)]
#![forbid(unsafe_code)]
#![forbid(unused_extern_crates)]
#![forbid(unused_import_braces)]
#![deny(unused_qualifications)]
#![forbid(unused_results)]
#![forbid(variant_size_differences)]

#[cfg(feature = "parallel")]
extern crate rayon;

#[cfg(feature = "parallel")]
use rayon::prelude::*;
use std::{env, io};
use std::ffi::OsString;
use std::fmt::{Arguments, Display};
use std::fs::{File, OpenOptions};
use std::io::{BufRead, BufReader, LineWriter, Read, Write};
use std::path::Path;

/// Facilitates the execution of problem solving code.
#[derive(Debug)]
pub struct TestEngine<I: AsRef<Path>, O: AsRef<Path>> {
    /// A path to an input file.
    input_file_path: I,
    /// A path to an output file.
    output_file_path: O,
}

/// Supports reading from an input file.
#[derive(Debug)]
pub struct InputReader(BufReader<File>);

/// Supports writing to an output file.
struct OutputWriter(LineWriter<File>);

impl<I: AsRef<Path>, O: AsRef<Path>> TestEngine<I, O> {
    /// Creates a new test engine using the specified input and output file paths.
    ///
    /// Calling this method is cheap; no files are opened until `TestEngine::run()` is called.
    pub fn new(input_file_path: I, output_file_path: O) -> TestEngine<I, O> {
        TestEngine {
            input_file_path: input_file_path,
            output_file_path: output_file_path,
        }
    }

    #[cfg(not(feature = "parallel"))]
    /// Consumes the test engine, executing a parser and solver once per test case.
    ///
    /// # Panics
    ///
    /// This method panics in the event of an I/O error.
    pub fn run<
        D: Sized + Send + Sync,
        R: Display + Sized + Send,
        P: Fn(&mut InputReader) -> D,
        S: Fn(&D) -> R + Sync
    >
        (
        self,
        p: P,
        s: S,
    ) {
        let mut reader = InputReader::new(self.input_file_path);
        let mut writer = OutputWriter::new(self.output_file_path);
        let mut current_case: usize = 1;
        let case_count = reader.get_case_count();
        while current_case <= case_count {
            writer.write_test_result(current_case, (s)(&(p)(&mut reader)));
            current_case += 1;
        }
    }

    /// Consumes the test engine, executing a parser and solver once per test case.
    ///
    /// # Panics
    ///
    /// This method panics in the event of an I/O error.
    #[cfg(feature = "parallel")]
    pub fn run<
        D: Sized + Send + Sync,
        R: Display + Sized + Send,
        P: Fn(&mut InputReader) -> D,
        S: Fn(&D) -> R + Sync
    >
        (
        self,
        p: P,
        s: S,
    ) {
        let mut reader = InputReader::new(self.input_file_path);
        let mut writer = OutputWriter::new(self.output_file_path);
        let case_count = reader.get_case_count();
        let mut data = Vec::with_capacity(0);
        data.reserve_exact(case_count);
        for _ in 0..case_count {
            data.push((p(&mut reader), None));
        }
        data.par_iter_mut().for_each(|d| d.1 = Some(s(&d.0)));
        for (i, &(_, ref r)) in data.iter().enumerate() {
            writer.write_test_result(
                i + 1,
                match *r {
                    Some(ref x) => x,
                    None => unreachable!(),
                },
            );
        }
    }
}

impl TestEngine<OsString, OsString> {
    /// Creates a new test engine using input and output file paths obtained from command line
    /// arguments.
    ///
    /// Calling this method is cheap; no files are opened until `TestEngine::run()` is called.
    ///
    /// # Panics
    ///
    /// This method panics if either the input file path or output file path is missing.
    pub fn from_args() -> TestEngine<OsString, OsString> {
        let mut args = env::args_os();
        let input_file_path = args.nth(1).expect("input file path not specified");
        let output_file_path = args.next().expect("output file path not specified");
        Self::new(input_file_path, output_file_path)
    }
}

impl Default for TestEngine<OsString, OsString> {
    fn default() -> TestEngine<OsString, OsString> {
        Self::from_args()
    }
}

impl InputReader {
    /// Reads a line of text from the input file, consuming the end-of-line marker if one is
    /// present.
    pub fn read_next_line(&mut self) -> String {
        let mut line = String::with_capacity(0);
        let _ = self.read_line(&mut line)
            .expect("could not read from input file");
        let line_len = line.lines()
            .next()
            .map(|l| l.len())
            .expect("could not obtain line length");
        line.truncate(line_len);
        line
    }

    /// Creates a new input reader over the given input file.
    fn new<P: AsRef<Path>>(path: P) -> InputReader {
        InputReader(
            BufReader::new(
                OpenOptions::new()
                    .read(true)
                    .open(path)
                    .expect("could not open input file for reading"),
            ),
        )
    }

    /// Reads the number of test cases from the input file.
    fn get_case_count(&mut self) -> usize {
        usize::from_str_radix(&self.read_next_line(), 10).expect("could not parse test case count")
    }
}

impl Read for InputReader {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }

    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        self.0.read_to_end(buf)
    }

    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
        self.0.read_to_string(buf)
    }

    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
        self.0.read_exact(buf)
    }
}

impl BufRead for InputReader {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        self.0.fill_buf()
    }

    fn consume(&mut self, amt: usize) {
        self.0.consume(amt)
    }

    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
        self.0.read_until(byte, buf)
    }

    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
        self.0.read_line(buf)
    }
}

impl OutputWriter {
    /// Creates a new output writer over the given output file.
    fn new<P: AsRef<Path>>(path: P) -> OutputWriter {
        OutputWriter(
            LineWriter::new(
                OpenOptions::new()
                    .write(true)
                    .truncate(true)
                    .create(true)
                    .open(path)
                    .expect("could not open output file for writing"),
            ),
        )
    }

    /// Writes a test result to the output file.
    fn write_test_result<R: Display>(&mut self, case: usize, result: R) {
        let case_prefix = "Case #";
        let case_number = case.to_string();
        let case_colon = ":";
        let r = result.to_string();
        let mut output = String::with_capacity(0);
        output.reserve_exact(case_prefix.len() + case_number.len() + case_colon.len() + r.len(),);
        output.push_str(case_prefix);
        output.push_str(&case_number);
        output.push_str(case_colon);
        output.push_str(&r);
        self.write_all(output.as_bytes())
            .expect("could not write test result to output file");
    }
}

impl Write for OutputWriter {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }

    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        self.0.write_all(buf)
    }

    fn write_fmt(&mut self, fmt: Arguments) -> io::Result<()> {
        self.0.write_fmt(fmt)
    }
}
<commit_msg>Fixed typos<commit_after>// Copyright (c) 2017 FaultyRAM
//
// 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.

//! A helper library for Google Code Jam solutions.
//!
//! In the Google Code Jam, solving a problem typically requires the following steps:
//!
//! 1. Open an input file containing a series of test cases.
//! 2. Open an output file where solutions will be written.
//! 2. Read the first line from the input file, which consists solely of an unsigned integer
//!    specifying the number of test cases in the input file.
//! 3. For each test case, perform the following steps:
//!    1. Obtain the corresponding test data by reading one or more lines from the input file (it
//!       may be a fixed number, or specified within the test data itself).
//!    2. Perform some logic using the test data, in order to obtain a set of results.
//!    3. Write the string `"Case #N:"` (where `N` is the number of completed test cases) followed
//!       by the results obtained in the previous step, formatted as the problem requires.
//!
//! Writing code to handle all of the above is tedious and time-consuming, in a situation where
//! every microsecond counts. `gcj-helper` is designed to handle the boilerplate, so you can focus
//! on writing solutions instead.
//!
//! # The `TestEngine` type
//!
//! To execute test cases, you need to create a `TestEngine` and call `TestEngine::run()`.
//! `TestEngine::run()` accepts two closures:
//!
//! 1. A *parser* that reads from an input file and returns the data for one test case.
//! 2. A *solver* that performs logic on the data for one test case and returns a result, encoded
//!    as a `Display` type.
//!
//! This two-step process to writing solutions is useful for two reasons:
//!
//! * It seperates parsing from the solution itself, making your code easier to read;
//! * It enables test case parallelisation if the `parallel` feature is enabled, improving
//!   run-time performance at the cost of increased build times.
//!
//! # The `InputReader` type
//!
//! `gcj-helper` provides parsers with access to an `InputReader`, a simple wrapper around a
//! `std::fs::File`. `InputReader` implements `io::BufRead` and also provides a convenience
//! method, `read_next_line()`, which reads a line of text from an input file and truncates the
//! end-of-line marker if one is present.
//!
//! # Formatting test results
//!
//! Before each test case, the `TestEngine` writes the string `"Case #N:"`, where `N` is the
//! current test case. This does not prepend or append any whitespace. This means that if the
//! colon must be followed by a space, your result should begin with one, and that the result must
//! end with a newline.

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(feature = "clippy", forbid(clippy))]
#![cfg_attr(feature = "clippy", forbid(clippy_internal))]
#![cfg_attr(feature = "clippy", forbid(clippy_pedantic))]
#![forbid(warnings)]
#![forbid(box_pointers)]
#![forbid(fat_ptr_transmutes)]
#![forbid(missing_copy_implementations)]
#![forbid(missing_debug_implementations)]
#![forbid(missing_docs)]
#![forbid(trivial_casts)]
#![forbid(trivial_numeric_casts)]
#![forbid(unsafe_code)]
#![forbid(unused_extern_crates)]
#![forbid(unused_import_braces)]
#![deny(unused_qualifications)]
#![forbid(unused_results)]
#![forbid(variant_size_differences)]

#[cfg(feature = "parallel")]
extern crate rayon;

#[cfg(feature = "parallel")]
use rayon::prelude::*;
use std::{env, io};
use std::ffi::OsString;
use std::fmt::{Arguments, Display};
use std::fs::{File, OpenOptions};
use std::io::{BufRead, BufReader, LineWriter, Read, Write};
use std::path::Path;

/// Facilitates the execution of problem solving code.
#[derive(Debug)]
pub struct TestEngine<I: AsRef<Path>, O: AsRef<Path>> {
    /// A path to an input file.
    input_file_path: I,
    /// A path to an output file.
    output_file_path: O,
}

/// Supports reading from an input file.
#[derive(Debug)]
pub struct InputReader(BufReader<File>);

/// Supports writing to an output file.
struct OutputWriter(LineWriter<File>);

impl<I: AsRef<Path>, O: AsRef<Path>> TestEngine<I, O> {
    /// Creates a new test engine using the specified input and output file paths.
    ///
    /// Calling this method is cheap; no files are opened until `TestEngine::run()` is called.
    pub fn new(input_file_path: I, output_file_path: O) -> TestEngine<I, O> {
        TestEngine {
            input_file_path: input_file_path,
            output_file_path: output_file_path,
        }
    }

    #[cfg(not(feature = "parallel"))]
    /// Consumes the test engine, executing a parser and solver once per test case.
    ///
    /// # Panics
    ///
    /// This method panics in the event of an I/O error.
    pub fn run<
        D: Sized + Send + Sync,
        R: Display + Sized + Send,
        P: Fn(&mut InputReader) -> D,
        S: Fn(&D) -> R + Sync
    >
        (
        self,
        p: P,
        s: S,
    ) {
        let mut reader = InputReader::new(self.input_file_path);
        let mut writer = OutputWriter::new(self.output_file_path);
        let mut current_case: usize = 1;
        let case_count = reader.get_case_count();
        while current_case <= case_count {
            writer.write_test_result(current_case, (s)(&(p)(&mut reader)));
            current_case += 1;
        }
    }

    /// Consumes the test engine, executing a parser and solver once per test case.
    ///
    /// # Panics
    ///
    /// This method panics in the event of an I/O error.
    #[cfg(feature = "parallel")]
    pub fn run<
        D: Sized + Send + Sync,
        R: Display + Sized + Send,
        P: Fn(&mut InputReader) -> D,
        S: Fn(&D) -> R + Sync
    >
        (
        self,
        p: P,
        s: S,
    ) {
        let mut reader = InputReader::new(self.input_file_path);
        let mut writer = OutputWriter::new(self.output_file_path);
        let case_count = reader.get_case_count();
        let mut data = Vec::with_capacity(0);
        data.reserve_exact(case_count);
        for _ in 0..case_count {
            data.push((p(&mut reader), None));
        }
        data.par_iter_mut().for_each(|d| d.1 = Some(s(&d.0)));
        for (i, &(_, ref r)) in data.iter().enumerate() {
            writer.write_test_result(
                i + 1,
                match *r {
                    Some(ref x) => x,
                    None => unreachable!(),
                },
            );
        }
    }
}

impl TestEngine<OsString, OsString> {
    /// Creates a new test engine using input and output file paths obtained from command line
    /// arguments.
    ///
    /// Calling this method is cheap; no files are opened until `TestEngine::run()` is called.
    ///
    /// # Panics
    ///
    /// This method panics if either the input file path or output file path is missing.
    pub fn from_args() -> TestEngine<OsString, OsString> {
        let mut args = env::args_os();
        let input_file_path = args.nth(1).expect("input file path not specified");
        let output_file_path = args.next().expect("output file path not specified");
        Self::new(input_file_path, output_file_path)
    }
}

impl Default for TestEngine<OsString, OsString> {
    fn default() -> TestEngine<OsString, OsString> {
        Self::from_args()
    }
}

impl InputReader {
    /// Reads a line of text from the input file, consuming the end-of-line marker if one is
    /// present.
    pub fn read_next_line(&mut self) -> String {
        let mut line = String::with_capacity(0);
        let _ = self.read_line(&mut line)
            .expect("could not read from input file");
        let line_len = line.lines()
            .next()
            .map(|l| l.len())
            .expect("could not obtain line length");
        line.truncate(line_len);
        line
    }

    /// Creates a new input reader over the given input file.
    fn new<P: AsRef<Path>>(path: P) -> InputReader {
        InputReader(
            BufReader::new(
                OpenOptions::new()
                    .read(true)
                    .open(path)
                    .expect("could not open input file for reading"),
            ),
        )
    }

    /// Reads the number of test cases from the input file.
    fn get_case_count(&mut self) -> usize {
        usize::from_str_radix(&self.read_next_line(), 10).expect("could not parse test case count")
    }
}

impl Read for InputReader {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }

    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        self.0.read_to_end(buf)
    }

    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
        self.0.read_to_string(buf)
    }

    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
        self.0.read_exact(buf)
    }
}

impl BufRead for InputReader {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        self.0.fill_buf()
    }

    fn consume(&mut self, amt: usize) {
        self.0.consume(amt)
    }

    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
        self.0.read_until(byte, buf)
    }

    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
        self.0.read_line(buf)
    }
}

impl OutputWriter {
    /// Creates a new output writer over the given output file.
    fn new<P: AsRef<Path>>(path: P) -> OutputWriter {
        OutputWriter(
            LineWriter::new(
                OpenOptions::new()
                    .write(true)
                    .truncate(true)
                    .create(true)
                    .open(path)
                    .expect("could not open output file for writing"),
            ),
        )
    }

    /// Writes a test result to the output file.
    fn write_test_result<R: Display>(&mut self, case: usize, result: R) {
        let case_prefix = "Case #";
        let case_number = case.to_string();
        let case_colon = ":";
        let r = result.to_string();
        let mut output = String::with_capacity(0);
        output.reserve_exact(case_prefix.len() + case_number.len() + case_colon.len() + r.len(),);
        output.push_str(case_prefix);
        output.push_str(&case_number);
        output.push_str(case_colon);
        output.push_str(&r);
        self.write_all(output.as_bytes())
            .expect("could not write test result to output file");
    }
}

impl Write for OutputWriter {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }

    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        self.0.write_all(buf)
    }

    fn write_fmt(&mut self, fmt: Arguments) -> io::Result<()> {
        self.0.write_fmt(fmt)
    }
}
<|endoftext|>


<commit_before>// Hound -- A WAV encoding library in Rust
// Copyright (C) 2015 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! Hound, a WAV encoding library.
//!
//! TODO: Add some introductory text here.
//!
//! The following example renders a 440 Hz sine wave, and stores it as as a
//! mono wav file with a sample rate of 44.1 kHz and 16 bits per sample.
//!
//! ```
//! #![feature(core)]
//!
//! use std::fs;
//! use std::f32::consts::PI;
//! use std::iter::IntoIterator;
//! use std::num;
//! use hound;
//!
//! let spec = hound::WavSpec {
//!     channels: 1,
//!     sample_rate: 44100,
//!     bits_per_sample: 16
//! };
//! // TODO: ensure that the type can be inferred.
//! let mut writer = hound::WavWriter::<fs::File>::create("sine.wav", spec);
//! let mut writer = writer.ok().unwrap();
//! for t in (0 .. 44100).into_iter().map(|x| x as f32 / 44100.0) {
//!     let sample = (t * 440.0 * 2.0 * PI).sin();
//!     let amplitude: i16 = num::Int::max_value();
//!     writer.write_sample((sample * amplitude as f32) as i16).ok().unwrap();
//! }
//! writer.finalize().ok().unwrap();
//! ```

#![warn(missing_docs)]
#![allow(dead_code)] // TODO: Remove for v0.1
#![feature(convert, io, unsafe_destructor)]

use std::fs;
use std::io;
use std::io::{Seek, Write};
use std::path;

/// Extends the functionality of `io::Write` with additional methods.
///
/// The methods may be used on any type that implements `io::Write`.
trait WriteExt: io::Write {
    /// Writes an unsigned 16-bit integer in little endian format.
    fn write_le_u16(&mut self, x: u16) -> io::Result<()>;

    /// Writes an unsigned 32-bit integer in little endian format.
    fn write_le_u32(&mut self, x: u32) -> io::Result<()>;
}

impl<W> WriteExt for W where W: io::Write {

    fn write_le_u16(&mut self, x: u16) -> io::Result<()> {
        let mut buf = [0u8; 2];
        buf[0] = (x & 0xff) as u8;
        buf[1] = (x >> 8) as u8;
        self.write_all(&buf)
    }

    fn write_le_u32(&mut self, x: u32) -> io::Result<()> {
        let mut buf = [0u8; 4];
        buf[0] = ((x >> 00) & 0xff) as u8;
        buf[1] = ((x >> 08) & 0xff) as u8;
        buf[2] = ((x >> 16) & 0xff) as u8;
        buf[3] = ((x >> 24) & 0xff) as u8;
        self.write_all(&buf)
    }
}

/// A type that can be used to represent audio samples.
pub trait Sample {
    /// Writes the audio sample to the WAVE data section.
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()>;
}

impl Sample for u16 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()> {
        writer.write_le_u16(self)
        // TODO: take bits into account
    }
}

impl Sample for i16 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()> {
        writer.write_le_u16(self as u16)
        // TODO: take bits into account
    }
}

/// Specifies properties of the audio data.
#[derive(Copy)]
pub struct WavSpec {
    /// The number of channels.
    pub channels: u16,

    /// The number of samples per second.
    ///
    /// A common value is 44100, this is 44.1 kHz which is used for CD audio.
    pub sample_rate: u32,

    /// The number of bits per sample.
    ///
    /// A common value is 16 bits per sample, which is used for CD audio.
    pub bits_per_sample: u32
}

/// A writer that accepts samples and writes the WAVE format.
///
/// TODO: add example.
///
/// After all samples have been written, the file must be finalized. This can
/// be done by calling `finalize`. If `finalize` is not called, the file will
/// be finalized upon drop. However, finalization involves IO that may fail,
/// and without calling `finalize`, such a failure cannot be observed.
pub struct WavWriter<W> where W: io::Write + io::Seek {
    /// Specifies properties of the audio data.
    spec: WavSpec,

    /// Whether the header has been written already.
    wrote_header: bool,

    /// The writer that will be written to.
    writer: io::BufWriter<W>,

    /// The number of bytes written to the data section.
    ///
    /// This is an `u32` because WAVE cannot accomodate more data.
    data_bytes_written: u32,

    /// Whether `finalize_internal` has been called.
    finalized: bool
}

impl<W> WavWriter<W> where W: io::Write + io::Seek {
    /// Creates a writer that writes the WAVE format to the underlying writer.
    ///
    /// The underlying writer is assumed to be at offset 0. `WavWriter` employs
    /// buffering internally to avoid too many `write` calls to the underlying
    /// writer.
    pub fn new(writer: W, spec: WavSpec) -> WavWriter<W> {
        WavWriter {
            spec: spec,
            wrote_header: false,
            writer: io::BufWriter::new(writer),
            data_bytes_written: 0,
            finalized: false
        }
    }

    /// Creates a writer that writes the WAVE format to a file.
    ///
    /// The file will be overwritten if it exists.
    pub fn create<P: AsRef<path::Path>>(filename: P, spec: WavSpec)
           -> io::Result<WavWriter<fs::File>> {
        let file = try!(fs::File::create(filename));
        Ok(WavWriter::new(file, spec))
    }

    /// Writes the RIFF WAVE header
    fn write_header(&mut self) -> io::Result<()> {
        let mut header = [0u8; 44];
        let spec = &self.spec;

        // Write the header in-memory first.
        {
            let mut buffer: io::Cursor<&mut [u8]> = io::Cursor::new(&mut header);
            try!(buffer.write_all("RIFF".as_bytes()));

            // Skip 4 bytes that will be filled with the file size afterwards.
            try!(buffer.seek(io::SeekFrom::Current(4)));

            try!(buffer.write_all("WAVE".as_bytes()));
            try!(buffer.write_all("fmt\0".as_bytes()));
            try!(buffer.write_le_u32(16)); // Size of the WAVE header
            try!(buffer.write_le_u16(1));  // PCM encoded audio
            try!(buffer.write_le_u16(spec.channels));
            try!(buffer.write_le_u32(spec.sample_rate));
            let bytes_per_sec = spec.sample_rate
                              * spec.bits_per_sample
                              * spec.channels as u32 / 8;
            try!(buffer.write_le_u32(bytes_per_sec));
            try!(buffer.write_le_u16(16)); // TODO: block align
            try!(buffer.write_le_u32(spec.bits_per_sample));

            // TODO: data section header
        }

        // Then write the entire header at once.
        try!(self.writer.write_all(&header));

        Ok(())
    }

    /// Writes a single sample for one channel.
    ///
    /// WAVE interleaves channel data, so the channel that this writes the
    /// sample to depends on previous writes.
    pub fn write_sample<S: Sample>(&mut self, sample: S) -> io::Result<()> {
        if !self.wrote_header {
            try!(self.write_header());
        }

        try!(sample.write(&mut self.writer, self.spec.bits_per_sample));
        self.data_bytes_written += self.spec.bits_per_sample / 8;
        Ok(())
    }

    /// Performs finalization. After calling this, the writer should be destructed.
    fn finalize_internal(&mut self) -> io::Result<()> {
        self.finalized = true;

        // Flush remaining samples via the BufWriter.
        try!(self.writer.flush());

        // Extract the underlying writer and rewind it to the start, to update
        // the header fields of which we now know the value.
        let mut writer = self.writer.get_mut();
        try!(writer.seek(io::SeekFrom::Start(0)));

        // TODO: update size fields
        Ok(())
    }

    /// Writes the parts of the WAVE format that require knowing all samples.
    ///
    /// This method must be called after all samples have been written. If it
    /// is not called, the destructor will finalize the file, but any IO errors
    /// that occur in the process cannot be observed in that manner.
    pub fn finalize(mut self) -> io::Result<()> {
        self.finalize_internal()
    }
}

#[unsafe_destructor] // TODO: this can hopefully be removed at the next nightly!
impl<W> Drop for WavWriter<W> where W: io::Write + io::Seek {
    fn drop(&mut self) {
        // `finalize_internal` must be called only once. If that is done via
        // `finalize`, then this method is a no-op. If the user did not
        // finalize explicitly, then we should do it now. This can fail, but
        // drop should not panic, so a failure is ignored silently here.
        if !self.finalized {
            let _r = self.finalize_internal();
        }
    }
}
<commit_msg>make destructor safe<commit_after>// Hound -- A WAV encoding library in Rust
// Copyright (C) 2015 Ruud van Asseldonk
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License only.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! Hound, a WAV encoding library.
//!
//! TODO: Add some introductory text here.
//!
//! The following example renders a 440 Hz sine wave, and stores it as as a
//! mono wav file with a sample rate of 44.1 kHz and 16 bits per sample.
//!
//! ```
//! #![feature(core)]
//!
//! use std::fs;
//! use std::f32::consts::PI;
//! use std::iter::IntoIterator;
//! use std::num;
//! use hound;
//!
//! let spec = hound::WavSpec {
//!     channels: 1,
//!     sample_rate: 44100,
//!     bits_per_sample: 16
//! };
//! // TODO: ensure that the type can be inferred.
//! let mut writer = hound::WavWriter::<fs::File>::create("sine.wav", spec);
//! let mut writer = writer.ok().unwrap();
//! for t in (0 .. 44100).into_iter().map(|x| x as f32 / 44100.0) {
//!     let sample = (t * 440.0 * 2.0 * PI).sin();
//!     let amplitude: i16 = num::Int::max_value();
//!     writer.write_sample((sample * amplitude as f32) as i16).ok().unwrap();
//! }
//! writer.finalize().ok().unwrap();
//! ```

#![warn(missing_docs)]
#![allow(dead_code)] // TODO: Remove for v0.1
#![feature(convert, io)]

use std::fs;
use std::io;
use std::io::{Seek, Write};
use std::path;

/// Extends the functionality of `io::Write` with additional methods.
///
/// The methods may be used on any type that implements `io::Write`.
trait WriteExt: io::Write {
    /// Writes an unsigned 16-bit integer in little endian format.
    fn write_le_u16(&mut self, x: u16) -> io::Result<()>;

    /// Writes an unsigned 32-bit integer in little endian format.
    fn write_le_u32(&mut self, x: u32) -> io::Result<()>;
}

impl<W> WriteExt for W where W: io::Write {

    fn write_le_u16(&mut self, x: u16) -> io::Result<()> {
        let mut buf = [0u8; 2];
        buf[0] = (x & 0xff) as u8;
        buf[1] = (x >> 8) as u8;
        self.write_all(&buf)
    }

    fn write_le_u32(&mut self, x: u32) -> io::Result<()> {
        let mut buf = [0u8; 4];
        buf[0] = ((x >> 00) & 0xff) as u8;
        buf[1] = ((x >> 08) & 0xff) as u8;
        buf[2] = ((x >> 16) & 0xff) as u8;
        buf[3] = ((x >> 24) & 0xff) as u8;
        self.write_all(&buf)
    }
}

/// A type that can be used to represent audio samples.
pub trait Sample {
    /// Writes the audio sample to the WAVE data section.
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()>;
}

impl Sample for u16 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()> {
        writer.write_le_u16(self)
        // TODO: take bits into account
    }
}

impl Sample for i16 {
    fn write<W: io::Write>(self, writer: &mut W, bits: u32) -> io::Result<()> {
        writer.write_le_u16(self as u16)
        // TODO: take bits into account
    }
}

/// Specifies properties of the audio data.
#[derive(Copy)]
pub struct WavSpec {
    /// The number of channels.
    pub channels: u16,

    /// The number of samples per second.
    ///
    /// A common value is 44100, this is 44.1 kHz which is used for CD audio.
    pub sample_rate: u32,

    /// The number of bits per sample.
    ///
    /// A common value is 16 bits per sample, which is used for CD audio.
    pub bits_per_sample: u32
}

/// A writer that accepts samples and writes the WAVE format.
///
/// TODO: add example.
///
/// After all samples have been written, the file must be finalized. This can
/// be done by calling `finalize`. If `finalize` is not called, the file will
/// be finalized upon drop. However, finalization involves IO that may fail,
/// and without calling `finalize`, such a failure cannot be observed.
pub struct WavWriter<W> where W: io::Write + io::Seek {
    /// Specifies properties of the audio data.
    spec: WavSpec,

    /// Whether the header has been written already.
    wrote_header: bool,

    /// The writer that will be written to.
    writer: io::BufWriter<W>,

    /// The number of bytes written to the data section.
    ///
    /// This is an `u32` because WAVE cannot accomodate more data.
    data_bytes_written: u32,

    /// Whether `finalize_internal` has been called.
    finalized: bool
}

impl<W> WavWriter<W> where W: io::Write + io::Seek {
    /// Creates a writer that writes the WAVE format to the underlying writer.
    ///
    /// The underlying writer is assumed to be at offset 0. `WavWriter` employs
    /// buffering internally to avoid too many `write` calls to the underlying
    /// writer.
    pub fn new(writer: W, spec: WavSpec) -> WavWriter<W> {
        WavWriter {
            spec: spec,
            wrote_header: false,
            writer: io::BufWriter::new(writer),
            data_bytes_written: 0,
            finalized: false
        }
    }

    /// Creates a writer that writes the WAVE format to a file.
    ///
    /// The file will be overwritten if it exists.
    pub fn create<P: AsRef<path::Path>>(filename: P, spec: WavSpec)
           -> io::Result<WavWriter<fs::File>> {
        let file = try!(fs::File::create(filename));
        Ok(WavWriter::new(file, spec))
    }

    /// Writes the RIFF WAVE header
    fn write_header(&mut self) -> io::Result<()> {
        let mut header = [0u8; 44];
        let spec = &self.spec;

        // Write the header in-memory first.
        {
            let mut buffer: io::Cursor<&mut [u8]> = io::Cursor::new(&mut header);
            try!(buffer.write_all("RIFF".as_bytes()));

            // Skip 4 bytes that will be filled with the file size afterwards.
            try!(buffer.seek(io::SeekFrom::Current(4)));

            try!(buffer.write_all("WAVE".as_bytes()));
            try!(buffer.write_all("fmt\0".as_bytes()));
            try!(buffer.write_le_u32(16)); // Size of the WAVE header
            try!(buffer.write_le_u16(1));  // PCM encoded audio
            try!(buffer.write_le_u16(spec.channels));
            try!(buffer.write_le_u32(spec.sample_rate));
            let bytes_per_sec = spec.sample_rate
                              * spec.bits_per_sample
                              * spec.channels as u32 / 8;
            try!(buffer.write_le_u32(bytes_per_sec));
            try!(buffer.write_le_u16(16)); // TODO: block align
            try!(buffer.write_le_u32(spec.bits_per_sample));

            // TODO: data section header
        }

        // Then write the entire header at once.
        try!(self.writer.write_all(&header));

        Ok(())
    }

    /// Writes a single sample for one channel.
    ///
    /// WAVE interleaves channel data, so the channel that this writes the
    /// sample to depends on previous writes.
    pub fn write_sample<S: Sample>(&mut self, sample: S) -> io::Result<()> {
        if !self.wrote_header {
            try!(self.write_header());
        }

        try!(sample.write(&mut self.writer, self.spec.bits_per_sample));
        self.data_bytes_written += self.spec.bits_per_sample / 8;
        Ok(())
    }

    /// Performs finalization. After calling this, the writer should be destructed.
    fn finalize_internal(&mut self) -> io::Result<()> {
        self.finalized = true;

        // Flush remaining samples via the BufWriter.
        try!(self.writer.flush());

        // Extract the underlying writer and rewind it to the start, to update
        // the header fields of which we now know the value.
        let mut writer = self.writer.get_mut();
        try!(writer.seek(io::SeekFrom::Start(0)));

        // TODO: update size fields
        Ok(())
    }

    /// Writes the parts of the WAVE format that require knowing all samples.
    ///
    /// This method must be called after all samples have been written. If it
    /// is not called, the destructor will finalize the file, but any IO errors
    /// that occur in the process cannot be observed in that manner.
    pub fn finalize(mut self) -> io::Result<()> {
        self.finalize_internal()
    }
}

impl<W> Drop for WavWriter<W> where W: io::Write + io::Seek {
    fn drop(&mut self) {
        // `finalize_internal` must be called only once. If that is done via
        // `finalize`, then this method is a no-op. If the user did not
        // finalize explicitly, then we should do it now. This can fail, but
        // drop should not panic, so a failure is ignored silently here.
        if !self.finalized {
            let _r = self.finalize_internal();
        }
    }
}
<|endoftext|>


<commit_before>#![no_std]

pub mod prelude;

// TODO documentation
// TODO attributes
// TODO MACROS
#[macro_export] macro_rules! lisp {
    // empty
    () => (());
    (()) => (());

    // special forms
    ((ns $($ns_form:tt)*) $($body:tt)*) => {
        $(lisp!($ns_form);)*
        $(lisp!($body);)*
    };
    ((extern [$($krate:tt)*])) => {
        $(lisp!(@krate $krate);)*
    };
    ((use [$($uze:tt)*])) => {
        $(lisp!(@uze $uze);)*
    };
    ((lambda ($($argn:ident)*) $($body:tt)*)) => {
        // regular lambda
        |$($argn),*| { $(lisp!($body));* }
    };
    ((lambda (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {
        // regular lambda
        |$($argn:$argt),*| -> $ret { $(lisp!($body));* }
    };
    ((lambda $s:ident (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {{
        // recursive lambda
        // $s MUST NOT be "self"
        // recurse by calling ($s ...)
        // FIXME recursive lambdas can't capture variables

        lisp!((rust { fn $s($($argn: $argt),*) -> $ret { $(lisp!($body));* } $s }))
    }};
    ((defn $name:ident () $($body:tt)*)) => {
        fn $name() {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([($selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([(&$selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name(&$selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([(&mut $selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name(&mut $selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([($selph:ident: Box<Self>) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($selph: Box<Self> $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([$(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($($argn:$argt),*) -> $ret {
            $(lisp!($body));*
        }
    };

    ((defstruct $name:ident $(($typ:ty))*)) => {
        struct $name($($typ),*);
    };
    ((defstruct $name:ident $(($field:ident $typ:ty))*)) => {
        struct $name { $($field: $typ),* }
    };
    ((defstruct $name:ident <$($gen:ident)*>)) => {
        struct $name<$($gen),*>;
    };
    ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($typ:ty))*)) => {
        struct $name<$($gen),*>($($typ),*) where $($wty: $($wtr)*),*;
    };
    ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($field:ident $typ:ty))*)) => {
        struct $name<$($gen),*> where $($wty: $($wtr)*),* { $($field: $typ),* }
    };

    ((deftype $name:ident $typ:ty)) => { type $name = $typ; };
    ((deftype $name:ident <$($gen:ident)*> $typ:ty)) => { type $name<$($gen),*> = $typ; };

    ((defimpl ($trate:ty) (for $typ:ty) $($body:tt)*)) => {
        impl $trate for $typ {
            $(lisp!($body);)*
        }
    };
    ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) (where $(($wty:ident $($wtr:tt)*))*) $($body:tt)*)) => {
        impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* {
            $(lisp!($body);)*
        }
    };
    ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) $($body:tt)*)) => {
        impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* {
            $(lisp!($body);)*
        }
    };

    ((if $cond:tt $yes:tt $no:tt)) => {
        if lisp!($cond) { lisp!($yes) } else { lisp!($no) }
    };
    (@list while, $cond:tt, $($body:tt),*) => {
        while lisp!($cond) { $(lisp!($body));* }
    };
    // TODO for loops
    (@list match, $var:tt, $(($cond:tt $arm:tt)),*) => {
        match lisp!($var) {
            $(lisp!(@pat $cond) => lisp!($arm)),*
        }
    };
    ((do $($stmts:tt)*)) => {{
        $(lisp!($stmts));*
    }};

    // variables
    ((let ((mut $var:ident $val:tt) $($bindings:tt)+) $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        lisp!((let ($($bindings)+) $($body)*))
    }};
    ((let (($var:ident $val:tt) $($bindings:tt)+) $($body:tt)*)) => {{
        let $var = lisp!($val);
        lisp!((let ($($bindings)+) $($body)*))
    }};
    ((let ((mut $var:ident $val:tt)) $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        $(lisp!($body));*
    }};
    ((let ((mut $var:ident $val:tt)) $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        $(lisp!($body));*
    }};
    ((let (($var:ident $val:tt)) $($body:tt)*)) => {{
        let $var = lisp!($val);
        $(lisp!($body));*
    }};
    ((:= $var:ident $val:tt)) => {
        $var = lisp!($val);
    };

    // escape hatch
    ((rust $body:block)) => {
        { $body }
    };

    // list parsing
    (($($elem:tt)*)) => {
        lisp!(@list $($elem),*)
    };

    // parsers for unary and binary operators
    (@list -,    $arg:tt   ) => { lisp!(@unary  _neg,   $arg   ) };
    (@list !,    $arg:tt   ) => { lisp!(@unary  _not,   $arg   ) };
    (@list +,  $($arg:tt),*) => { lisp!(@binary _add, $($arg),*) };
    (@list &,  $($arg:tt),*) => { lisp!(@binary _and, $($arg),*) };
    (@list |,  $($arg:tt),*) => { lisp!(@binary _or,  $($arg),*) };
    (@list ^,  $($arg:tt),*) => { lisp!(@binary _xor, $($arg),*) };
    (@list /,  $($arg:tt),*) => { lisp!(@binary _div, $($arg),*) };
    (@list *,  $($arg:tt),*) => { lisp!(@binary _mul, $($arg),*) };
    (@list %,  $($arg:tt),*) => { lisp!(@binary _rem, $($arg),*) };
    (@list <<, $($arg:tt),*) => { lisp!(@binary _shl, $($arg),*) };
    (@list >>, $($arg:tt),*) => { lisp!(@binary _shr, $($arg),*) };
    (@list -,  $($arg:tt),*) => { lisp!(@binary _sub, $($arg),*) };
    (@list ==, $($arg:tt),*) => { lisp!(@binary _eq,  $($arg),*) };
    (@list !=, $($arg:tt),*) => { lisp!(@binary _ne,  $($arg),*) };
    (@list >,  $($arg:tt),*) => { lisp!(@binary _gt,  $($arg),*) };
    (@list <,  $($arg:tt),*) => { lisp!(@binary _lt,  $($arg),*) };
    (@list >=, $($arg:tt),*) => { lisp!(@binary _ge,  $($arg),*) };
    (@list <=, $($arg:tt),*) => { lisp!(@binary _le,  $($arg),*) };

    // generically turn unary/binary operators into function calls
    // binary operators can be used as n-ary operators through @reduce
    (@unary  $op:ident, $a:tt)        => { lisp!(@list $op, $a)     };
    (@binary $op:ident, $a:tt, $b:tt) => { lisp!(@list $op, $a, $b) };
    (@binary $op:ident, $a:tt, $b:tt, $($rest:tt),+) =>
                                               { lisp!(@reduce $op,
                                                       ($op $a $b),
                                                       $($rest),+) };

    // reduce implementation
    // TODO external entry point for @reduce
    (@reduce $op:ident, $acc:tt)                       => { lisp!($acc)          };
    (@reduce $op:ident, $acc:tt, $a:tt)                => { lisp!(@reduce $op,
                                                                  ($op $acc $a)) };
    (@reduce $op:ident, $acc:tt, $a:tt, $($rest:tt),+) => { lisp!(@reduce $op,
                                                                  ($op $acc $a),
                                                                  $($rest),+)    };
    // ns form helpers
    (@krate $(^$attr:meta)* $krate:ident) => {
        $(#[$attr:meta])*
        extern crate $krate;
    };
    (@krate $(^$attr:meta)* ($krate:ident $alias:ident)) => {
        $(#[$attr:meta])*
        extern crate $krate as $alias;
    };
    (@uze ($($head:ident)*)) => { use $($head)::*; };
    (@uze ($($head:ident)* { $($multiple:ident)* })) => {
        lisp!(@uze mult ($($head)*) { $($multiple)* });
    };
    (@uze mult $head:tt { $($multiple:ident)* }) => {
        $(lisp!(@uze mult out $head $multiple);)*
    };
    (@uze mult out ($($head:ident)*) $multiple:ident) => {
        use $($head)::*::$multiple;
    };

    // macro calls
    (@list $mac:ident, !) => {
        $mac!()
    };
    (@list $mac:ident, !, $($arg:tt),*) => {
        $mac!($(lisp!($arg)),*)
    };

    // struct constructors
    (@list $name:ident, ., $(($member:ident $val:tt)),*) => {
        $name { $($member: lisp!($val))* }
    };

    // function calls
    (@list $name:expr) => {
        lisp!($name)()
    };
    (@list $name:expr, $($arg:tt),*) => {
        lisp!($name)($(lisp!($arg)),*)
    };

    // one expression
    ($e:expr) => ($e);
}
<commit_msg>parse match and while without @list<commit_after>#![no_std]

pub mod prelude;

// TODO documentation
// TODO attributes
// TODO MACROS
#[macro_export] macro_rules! lisp {
    // empty
    () => (());
    (()) => (());

    // special forms
    ((ns $($ns_form:tt)*) $($body:tt)*) => {
        $(lisp!($ns_form);)*
        $(lisp!($body);)*
    };
    ((extern [$($krate:tt)*])) => {
        $(lisp!(@krate $krate);)*
    };
    ((use [$($uze:tt)*])) => {
        $(lisp!(@uze $uze);)*
    };
    ((lambda ($($argn:ident)*) $($body:tt)*)) => {
        // regular lambda
        |$($argn),*| { $(lisp!($body));* }
    };
    ((lambda (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {
        // regular lambda
        |$($argn:$argt),*| -> $ret { $(lisp!($body));* }
    };
    ((lambda $s:ident (($(($argn:ident $argt:ty))*) $ret:ty) $($body:tt)*)) => {{
        // recursive lambda
        // $s MUST NOT be "self"
        // recurse by calling ($s ...)
        // FIXME recursive lambdas can't capture variables

        lisp!((rust { fn $s($($argn: $argt),*) -> $ret { $(lisp!($body));* } $s }))
    }};
    ((defn $name:ident () $($body:tt)*)) => {
        fn $name() {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([($selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([(&$selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name(&$selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([(&mut $selph:ident) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name(&mut $selph $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([($selph:ident: Box<Self>) $(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($selph: Box<Self> $(, $argn:$argt)*) -> $ret {
            $(lisp!($body));*
        }
    };
    ((defn $name:ident ([$(($argn:ident $argt:ty))*] $ret:ty) $($body:tt)*)) => {
        fn $name($($argn:$argt),*) -> $ret {
            $(lisp!($body));*
        }
    };

    ((defstruct $name:ident $(($typ:ty))*)) => {
        struct $name($($typ),*);
    };
    ((defstruct $name:ident $(($field:ident $typ:ty))*)) => {
        struct $name { $($field: $typ),* }
    };
    ((defstruct $name:ident <$($gen:ident)*>)) => {
        struct $name<$($gen),*>;
    };
    ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($typ:ty))*)) => {
        struct $name<$($gen),*>($($typ),*) where $($wty: $($wtr)*),*;
    };
    ((defstruct $name:ident <$($gen:ident)*> (where $(($wty:ident $($wtr:tt)*))*) $(($field:ident $typ:ty))*)) => {
        struct $name<$($gen),*> where $($wty: $($wtr)*),* { $($field: $typ),* }
    };

    ((deftype $name:ident $typ:ty)) => { type $name = $typ; };
    ((deftype $name:ident <$($gen:ident)*> $typ:ty)) => { type $name<$($gen),*> = $typ; };

    ((defimpl ($trate:ty) (for $typ:ty) $($body:tt)*)) => {
        impl $trate for $typ {
            $(lisp!($body);)*
        }
    };
    ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) (where $(($wty:ident $($wtr:tt)*))*) $($body:tt)*)) => {
        impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* {
            $(lisp!($body);)*
        }
    };
    ((defimpl <$($gen:ident)*> ($trate:ty) (for $typ:ty) $($body:tt)*)) => {
        impl<$($gen),*> $trate for $typ where $($wty: $($wtr)*),* {
            $(lisp!($body);)*
        }
    };

    ((if $cond:tt $yes:tt $no:tt)) => {
        if lisp!($cond) { lisp!($yes) } else { lisp!($no) }
    };
    ((while $cond:tt $($body:tt)*)) => {
        while lisp!($cond) { $(lisp!($body));* }
    };
    // TODO for loops
    ((match $var:tt $(($cond:pat) $arm:tt)*)) => {
        match lisp!($var) {
            $($cond => lisp!($arm)),*
        }
    };
    ((do $($stmts:tt)*)) => {{
        $(lisp!($stmts));*
    }};

    // variables
    ((let ((mut $var:ident $val:tt) $($bindings:tt)+) $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        lisp!((let ($($bindings)+) $($body)*))
    }};
    ((let (($var:ident $val:tt) $($bindings:tt)+) $($body:tt)*)) => {{
        let $var = lisp!($val);
        lisp!((let ($($bindings)+) $($body)*))
    }};
    ((let ((mut $var:ident $val:tt)) $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        $(lisp!($body));*
    }};
    ((let ((mut $var:ident $val:tt)) $($body:tt)*)) => {{
        let mut $var = lisp!($val);
        $(lisp!($body));*
    }};
    ((let (($var:ident $val:tt)) $($body:tt)*)) => {{
        let $var = lisp!($val);
        $(lisp!($body));*
    }};
    ((:= $var:ident $val:tt)) => {
        $var = lisp!($val);
    };

    // escape hatch
    ((rust $body:block)) => {
        { $body }
    };

    // list parsing
    (($($elem:tt)*)) => {
        lisp!(@list $($elem),*)
    };

    // parsers for unary and binary operators
    (@list -,    $arg:tt   ) => { lisp!(@unary  _neg,   $arg   ) };
    (@list !,    $arg:tt   ) => { lisp!(@unary  _not,   $arg   ) };
    (@list +,  $($arg:tt),*) => { lisp!(@binary _add, $($arg),*) };
    (@list &,  $($arg:tt),*) => { lisp!(@binary _and, $($arg),*) };
    (@list |,  $($arg:tt),*) => { lisp!(@binary _or,  $($arg),*) };
    (@list ^,  $($arg:tt),*) => { lisp!(@binary _xor, $($arg),*) };
    (@list /,  $($arg:tt),*) => { lisp!(@binary _div, $($arg),*) };
    (@list *,  $($arg:tt),*) => { lisp!(@binary _mul, $($arg),*) };
    (@list %,  $($arg:tt),*) => { lisp!(@binary _rem, $($arg),*) };
    (@list <<, $($arg:tt),*) => { lisp!(@binary _shl, $($arg),*) };
    (@list >>, $($arg:tt),*) => { lisp!(@binary _shr, $($arg),*) };
    (@list -,  $($arg:tt),*) => { lisp!(@binary _sub, $($arg),*) };
    (@list ==, $($arg:tt),*) => { lisp!(@binary _eq,  $($arg),*) };
    (@list !=, $($arg:tt),*) => { lisp!(@binary _ne,  $($arg),*) };
    (@list >,  $($arg:tt),*) => { lisp!(@binary _gt,  $($arg),*) };
    (@list <,  $($arg:tt),*) => { lisp!(@binary _lt,  $($arg),*) };
    (@list >=, $($arg:tt),*) => { lisp!(@binary _ge,  $($arg),*) };
    (@list <=, $($arg:tt),*) => { lisp!(@binary _le,  $($arg),*) };

    // generically turn unary/binary operators into function calls
    // binary operators can be used as n-ary operators through @reduce
    (@unary  $op:ident, $a:tt)        => { lisp!(@list $op, $a)     };
    (@binary $op:ident, $a:tt, $b:tt) => { lisp!(@list $op, $a, $b) };
    (@binary $op:ident, $a:tt, $b:tt, $($rest:tt),+) =>
                                               { lisp!(@reduce $op,
                                                       ($op $a $b),
                                                       $($rest),+) };

    // reduce implementation
    // TODO external entry point for @reduce
    (@reduce $op:ident, $acc:tt)                       => { lisp!($acc)          };
    (@reduce $op:ident, $acc:tt, $a:tt)                => { lisp!(@reduce $op,
                                                                  ($op $acc $a)) };
    (@reduce $op:ident, $acc:tt, $a:tt, $($rest:tt),+) => { lisp!(@reduce $op,
                                                                  ($op $acc $a),
                                                                  $($rest),+)    };
    // ns form helpers
    (@krate $(^$attr:meta)* $krate:ident) => {
        $(#[$attr:meta])*
        extern crate $krate;
    };
    (@krate $(^$attr:meta)* ($krate:ident $alias:ident)) => {
        $(#[$attr:meta])*
        extern crate $krate as $alias;
    };
    (@uze ($($head:ident)*)) => { use $($head)::*; };
    (@uze ($($head:ident)* { $($multiple:ident)* })) => {
        lisp!(@uze mult ($($head)*) { $($multiple)* });
    };
    (@uze mult $head:tt { $($multiple:ident)* }) => {
        $(lisp!(@uze mult out $head $multiple);)*
    };
    (@uze mult out ($($head:ident)*) $multiple:ident) => {
        use $($head)::*::$multiple;
    };

    // macro calls
    (@list $mac:ident, !) => {
        $mac!()
    };
    (@list $mac:ident, !, $($arg:tt),*) => {
        $mac!($(lisp!($arg)),*)
    };

    // struct constructors
    (@list $name:ident, ., $(($member:ident $val:tt)),*) => {
        $name { $($member: lisp!($val))* }
    };

    // function calls
    (@list $name:expr) => {
        lisp!($name)()
    };
    (@list $name:expr, $($arg:tt),*) => {
        lisp!($name)($(lisp!($arg)),*)
    };

    // one expression
    ($e:expr) => ($e);
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::str::FromStr;

pub fn puzzle(input: &str) -> i32 {
    for line in input.lines() {
        let line = line.trim();
    }
    0
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Instruction {
    Copy(FromLocation, Register),
    Increment(Register),
    Decrement(Register),
    JumpNonZero(Register, i32),
}

impl FromStr for Instruction {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut parts = s.split_whitespace();
        match parts.next() {
            Some("cpy") => Ok(
                Instruction::Copy(
                    parts.next().ok_or("no from location")?.parse()?,
                    parts.next().ok_or("no register")?.parse()?
                )
            ),
            Some("inc") => Ok(
                Instruction::Increment(
                    parts.next().ok_or("no register")?.parse()?
                )
            ),
            Some("dec") => Ok(
                Instruction::Decrement(
                    parts.next().ok_or("no register")?.parse()?
                )
            ),
            Some("jnz") => Ok(
                Instruction::JumpNonZero(
                    parts.next().ok_or("no register")?.parse()?,
                    parts.next().ok_or("no offset")?.parse()?
                )
            ),
            Some(other) => Err(format!("Unknown instruction: {}", other).into()),
            None => Err("Instruction missing".into()),
        }
    }
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum FromLocation {
    Integer(i32),
    Register(Register),
}

impl FromStr for FromLocation {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        s.parse().map(FromLocation::Integer)
                 .or_else(|_| s.parse().map(FromLocation::Register))
    }
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Register {
    A,
    B,
    C,
    D,
}

impl FromStr for Register {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Register::*;
        match s {
            "a" => Ok(A),
            "b" => Ok(B),
            "c" => Ok(C),
            "d" => Ok(D),
            other => Err(format!("Unknown register {}", other).into()),
        }
    }
}

pub struct Machine {
    registers: [i32; 4],
}

impl Machine {
    pub fn new() -> Machine {
        Machine {
            registers: [0; 4],
        }
    }

    fn execute(&mut self, instructions: &[Instruction]) {
        for &instruction in instructions {
            match instruction {
                Instruction::Copy(
                    FromLocation::Integer(i),
                    to
                ) => {
                    let index = Machine::register_index(to);
                    self.registers[index] = i;
                },
                Instruction::Copy(FromLocation::Register(from), to) => {
                    let index_from = Machine::register_index(from);
                    let index_to = Machine::register_index(to);
                    self.registers[index_to] = self.registers[index_from];
                },
                Instruction::Increment(register) => {
                    let index = Machine::register_index(register);
                    self.registers[index] += 1;
                },
                Instruction::Decrement(register) => {
                    let index = Machine::register_index(register);
                    self.registers[index] -= 1;
                },
                Instruction::JumpNonZero(_, _) => {},
            }
        }
    }

    fn register_index(register: Register) -> usize {
        use Register::*;
        match register {
            A => 0,
            B => 1,
            C => 2,
            D => 3,
        }
    }

    fn value_of(&self, register: Register) -> i32 {
        let index = Machine::register_index(register);
        self.registers[index]
    }
}

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

    #[test]
    fn parse_cpy() {
        let instr: Instruction = "cpy 41 a".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Copy(FromLocation::Integer(41), Register::A)
        );
    }

    #[test]
    fn parse_cpy_register() {
        let instr: Instruction = "cpy a c".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Copy(
                FromLocation::Register(Register::A),
                Register::C,
            )
        );
    }

    #[test]
    fn parse_inc() {
        let instr: Instruction = "inc a".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Increment(Register::A)
        );
    }

    #[test]
    fn parse_dec() {
        let instr: Instruction = "dec a".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Decrement(Register::A)
        );
    }

    #[test]
    fn parse_jnz() {
        let instr: Instruction = "jnz a 2".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::JumpNonZero(Register::A, 2)
        );
    }

    #[test]
    fn execute_copy() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                Instruction::Copy(
                    FromLocation::Integer(5),
                    Register::A,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::A), 5);
    }

    #[test]
    fn execute_copy_register() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                Instruction::Copy(
                    FromLocation::Integer(5),
                    Register::A,
                ),
                Instruction::Copy(
                    FromLocation::Register(Register::A),
                    Register::B,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::B), 5);
    }

    #[test]
    fn execute_increment() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                Instruction::Increment(
                    Register::C,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::C), 1);
    }

    #[test]
    fn execute_decrement() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                Instruction::Decrement(
                    Register::D,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::D), -1);
    }

    #[test]
    fn execute_jnz_when_zero() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                // D should be 0, jump doesn't happen
                Instruction::JumpNonZero(Register::D, 2),
                Instruction::Increment(
                    Register::A,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::A), 1);
    }

    #[test]
    fn sample() {
        let input = "cpy 41 a
            inc a
            inc a
            dec a
            jnz a 2
            dec a";
        assert_eq!(puzzle(input), 42);
    }
}
<commit_msg>Sample works<commit_after>use std::error::Error;
use std::str::FromStr;

pub fn puzzle(input: &str) -> i32 {
    let instructions: Result<Vec<_>, _> = input.lines().map(|line| line.trim().parse()).collect();
    let instructions = instructions.expect("couldn't parse instructions");
    let mut machine = Machine::new();
    machine.execute(&instructions);
    machine.value_of(Register::A)
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Instruction {
    Copy(FromLocation, Register),
    Increment(Register),
    Decrement(Register),
    JumpNonZero(Register, i32),
}

impl FromStr for Instruction {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut parts = s.split_whitespace();
        match parts.next() {
            Some("cpy") => Ok(
                Instruction::Copy(
                    parts.next().ok_or("no from location")?.parse()?,
                    parts.next().ok_or("no register")?.parse()?
                )
            ),
            Some("inc") => Ok(
                Instruction::Increment(
                    parts.next().ok_or("no register")?.parse()?
                )
            ),
            Some("dec") => Ok(
                Instruction::Decrement(
                    parts.next().ok_or("no register")?.parse()?
                )
            ),
            Some("jnz") => Ok(
                Instruction::JumpNonZero(
                    parts.next().ok_or("no register")?.parse()?,
                    parts.next().ok_or("no offset")?.parse()?
                )
            ),
            Some(other) => Err(format!("Unknown instruction: {}", other).into()),
            None => Err("Instruction missing".into()),
        }
    }
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum FromLocation {
    Integer(i32),
    Register(Register),
}

impl FromStr for FromLocation {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        s.parse().map(FromLocation::Integer)
                 .or_else(|_| s.parse().map(FromLocation::Register))
    }
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Register {
    A,
    B,
    C,
    D,
}

impl FromStr for Register {
    type Err = Box<Error>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Register::*;
        match s {
            "a" => Ok(A),
            "b" => Ok(B),
            "c" => Ok(C),
            "d" => Ok(D),
            other => Err(format!("Unknown register {}", other).into()),
        }
    }
}

pub struct Machine {
    registers: [i32; 4],
}

impl Machine {
    pub fn new() -> Machine {
        Machine {
            registers: [0; 4],
        }
    }

    fn execute(&mut self, instructions: &[Instruction]) {
        let mut program_counter = 0;
        while let Some(&instruction) = instructions.get(program_counter) {
            let mut jump = 0;
            match instruction {
                Instruction::Copy(
                    FromLocation::Integer(i),
                    to
                ) => {
                    let index = Machine::register_index(to);
                    self.registers[index] = i;
                },
                Instruction::Copy(FromLocation::Register(from), to) => {
                    let index_from = Machine::register_index(from);
                    let index_to = Machine::register_index(to);
                    self.registers[index_to] = self.registers[index_from];
                },
                Instruction::Increment(register) => {
                    let index = Machine::register_index(register);
                    self.registers[index] += 1;
                },
                Instruction::Decrement(register) => {
                    let index = Machine::register_index(register);
                    self.registers[index] -= 1;
                },
                Instruction::JumpNonZero(register, offset) => {
                    let index = Machine::register_index(register);
                    if self.registers[index] != 0 {
                        jump = offset;
                    }
                },
            }
            let next_pc = program_counter as i32 + 1 + jump;
            if next_pc < 0 {
                panic!("Jumped too far back!")
            }
            program_counter = next_pc as usize;
        }
    }

    fn register_index(register: Register) -> usize {
        use Register::*;
        match register {
            A => 0,
            B => 1,
            C => 2,
            D => 3,
        }
    }

    fn value_of(&self, register: Register) -> i32 {
        let index = Machine::register_index(register);
        self.registers[index]
    }
}

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

    #[test]
    fn parse_cpy() {
        let instr: Instruction = "cpy 41 a".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Copy(FromLocation::Integer(41), Register::A)
        );
    }

    #[test]
    fn parse_cpy_register() {
        let instr: Instruction = "cpy a c".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Copy(
                FromLocation::Register(Register::A),
                Register::C,
            )
        );
    }

    #[test]
    fn parse_inc() {
        let instr: Instruction = "inc a".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Increment(Register::A)
        );
    }

    #[test]
    fn parse_dec() {
        let instr: Instruction = "dec a".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::Decrement(Register::A)
        );
    }

    #[test]
    fn parse_jnz() {
        let instr: Instruction = "jnz a 2".parse().expect("couldn't parse");
        assert_eq!(
            instr,
            Instruction::JumpNonZero(Register::A, 2)
        );
    }

    #[test]
    fn execute_copy() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                Instruction::Copy(
                    FromLocation::Integer(5),
                    Register::A,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::A), 5);
    }

    #[test]
    fn execute_copy_register() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                Instruction::Copy(
                    FromLocation::Integer(5),
                    Register::A,
                ),
                Instruction::Copy(
                    FromLocation::Register(Register::A),
                    Register::B,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::B), 5);
    }

    #[test]
    fn execute_increment() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                Instruction::Increment(
                    Register::C,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::C), 1);
    }

    #[test]
    fn execute_decrement() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                Instruction::Decrement(
                    Register::D,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::D), -1);
    }

    #[test]
    fn execute_jnz_when_zero() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                // D should be 0, jump doesn't happen
                Instruction::JumpNonZero(Register::D, 2),
                Instruction::Increment(
                    Register::A,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::A), 1);
    }

    #[test]
    fn execute_jnz_when_non_zero() {
        let mut machine = Machine::new();
        machine.execute(
            &[
                Instruction::Decrement(
                    Register::D,
                ),
                Instruction::JumpNonZero(Register::D, 2),
                Instruction::Increment(
                    Register::A,
                ),
            ]
        );

        assert_eq!(machine.value_of(Register::A), 0);
    }

    #[test]
    fn sample() {
        let input = "cpy 41 a
            inc a
            inc a
            dec a
            jnz a 2
            dec a";
        assert_eq!(puzzle(input), 42);
    }
}
<|endoftext|>


<commit_before>#![feature(metadata_ext)]
#![cfg_attr(any(target_os = "bitrig",
                target_os = "freebsd",
                target_os = "ios",
                target_os = "macos",
                target_os = "openbsd"), feature(raw_ext))]

#[cfg(unix)] use std::os::unix::prelude::*;
#[cfg(windows)] use std::os::windows::prelude::*;

use std::fmt;
use std::fs;

/// A helper structure to represent a timestamp for a file.
///
/// The actual value contined within is platform-specific and does not have the
/// same meaning across platforms, but comparisons and stringification can be
/// significant among the same platform.
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Copy, Clone)]
pub struct FileTime {
    seconds: u64,
    nanos: u32,
}

impl FileTime {
    /// Creates a new timestamp representing a 0 time.
    ///
    /// Useful for creating the base of a cmp::max chain of times.
    pub fn zero() -> FileTime {
        FileTime { seconds: 0, nanos: 0 }
    }

    /// Creates a new timestamp from the last modification time listed in the
    /// specified metadata.
    ///
    /// The returned value corresponds to the `mtime` field of `stat` on Unix
    /// platforms and the `ftLastWriteTime` field on Windows platforms.
    pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime {
        #[cfg(unix)]
        fn imp(meta: &fs::Metadata) -> FileTime {
            let meta = meta.as_raw();
            FileTime::from_os_repr(meta.mtime() as u64, meta.mtime_nsec() as u32)
        }
        #[cfg(windows)]
        fn imp(meta: &fs::Metadata) -> FileTime {
            FileTime::from_os_repr(meta.last_write_time())
        }
        imp(meta)
    }

    /// Creates a new timestamp from the last access time listed in the
    /// specified metadata.
    ///
    /// The returned value corresponds to the `atime` field of `stat` on Unix
    /// platforms and the `ftLastAccessTime` field on Windows platforms.
    pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime {
        #[cfg(unix)]
        fn imp(meta: &fs::Metadata) -> FileTime {
            let meta = meta.as_raw();
            FileTime::from_os_repr(meta.atime() as u64, meta.atime_nsec() as u32)
        }
        #[cfg(windows)]
        fn imp(meta: &fs::Metadata) -> FileTime {
            FileTime::from_os_repr(meta.last_access_time())
        }
        imp(meta)
    }

    /// Creates a new timestamp from the creation time listed in the specified
    /// metadata.
    ///
    /// The returned value corresponds to the `birthtime` field of `stat` on
    /// Unix platforms and the `ftCreationTime` field on Windows platforms. Note
    /// that not all Unix platforms have this field available and may return
    /// `None` in some circumstances.
    pub fn from_creation_time(meta: &fs::Metadata) -> Option<FileTime> {
        macro_rules! birthtim {
            ($(($e:expr, $i:ident)),*) => {
                #[cfg(any($(target_os = $e),*))]
                fn imp(meta: &fs::Metadata) -> Option<FileTime> {
                    $(
                        #[cfg(target_os = $e)]
                        use std::os::$i::fs::MetadataExt;
                    )*
                    let raw = meta.as_raw_stat();
                    Some(FileTime::from_os_repr(raw.st_birthtime as u64,
                                                raw.st_birthtime_nsec as u32))
                }

                #[cfg(all(not(windows),
                          $(not(target_os = $e)),*))]
                fn imp(_meta: &fs::Metadata) -> Option<FileTime> {
                    None
                }
            }
        }

        birthtim! {
            ("bitrig", bitrig),
            ("freebsd", freebsd),
            ("ios", ios),
            ("macos", macos),
            ("openbsd", openbsd)
        }

        #[cfg(windows)]
        fn imp(meta: &fs::Metadata) -> Option<FileTime> {
            Some(FileTime::from_os_repr(meta.last_access_time()))
        }
        imp(meta)
    }

    #[cfg(windows)]
    fn from_os_repr(time: u64) -> FileTime {
        // Windows write times are in 100ns intervals, so do a little math to
        // get it into the right representation.
        FileTime {
            seconds: time / (1_000_000_000 / 100),
            nanos: ((time % (1_000_000_000 / 100)) * 100) as u32,
        }
    }

    #[cfg(unix)]
    fn from_os_repr(seconds: u64, _nanos: u32) -> FileTime {
        // FIXME: currently there is a bug in the standard library where the
        //        nanosecond accessor is just accessing the seconds again, once
        //        that bug is fixed this should take nanoseconds into account.
        FileTime { seconds: seconds, nanos: 0 }
    }

    /// Returns the whole number of seconds represented by this timestamp.
    ///
    /// Note that this value's meaning is **platform specific**. On Unix
    /// platform time stamps are typically relative to January 1, 1970, but on
    /// Windows platforms time stamps are relative to January 1, 1601.
    pub fn seconds(&self) -> u64 { self.seconds }

    /// Returns the whole number of seconds represented by this timestamp,
    /// relative to the Unix epoch start of January 1, 1970.
    ///
    /// Note that this does not return the same value as `seconds` for Windows
    /// platforms as seconds are relative to a different date there.
    pub fn seconds_relative_to_1970(&self) -> u64 {
        self.seconds - if cfg!(windows) {11644473600} else {0}
    }

    /// Returns the nanosecond precision of this timestamp.
    ///
    /// The returned value is always less than one billion and represents a
    /// portion of a second forward from the seconds returned by the `seconds`
    /// method.
    pub fn nanoseconds(&self) -> u32 { self.nanos }
}

impl fmt::Display for FileTime {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}.{:09}s", self.seconds, self.nanos)
    }
}
<commit_msg>Use nanos now that the stdlib has fixed the bug<commit_after>#![feature(metadata_ext)]
#![cfg_attr(any(target_os = "bitrig",
                target_os = "freebsd",
                target_os = "ios",
                target_os = "macos",
                target_os = "openbsd"), feature(raw_ext))]

#[cfg(unix)] use std::os::unix::prelude::*;
#[cfg(windows)] use std::os::windows::prelude::*;

use std::fmt;
use std::fs;

/// A helper structure to represent a timestamp for a file.
///
/// The actual value contined within is platform-specific and does not have the
/// same meaning across platforms, but comparisons and stringification can be
/// significant among the same platform.
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Copy, Clone)]
pub struct FileTime {
    seconds: u64,
    nanos: u32,
}

impl FileTime {
    /// Creates a new timestamp representing a 0 time.
    ///
    /// Useful for creating the base of a cmp::max chain of times.
    pub fn zero() -> FileTime {
        FileTime { seconds: 0, nanos: 0 }
    }

    /// Creates a new timestamp from the last modification time listed in the
    /// specified metadata.
    ///
    /// The returned value corresponds to the `mtime` field of `stat` on Unix
    /// platforms and the `ftLastWriteTime` field on Windows platforms.
    pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime {
        #[cfg(unix)]
        fn imp(meta: &fs::Metadata) -> FileTime {
            let meta = meta.as_raw();
            FileTime::from_os_repr(meta.mtime() as u64, meta.mtime_nsec() as u32)
        }
        #[cfg(windows)]
        fn imp(meta: &fs::Metadata) -> FileTime {
            FileTime::from_os_repr(meta.last_write_time())
        }
        imp(meta)
    }

    /// Creates a new timestamp from the last access time listed in the
    /// specified metadata.
    ///
    /// The returned value corresponds to the `atime` field of `stat` on Unix
    /// platforms and the `ftLastAccessTime` field on Windows platforms.
    pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime {
        #[cfg(unix)]
        fn imp(meta: &fs::Metadata) -> FileTime {
            let meta = meta.as_raw();
            FileTime::from_os_repr(meta.atime() as u64, meta.atime_nsec() as u32)
        }
        #[cfg(windows)]
        fn imp(meta: &fs::Metadata) -> FileTime {
            FileTime::from_os_repr(meta.last_access_time())
        }
        imp(meta)
    }

    /// Creates a new timestamp from the creation time listed in the specified
    /// metadata.
    ///
    /// The returned value corresponds to the `birthtime` field of `stat` on
    /// Unix platforms and the `ftCreationTime` field on Windows platforms. Note
    /// that not all Unix platforms have this field available and may return
    /// `None` in some circumstances.
    pub fn from_creation_time(meta: &fs::Metadata) -> Option<FileTime> {
        macro_rules! birthtim {
            ($(($e:expr, $i:ident)),*) => {
                #[cfg(any($(target_os = $e),*))]
                fn imp(meta: &fs::Metadata) -> Option<FileTime> {
                    $(
                        #[cfg(target_os = $e)]
                        use std::os::$i::fs::MetadataExt;
                    )*
                    let raw = meta.as_raw_stat();
                    Some(FileTime::from_os_repr(raw.st_birthtime as u64,
                                                raw.st_birthtime_nsec as u32))
                }

                #[cfg(all(not(windows),
                          $(not(target_os = $e)),*))]
                fn imp(_meta: &fs::Metadata) -> Option<FileTime> {
                    None
                }
            }
        }

        birthtim! {
            ("bitrig", bitrig),
            ("freebsd", freebsd),
            ("ios", ios),
            ("macos", macos),
            ("openbsd", openbsd)
        }

        #[cfg(windows)]
        fn imp(meta: &fs::Metadata) -> Option<FileTime> {
            Some(FileTime::from_os_repr(meta.last_access_time()))
        }
        imp(meta)
    }

    #[cfg(windows)]
    fn from_os_repr(time: u64) -> FileTime {
        // Windows write times are in 100ns intervals, so do a little math to
        // get it into the right representation.
        FileTime {
            seconds: time / (1_000_000_000 / 100),
            nanos: ((time % (1_000_000_000 / 100)) * 100) as u32,
        }
    }

    #[cfg(unix)]
    fn from_os_repr(seconds: u64, nanos: u32) -> FileTime {
        FileTime { seconds: seconds, nanos: nanos }
    }

    /// Returns the whole number of seconds represented by this timestamp.
    ///
    /// Note that this value's meaning is **platform specific**. On Unix
    /// platform time stamps are typically relative to January 1, 1970, but on
    /// Windows platforms time stamps are relative to January 1, 1601.
    pub fn seconds(&self) -> u64 { self.seconds }

    /// Returns the whole number of seconds represented by this timestamp,
    /// relative to the Unix epoch start of January 1, 1970.
    ///
    /// Note that this does not return the same value as `seconds` for Windows
    /// platforms as seconds are relative to a different date there.
    pub fn seconds_relative_to_1970(&self) -> u64 {
        self.seconds - if cfg!(windows) {11644473600} else {0}
    }

    /// Returns the nanosecond precision of this timestamp.
    ///
    /// The returned value is always less than one billion and represents a
    /// portion of a second forward from the seconds returned by the `seconds`
    /// method.
    pub fn nanoseconds(&self) -> u32 { self.nanos }
}

impl fmt::Display for FileTime {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}.{:09}s", self.seconds, self.nanos)
    }
}
<|endoftext|>