<commit_before>// error-pattern:yummy
#![feature(box_syntax)]
#![feature(rustc_private)]
#![allow(unknown_lints, missing_docs_in_private_items)]

extern crate clippy_lints;
extern crate getopts;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_plugin;
extern crate syntax;

use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls};
use rustc::session::{config, CompileIncomplete, Session};
use rustc::session::config::{ErrorOutputType, Input};
use std::collections::HashMap;
use std::path::PathBuf;
use std::process::{self, Command};
use syntax::ast;
use std::io::{self, Write};

extern crate cargo_metadata;

struct ClippyCompilerCalls {
    default: RustcDefaultCalls,
    run_lints: bool,
}

impl ClippyCompilerCalls {
    fn new(run_lints: bool) -> Self {
        Self {
            default: RustcDefaultCalls,
            run_lints: run_lints,
        }
    }
}

impl<'a> CompilerCalls<'a> for ClippyCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType,
    ) -> Compilation {
        self.default
            .early_callback(matches, sopts, cfg, descriptions, output)
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry,
    ) -> Option<(Input, Option<PathBuf>)> {
        self.default
            .no_input(matches, sopts, cfg, odir, ofile, descriptions)
    }
    fn late_callback(
        &mut self,
        matches: &getopts::Matches,
        sess: &Session,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
    ) -> Compilation {
        self.default
            .late_callback(matches, sess, input, odir, ofile)
    }
    fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> {
        let mut control = self.default.build_controller(sess, matches);

        if self.run_lints {
            let old = std::mem::replace(&mut control.after_parse.callback, box |_| {});
            control.after_parse.callback = Box::new(move |state| {
                {
                    let mut registry = rustc_plugin::registry::Registry::new(
                        state.session,
                        state
                            .krate
                            .as_ref()
                            .expect(
                                "at this compilation stage \
                                 the krate must be parsed",
                            )
                            .span,
                    );
                    registry.args_hidden = Some(Vec::new());
                    clippy_lints::register_plugins(&mut registry);

                    let rustc_plugin::registry::Registry {
                        early_lint_passes,
                        late_lint_passes,
                        lint_groups,
                        llvm_passes,
                        attributes,
                        ..
                    } = registry;
                    let sess = &state.session;
                    let mut ls = sess.lint_store.borrow_mut();
                    for pass in early_lint_passes {
                        ls.register_early_pass(Some(sess), true, pass);
                    }
                    for pass in late_lint_passes {
                        ls.register_late_pass(Some(sess), true, pass);
                    }

                    for (name, to) in lint_groups {
                        ls.register_group(Some(sess), true, name, to);
                    }

                    sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes);
                    sess.plugin_attributes.borrow_mut().extend(attributes);
                }
                old(state);
            });
        }

        control
    }
}

use std::path::Path;

const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.

Usage:
    cargo clippy [options] [--] [<opts>...]

Common options:
    -h, --help               Print this message
    --features               Features to compile for the package
    -V, --version            Print version info and exit
    --all                    Run over all packages in the current workspace

Other options are the same as `cargo rustc`.

To allow or deny a lint from the command line you can use `cargo clippy --`
with:

    -W --warn OPT       Set lint warnings
    -A --allow OPT      Set lint allowed
    -D --deny OPT       Set lint denied
    -F --forbid OPT     Set lint forbidden

The feature `cargo-clippy` is automatically defined for convenience. You can use
it to allow or deny lints from the code, eg.:

    #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
"#;

#[allow(print_stdout)]
fn show_help() {
    println!("{}", CARGO_CLIPPY_HELP);
}

#[allow(print_stdout)]
fn show_version() {
    println!("{}", env!("CARGO_PKG_VERSION"));
}

pub fn main() {
    use std::env;

    if env::var("CLIPPY_DOGFOOD").map(|_| true).unwrap_or(false) {
        panic!("yummy");
    }

    // Check for version and help flags even when invoked as 'cargo-clippy'
    if std::env::args().any(|a| a == "--help" || a == "-h") {
        show_help();
        return;
    }
    if std::env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
        // this arm is executed on the initial call to `cargo clippy`

        let manifest_path_arg = std::env::args()
            .skip(2)
            .find(|val| val.starts_with("--manifest-path="));

        let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref))
        {
            metadata
        } else {
            let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n"));
            process::exit(101);
        };

        let manifest_path = manifest_path_arg.map(|arg| {
            Path::new(&arg["--manifest-path=".len()..])
                .canonicalize()
                .expect("manifest path could not be canonicalized")
        });

        let packages = if std::env::args().any(|a| a == "--all") {
            metadata.packages
        } else {
            let package_index = {
                if let Some(manifest_path) = manifest_path {
                    metadata.packages.iter().position(|package| {
                        let package_manifest_path = Path::new(&package.manifest_path)
                            .canonicalize()
                            .expect("package manifest path could not be canonicalized");
                        package_manifest_path == manifest_path
                    })
                } else {
                    let package_manifest_paths: HashMap<_, _> = metadata
                        .packages
                        .iter()
                        .enumerate()
                        .map(|(i, package)| {
                            let package_manifest_path = Path::new(&package.manifest_path)
                                .parent()
                                .expect("could not find parent directory of package manifest")
                                .canonicalize()
                                .expect("package directory cannot be canonicalized");
                            (package_manifest_path, i)
                        })
                        .collect();

                    let current_dir = std::env::current_dir()
                        .expect("could not read current directory")
                        .canonicalize()
                        .expect("current directory cannot be canonicalized");

                    let mut current_path: &Path = &current_dir;

                    // This gets the most-recent parent (the one that takes the fewest `cd ..`s to
                    // reach).
                    loop {
                        if let Some(&package_index) = package_manifest_paths.get(current_path) {
                            break Some(package_index);
                        } else {
                            // We'll never reach the filesystem root, because to get to this point in the
                            // code
                            // the call to `cargo_metadata::metadata` must have succeeded. So it's okay to
                            // unwrap the current path's parent.
                            current_path = current_path
                                .parent()
                                .unwrap_or_else(|| panic!("could not find parent of path {}", current_path.display()));
                        }
                    }
                }
            }.expect("could not find matching package");

            vec![metadata.packages.remove(package_index)]
        };

        for package in packages {
            let manifest_path = package.manifest_path;

            for target in package.targets {
                let args = std::env::args()
                    .skip(2)
                    .filter(|a| a != "--all" && !a.starts_with("--manifest-path="));

                let args = std::iter::once(format!("--manifest-path={}", manifest_path)).chain(args);
                if let Some(first) = target.kind.get(0) {
                    if target.kind.len() > 1 || first.ends_with("lib") {
                        if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args)) {
                            std::process::exit(code);
                        }
                    } else if ["bin", "example", "test", "bench"].contains(&&**first) {
                        if let Err(code) = process(
                            vec![format!("--{}", first), target.name]
                                .into_iter()
                                .chain(args),
                        ) {
                            std::process::exit(code);
                        }
                    }
                } else {
                    panic!("badly formatted cargo metadata: target::kind is an empty array");
                }
            }
        }
    } else {
        // this arm is executed when cargo-clippy runs `cargo rustc` with the `RUSTC`
        // env var set to itself

        let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
        let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
        let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) {
            format!("{}/toolchains/{}", home, toolchain)
        } else {
            option_env!("SYSROOT")
                .map(|s| s.to_owned())
                .or_else(|| {
                    Command::new("rustc")
                        .arg("--print")
                        .arg("sysroot")
                        .output()
                        .ok()
                        .and_then(|out| String::from_utf8(out.stdout).ok())
                        .map(|s| s.trim().to_owned())
                })
                .expect(
                    "need to specify SYSROOT env var during clippy compilation, or use rustup or multirust",
                )
        };

        rustc_driver::in_rustc_thread(|| {
            // this conditional check for the --sysroot flag is there so users can call
            // `cargo-clippy` directly
            // without having to pass --sysroot or anything
            let mut args: Vec<String> = if env::args().any(|s| s == "--sysroot") {
                env::args().collect()
            } else {
                env::args()
                    .chain(Some("--sysroot".to_owned()))
                    .chain(Some(sys_root))
                    .collect()
            };

            // this check ensures that dependencies are built but not linted and the final
            // crate is
            // linted but not built
            let clippy_enabled = env::args().any(|s| s == "--emit=metadata");

            if clippy_enabled {
                args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
            }

            let mut ccc = ClippyCompilerCalls::new(clippy_enabled);
            let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None);
            if let Err(CompileIncomplete::Errored(_)) = result {
                std::process::exit(1);
            }
        }).expect("rustc_thread failed");
    }
}

fn process<I>(old_args: I) -> Result<(), i32>
where
    I: Iterator<Item = String>,
{
    let mut args = vec!["rustc".to_owned()];

    let mut found_dashes = false;
    for arg in old_args {
        found_dashes |= arg == "--";
        args.push(arg);
    }
    if !found_dashes {
        args.push("--".to_owned());
    }
    args.push("--emit=metadata".to_owned());
    args.push("--cfg".to_owned());
    args.push(r#"feature="cargo-clippy""#.to_owned());

    let path = std::env::current_exe().expect("current executable path invalid");
    let exit_status = std::process::Command::new("cargo")
        .args(&args)
        .env("RUSTC", path)
        .spawn()
        .expect("could not run cargo")
        .wait()
        .expect("failed to wait for cargo?");

    if exit_status.success() {
        Ok(())
    } else {
        Err(exit_status.code().unwrap_or(-1))
    }
}
<commit_msg>Add a missing argument<commit_after>// error-pattern:yummy
#![feature(box_syntax)]
#![feature(rustc_private)]
#![allow(unknown_lints, missing_docs_in_private_items)]

extern crate clippy_lints;
extern crate getopts;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_plugin;
extern crate syntax;

use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls};
use rustc::session::{config, CompileIncomplete, Session};
use rustc::session::config::{ErrorOutputType, Input};
use std::collections::HashMap;
use std::path::PathBuf;
use std::process::{self, Command};
use syntax::ast;
use std::io::{self, Write};

extern crate cargo_metadata;

struct ClippyCompilerCalls {
    default: RustcDefaultCalls,
    run_lints: bool,
}

impl ClippyCompilerCalls {
    fn new(run_lints: bool) -> Self {
        Self {
            default: RustcDefaultCalls,
            run_lints: run_lints,
        }
    }
}

impl<'a> CompilerCalls<'a> for ClippyCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType,
    ) -> Compilation {
        self.default
            .early_callback(matches, sopts, cfg, descriptions, output)
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry,
    ) -> Option<(Input, Option<PathBuf>)> {
        self.default
            .no_input(matches, sopts, cfg, odir, ofile, descriptions)
    }
    fn late_callback(
        &mut self,
        matches: &getopts::Matches,
        sess: &Session,
        crate_stores: &rustc::middle::cstore::CrateStore,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
    ) -> Compilation {
        self.default
            .late_callback(matches, sess, crate_stores, input, odir, ofile)
    }
    fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> {
        let mut control = self.default.build_controller(sess, matches);

        if self.run_lints {
            let old = std::mem::replace(&mut control.after_parse.callback, box |_| {});
            control.after_parse.callback = Box::new(move |state| {
                {
                    let mut registry = rustc_plugin::registry::Registry::new(
                        state.session,
                        state
                            .krate
                            .as_ref()
                            .expect(
                                "at this compilation stage \
                                 the krate must be parsed",
                            )
                            .span,
                    );
                    registry.args_hidden = Some(Vec::new());
                    clippy_lints::register_plugins(&mut registry);

                    let rustc_plugin::registry::Registry {
                        early_lint_passes,
                        late_lint_passes,
                        lint_groups,
                        llvm_passes,
                        attributes,
                        ..
                    } = registry;
                    let sess = &state.session;
                    let mut ls = sess.lint_store.borrow_mut();
                    for pass in early_lint_passes {
                        ls.register_early_pass(Some(sess), true, pass);
                    }
                    for pass in late_lint_passes {
                        ls.register_late_pass(Some(sess), true, pass);
                    }

                    for (name, to) in lint_groups {
                        ls.register_group(Some(sess), true, name, to);
                    }

                    sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes);
                    sess.plugin_attributes.borrow_mut().extend(attributes);
                }
                old(state);
            });
        }

        control
    }
}

use std::path::Path;

const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.

Usage:
    cargo clippy [options] [--] [<opts>...]

Common options:
    -h, --help               Print this message
    --features               Features to compile for the package
    -V, --version            Print version info and exit
    --all                    Run over all packages in the current workspace

Other options are the same as `cargo rustc`.

To allow or deny a lint from the command line you can use `cargo clippy --`
with:

    -W --warn OPT       Set lint warnings
    -A --allow OPT      Set lint allowed
    -D --deny OPT       Set lint denied
    -F --forbid OPT     Set lint forbidden

The feature `cargo-clippy` is automatically defined for convenience. You can use
it to allow or deny lints from the code, eg.:

    #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
"#;

#[allow(print_stdout)]
fn show_help() {
    println!("{}", CARGO_CLIPPY_HELP);
}

#[allow(print_stdout)]
fn show_version() {
    println!("{}", env!("CARGO_PKG_VERSION"));
}

pub fn main() {
    use std::env;

    if env::var("CLIPPY_DOGFOOD").map(|_| true).unwrap_or(false) {
        panic!("yummy");
    }

    // Check for version and help flags even when invoked as 'cargo-clippy'
    if std::env::args().any(|a| a == "--help" || a == "-h") {
        show_help();
        return;
    }
    if std::env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
        // this arm is executed on the initial call to `cargo clippy`

        let manifest_path_arg = std::env::args()
            .skip(2)
            .find(|val| val.starts_with("--manifest-path="));

        let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref))
        {
            metadata
        } else {
            let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n"));
            process::exit(101);
        };

        let manifest_path = manifest_path_arg.map(|arg| {
            Path::new(&arg["--manifest-path=".len()..])
                .canonicalize()
                .expect("manifest path could not be canonicalized")
        });

        let packages = if std::env::args().any(|a| a == "--all") {
            metadata.packages
        } else {
            let package_index = {
                if let Some(manifest_path) = manifest_path {
                    metadata.packages.iter().position(|package| {
                        let package_manifest_path = Path::new(&package.manifest_path)
                            .canonicalize()
                            .expect("package manifest path could not be canonicalized");
                        package_manifest_path == manifest_path
                    })
                } else {
                    let package_manifest_paths: HashMap<_, _> = metadata
                        .packages
                        .iter()
                        .enumerate()
                        .map(|(i, package)| {
                            let package_manifest_path = Path::new(&package.manifest_path)
                                .parent()
                                .expect("could not find parent directory of package manifest")
                                .canonicalize()
                                .expect("package directory cannot be canonicalized");
                            (package_manifest_path, i)
                        })
                        .collect();

                    let current_dir = std::env::current_dir()
                        .expect("could not read current directory")
                        .canonicalize()
                        .expect("current directory cannot be canonicalized");

                    let mut current_path: &Path = &current_dir;

                    // This gets the most-recent parent (the one that takes the fewest `cd ..`s to
                    // reach).
                    loop {
                        if let Some(&package_index) = package_manifest_paths.get(current_path) {
                            break Some(package_index);
                        } else {
                            // We'll never reach the filesystem root, because to get to this point in the
                            // code
                            // the call to `cargo_metadata::metadata` must have succeeded. So it's okay to
                            // unwrap the current path's parent.
                            current_path = current_path
                                .parent()
                                .unwrap_or_else(|| panic!("could not find parent of path {}", current_path.display()));
                        }
                    }
                }
            }.expect("could not find matching package");

            vec![metadata.packages.remove(package_index)]
        };

        for package in packages {
            let manifest_path = package.manifest_path;

            for target in package.targets {
                let args = std::env::args()
                    .skip(2)
                    .filter(|a| a != "--all" && !a.starts_with("--manifest-path="));

                let args = std::iter::once(format!("--manifest-path={}", manifest_path)).chain(args);
                if let Some(first) = target.kind.get(0) {
                    if target.kind.len() > 1 || first.ends_with("lib") {
                        if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args)) {
                            std::process::exit(code);
                        }
                    } else if ["bin", "example", "test", "bench"].contains(&&**first) {
                        if let Err(code) = process(
                            vec![format!("--{}", first), target.name]
                                .into_iter()
                                .chain(args),
                        ) {
                            std::process::exit(code);
                        }
                    }
                } else {
                    panic!("badly formatted cargo metadata: target::kind is an empty array");
                }
            }
        }
    } else {
        // this arm is executed when cargo-clippy runs `cargo rustc` with the `RUSTC`
        // env var set to itself

        let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
        let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
        let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) {
            format!("{}/toolchains/{}", home, toolchain)
        } else {
            option_env!("SYSROOT")
                .map(|s| s.to_owned())
                .or_else(|| {
                    Command::new("rustc")
                        .arg("--print")
                        .arg("sysroot")
                        .output()
                        .ok()
                        .and_then(|out| String::from_utf8(out.stdout).ok())
                        .map(|s| s.trim().to_owned())
                })
                .expect(
                    "need to specify SYSROOT env var during clippy compilation, or use rustup or multirust",
                )
        };

        rustc_driver::in_rustc_thread(|| {
            // this conditional check for the --sysroot flag is there so users can call
            // `cargo-clippy` directly
            // without having to pass --sysroot or anything
            let mut args: Vec<String> = if env::args().any(|s| s == "--sysroot") {
                env::args().collect()
            } else {
                env::args()
                    .chain(Some("--sysroot".to_owned()))
                    .chain(Some(sys_root))
                    .collect()
            };

            // this check ensures that dependencies are built but not linted and the final
            // crate is
            // linted but not built
            let clippy_enabled = env::args().any(|s| s == "--emit=metadata");

            if clippy_enabled {
                args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
            }

            let mut ccc = ClippyCompilerCalls::new(clippy_enabled);
            let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None);
            if let Err(CompileIncomplete::Errored(_)) = result {
                std::process::exit(1);
            }
        }).expect("rustc_thread failed");
    }
}

fn process<I>(old_args: I) -> Result<(), i32>
where
    I: Iterator<Item = String>,
{
    let mut args = vec!["rustc".to_owned()];

    let mut found_dashes = false;
    for arg in old_args {
        found_dashes |= arg == "--";
        args.push(arg);
    }
    if !found_dashes {
        args.push("--".to_owned());
    }
    args.push("--emit=metadata".to_owned());
    args.push("--cfg".to_owned());
    args.push(r#"feature="cargo-clippy""#.to_owned());

    let path = std::env::current_exe().expect("current executable path invalid");
    let exit_status = std::process::Command::new("cargo")
        .args(&args)
        .env("RUSTC", path)
        .spawn()
        .expect("could not run cargo")
        .wait()
        .expect("failed to wait for cargo?");

    if exit_status.success() {
        Ok(())
    } else {
        Err(exit_status.code().unwrap_or(-1))
    }
}
<|endoftext|>


<commit_before>use std::io::{Write, BufWriter};
use std::fs::File;

extern crate rand;
use rand::Rng;

mod vector;
mod ray;
mod sphere;
mod hitable;
mod hitable_list;
mod camera;

use vector::{Vec3, dot, cross, unit_vector};
use ray::Ray;
use sphere::{Sphere};
use hitable::{Hitable, hit_record};
use hitable_list::Hitable_list;
use camera::Camera;

fn color<T: Hitable>(ray : Ray, world : &T) -> Vec3 {
  let mut rec = hit_record::new(0.0, Vec3::origin(), Vec3::origin());
  if world.hit(ray, 0.0, std::f64::MAX, &mut rec) {
    return (rec.normal + Vec3::new(1.0, 1.0, 1.0)) * 0.5
  }
  else {
    let unit_direction = unit_vector(ray.direction());
    let t = (unit_direction.y() + 1.0) * 0.5;
    return Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t;
  }
}

fn random<T: Hitable>(i : i32, j : i32, nx : i32, ny : i32, cam : Camera, world : &T, rng : &mut rand::ThreadRng) -> Vec3 {
  let ns = 100;
  let mut col = Vec3::origin();
  for s in 0..ns {
    let u = (i as f64 + rng.gen::<f64>()) / nx as f64;
    let v = (j as f64 + rng.gen::<f64>()) / ny as f64;
    let r = cam.get_ray(u, v);

    let p = r.point_at_parameter(2.0);
    col += color(r, world);
  }

  col /= ns as f64;
  return col;
}

fn stratified<T: Hitable>(i : i32, j : i32, nx : i32, ny : i32, cam : Camera, world : &T, rng : &mut rand::ThreadRng) -> Vec3 {
  let mut col = Vec3::origin();
  let grid_size = 5;
  let step = 1.0 / grid_size as f64;
  let lowI = i as f64 - 0.5;
  let lowJ = j as f64 - 0.5;

  for ii in 0..grid_size {
    for jj in 0..grid_size {
      let u = ((lowI + ii as f64 * step) + rng.gen_range(0.0, step)) / nx as f64;
      let v = ((lowJ + jj as f64 * step) + rng.gen_range(0.0, step)) / ny as f64;
      let r = cam.get_ray(u, v);

      let p = r.point_at_parameter(2.0);
      col += color(r, world);
    }
  }

  col /= (grid_size * grid_size) as f64;
  return col;
}

fn main() {
  let nx = 200;
  let ny = 100;
  let data = format!("{}\n{} {}\n{}\n", "P3", nx, ny, 255);
  let f = File::create("target/image.ppm").expect("Unable to create file");
  let mut f = BufWriter::new(f);
  f.write_all(data.as_bytes()).expect("Unable to write data");

  let lower_left_corner = Vec3::new(-2.0, -1.0, -1.0);
  let horizontal = Vec3::new(4.0, 0.0, 0.0);
  let vertical = Vec3::new(0.0, 2.0, 0.0);
  let origin = Vec3::new(0.0, 0.0, 0.0);

  let cam = Camera::new(lower_left_corner, vertical, horizontal, origin);

  let mut list : Vec<Box<Hitable>> = Vec::new();
  list.push(Box::new(Sphere::new(Vec3::new(0.0,0.0,-1.0), 0.5)));
  list.push(Box::new(Sphere::new(Vec3::new(0.0,-100.5,-1.0), 100.0)));
  let world = Hitable_list::new(list);

  let mut rng = rand::thread_rng();

  for j in (0..ny).rev() {
    for i in 0..nx {
      let col = stratified(i, j, nx, ny, cam, &world, &mut rng);

      let ir = (255.99*col.r()) as i32;
      let ig = (255.99*col.g()) as i32;
      let ib = (255.99*col.b()) as i32;
      f.write_all(format!("{} {} {}\n", ir, ig, ib).as_bytes()).expect("Unable to write data");
    }
  }
}<commit_msg>Clean up compiler warnings in antialiasing functions<commit_after>use std::io::{Write, BufWriter};
use std::fs::File;

extern crate rand;
use rand::Rng;

mod vector;
mod ray;
mod sphere;
mod hitable;
mod hitable_list;
mod camera;

use vector::{Vec3, dot, cross, unit_vector};
use ray::Ray;
use sphere::{Sphere};
use hitable::{Hitable, hit_record};
use hitable_list::Hitable_list;
use camera::Camera;

fn color<T: Hitable>(ray : Ray, world : &T) -> Vec3 {
  let mut rec = hit_record::new(0.0, Vec3::origin(), Vec3::origin());
  if world.hit(ray, 0.0, std::f64::MAX, &mut rec) {
    return (rec.normal + Vec3::new(1.0, 1.0, 1.0)) * 0.5
  }
  else {
    let unit_direction = unit_vector(ray.direction());
    let t = (unit_direction.y() + 1.0) * 0.5;
    return Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t;
  }
}

fn random<T: Hitable>(i : i32, j : i32, nx : i32, ny : i32, cam : Camera, world : &T, rng : &mut rand::ThreadRng) -> Vec3 {
  let sample_size = 100;
  let mut samples = 0;
  let mut col = Vec3::origin();
  loop {
    let u = (i as f64 + rng.gen::<f64>()) / nx as f64;
    let v = (j as f64 + rng.gen::<f64>()) / ny as f64;
    let r = cam.get_ray(u, v);

    col += color(r, world);
    samples += 1;
    if samples >= sample_size { break; }
  }

  col /= sample_size as f64;
  return col;
}

fn stratified<T: Hitable>(i : i32, j : i32, nx : i32, ny : i32, cam : Camera, world : &T, rng : &mut rand::ThreadRng) -> Vec3 {
  let mut col = Vec3::origin();
  let grid_size = 5;
  let step = 1.0 / grid_size as f64;
  let low_i = i as f64 - 0.5;
  let low_j = j as f64 - 0.5;

  for ii in 0..grid_size {
    for jj in 0..grid_size {
      let u = ((low_i + ii as f64 * step) + rng.gen_range(0.0, step)) / nx as f64;
      let v = ((low_j + jj as f64 * step) + rng.gen_range(0.0, step)) / ny as f64;
      let r = cam.get_ray(u, v);

      col += color(r, world);
    }
  }

  col /= (grid_size * grid_size) as f64;
  return col;
}

fn main() {
  let nx = 200;
  let ny = 100;
  let data = format!("{}\n{} {}\n{}\n", "P3", nx, ny, 255);
  let f = File::create("target/image.ppm").expect("Unable to create file");
  let mut f = BufWriter::new(f);
  f.write_all(data.as_bytes()).expect("Unable to write data");

  let lower_left_corner = Vec3::new(-2.0, -1.0, -1.0);
  let horizontal = Vec3::new(4.0, 0.0, 0.0);
  let vertical = Vec3::new(0.0, 2.0, 0.0);
  let origin = Vec3::new(0.0, 0.0, 0.0);

  let cam = Camera::new(lower_left_corner, vertical, horizontal, origin);

  let mut list : Vec<Box<Hitable>> = Vec::new();
  list.push(Box::new(Sphere::new(Vec3::new(0.0,0.0,-1.0), 0.5)));
  list.push(Box::new(Sphere::new(Vec3::new(0.0,-100.5,-1.0), 100.0)));
  let world = Hitable_list::new(list);

  let mut rng = rand::thread_rng();

  for j in (0..ny).rev() {
    for i in 0..nx {
      let col = stratified(i, j, nx, ny, cam, &world, &mut rng);

      let ir = (255.99*col.r()) as i32;
      let ig = (255.99*col.g()) as i32;
      let ib = (255.99*col.b()) as i32;
      f.write_all(format!("{} {} {}\n", ir, ig, ib).as_bytes()).expect("Unable to write data");
    }
  }
}<|endoftext|>


<commit_before>extern crate ansi_term;
extern crate getopts;
extern crate isatty;
extern crate regex;
extern crate walkdir;

use std::collections::HashMap;
use std::env;
use std::error::Error;
use std::ffi::OsStr;
use std::fs::File;
use std::io::{Write, BufReader,BufRead};
use std::path::{Path, Component};
use std::process;

use ansi_term::{Style, Colour};
use getopts::Options;
use isatty::stdout_isatty;
use regex::{Regex, RegexBuilder};
use walkdir::{WalkDir, DirEntry, WalkDirIterator};

/// Maps file extensions to ANSI colors / styles.
type ExtensionStyles = HashMap<String, ansi_term::Style>;

/// Configuration options for *fd*.
struct FdOptions {
    case_sensitive: bool,
    search_full_path: bool,
    search_hidden: bool,
    follow_links: bool,
    colored: bool,
    max_depth: usize,
    extension_styles: Option<ExtensionStyles>
}

/// The default maximum recursion depth.
const MAX_DEPTH_DEFAULT : usize = 25;

/// Print a search result to the console.
fn print_entry(path_root: &Path, path_entry: &Path, config: &FdOptions) {
    let path_full = path_root.join(path_entry);

    let path_str = match path_entry.to_str() {
        Some(p) => p,
        None    => return
    };

    if !config.colored {
        println!("{}", path_str);
    } else {
        let mut component_path = path_root.to_path_buf();

        // Traverse the path and colorize each component
        for component in path_entry.components() {
            let comp_str = match component {
                Component::Normal(p) => p,
                _                    => error("Unexpected path component")
            };

            component_path.push(Path::new(comp_str));

            let style =
                if component_path.symlink_metadata()
                                 .map(|md| md.file_type().is_symlink())
                                 .unwrap_or(false) {
                    Colour::Cyan.normal()
                } else if component_path.is_dir() {
                    Colour::Blue.bold()
                } else {
                    // Loop up file extension
                    if let Some(ref ext_styles) = config.extension_styles {
                        component_path.extension()
                                      .and_then(|e| e.to_str())
                                      .and_then(|e| ext_styles.get(e))
                                      .map(|r| r.clone())
                                      .unwrap_or(Style::new())
                    }
                    else {
                        Style::new()
                    }
                };

            print!("{}", style.paint(comp_str.to_str().unwrap()));

            if component_path.is_dir() && component_path != path_full {
                let sep = std::path::MAIN_SEPARATOR.to_string();
                print!("{}", style.paint(sep));
            }
        }
        println!();
    }
}

/// Check if filename of entry starts with a dot.
fn is_hidden(entry: &DirEntry) -> bool {
    entry.file_name()
         .to_str()
         .map(|s| s.starts_with("."))
         .unwrap_or(false)
}

/// Recursively scan the given root path and search for files / pathnames
/// matching the pattern.
fn scan(root: &Path, pattern: &Regex, config: &FdOptions) {
    let walker = WalkDir::new(root)
                     .follow_links(config.follow_links)
                     .max_depth(config.max_depth)
                     .into_iter()
                     .filter_entry(|e| config.search_hidden || !is_hidden(e))
                     .filter_map(|e| e.ok())
                     .filter(|e| e.path() != root);

    for entry in walker {
        let path_rel = match entry.path().strip_prefix(root) {
            Ok(p) => p,
            Err(_) => continue
        };

        let search_str =
            if config.search_full_path {
                path_rel.to_str()
            } else {
                if !path_rel.is_file() { continue }

                path_rel.file_name()
                        .and_then(OsStr::to_str)
            };

        search_str.and_then(|s| pattern.find(s))
                  .map(|_| print_entry(&root, path_rel, &config));
    }
}

/// Print error message to stderr and exit with status `1`.
fn error(message: &str) -> ! {
    writeln!(&mut std::io::stderr(), "{}", message)
        .expect("Failed writing to stderr");
    process::exit(1);
}

/// Parse `dircolors` file.
fn parse_dircolors(path: &Path) -> std::io::Result<ExtensionStyles> {
    let file = File::open(path)?;
    let mut ext_styles = HashMap::new();

    let pattern_ansi_256 =
        Regex::new(r"^\.([A-Za-z0-9]+)\s*(?:00;)?38;5;([0-9]+)\b")
            .unwrap();

    let pattern_ansi =
        Regex::new(r"^\.([A-Za-z0-9]+)\s*([0-9][0-9]);([0-9][0-9])\b")
            .unwrap();

    for line in BufReader::new(file).lines() {
        let line_s = line.unwrap();
        if let Some(caps) = pattern_ansi_256.captures(line_s.as_str()) {
            if let Some(ext) = caps.get(1).map(|m| m.as_str()) {
                let fg = caps.get(2)
                             .map(|m| m.as_str())
                             .and_then(|n| u8::from_str_radix(n, 10).ok())
                             .unwrap_or(7); // white
                ext_styles.insert(String::from(ext),
                                  Colour::Fixed(fg).normal());
            }
        } else if let Some(caps) = pattern_ansi.captures(line_s.as_str()) {
            if let Some(ext) = caps.get(1).map(|m| m.as_str()) {
                let color_s = caps.get(3)
                                  .map_or("", |m| m.as_str());
                let color = match color_s {
                    "31" => Colour::Red,
                    "32" => Colour::Green,
                    "33" => Colour::Yellow,
                    "34" => Colour::Blue,
                    "35" => Colour::Purple,
                    "36" => Colour::Cyan,
                    _    => Colour::White
                };
                let style_s = caps.get(2)
                                  .map_or("", |m| m.as_str());
                let style = match style_s {
                    "01" => color.bold(),
                    "03" => color.italic(),
                    "04" => color.underline(),
                    _    => color.normal()
                };
                ext_styles.insert(String::from(ext), style);
            }
        }
    }
    Ok(ext_styles)
}

fn main() {
    let args: Vec<String> = env::args().collect();

    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help message");
    opts.optflag("s", "sensitive",
                      "case-sensitive search (default: smart case)");
    opts.optflag("f", "filename",
                      "search filenames only (default: full path)");
    opts.optflag("H", "hidden",
                      "search hidden files/directories (default: off)");
    opts.optflag("F", "follow", "follow symlinks (default: off)");
    opts.optflag("n", "no-color", "do not colorize output (default: on)");
    opts.optopt("d", "max-depth",
                     format!("maximum search depth (default: {})",
                             MAX_DEPTH_DEFAULT).as_str(),
                     "D");

    let matches = match opts.parse(&args[1..]) {
        Ok(m)  => m,
        Err(e) => error(e.description())
    };

    if matches.opt_present("h") {
        let brief = "Usage: fd [options] [PATTERN]";
        print!("{}", opts.usage(&brief));
        process::exit(1);
    }

    let empty = String::new();
    let pattern = matches.free.get(0).unwrap_or(&empty);

    let current_dir_buf = match env::current_dir() {
        Ok(cd) => cd,
        Err(_) => error("Could not get current directory!")
    };
    let current_dir = current_dir_buf.as_path();

    let ext_styles = env::home_dir()
                         .map(|h| h.join(".dir_colors"))
                         .and_then(|path| parse_dircolors(&path).ok());

    let config = FdOptions {
        // The search will be case-sensitive if the command line flag is set or
        // if the pattern has an uppercase character (smart case).
        case_sensitive:    matches.opt_present("sensitive") ||
                           pattern.chars().any(char::is_uppercase),
        search_full_path: !matches.opt_present("filename"),
        search_hidden:     matches.opt_present("hidden"),
        colored:          !matches.opt_present("no-color") &&
                           stdout_isatty(),
        follow_links:      matches.opt_present("follow"),
        max_depth:
            matches.opt_str("max-depth")
                   .and_then(|ds| usize::from_str_radix(&ds, 10).ok())
                   .unwrap_or(MAX_DEPTH_DEFAULT),
        extension_styles:  ext_styles
    };

    match RegexBuilder::new(pattern)
              .case_insensitive(!config.case_sensitive)
              .build() {
        Ok(re)   => scan(&current_dir, &re, &config),
        Err(err) => error(err.description())
    }
}
<commit_msg>Small fix for ANSI code regex<commit_after>extern crate ansi_term;
extern crate getopts;
extern crate isatty;
extern crate regex;
extern crate walkdir;

use std::collections::HashMap;
use std::env;
use std::error::Error;
use std::ffi::OsStr;
use std::fs::File;
use std::io::{Write, BufReader,BufRead};
use std::path::{Path, Component};
use std::process;

use ansi_term::{Style, Colour};
use getopts::Options;
use isatty::stdout_isatty;
use regex::{Regex, RegexBuilder};
use walkdir::{WalkDir, DirEntry, WalkDirIterator};

/// Maps file extensions to ANSI colors / styles.
type ExtensionStyles = HashMap<String, ansi_term::Style>;

/// Configuration options for *fd*.
struct FdOptions {
    case_sensitive: bool,
    search_full_path: bool,
    search_hidden: bool,
    follow_links: bool,
    colored: bool,
    max_depth: usize,
    extension_styles: Option<ExtensionStyles>
}

/// The default maximum recursion depth.
const MAX_DEPTH_DEFAULT : usize = 25;

/// Print a search result to the console.
fn print_entry(path_root: &Path, path_entry: &Path, config: &FdOptions) {
    let path_full = path_root.join(path_entry);

    let path_str = match path_entry.to_str() {
        Some(p) => p,
        None    => return
    };

    if !config.colored {
        println!("{}", path_str);
    } else {
        let mut component_path = path_root.to_path_buf();

        // Traverse the path and colorize each component
        for component in path_entry.components() {
            let comp_str = match component {
                Component::Normal(p) => p,
                _                    => error("Unexpected path component")
            };

            component_path.push(Path::new(comp_str));

            let style =
                if component_path.symlink_metadata()
                                 .map(|md| md.file_type().is_symlink())
                                 .unwrap_or(false) {
                    Colour::Cyan.normal()
                } else if component_path.is_dir() {
                    Colour::Blue.bold()
                } else {
                    // Loop up file extension
                    if let Some(ref ext_styles) = config.extension_styles {
                        component_path.extension()
                                      .and_then(|e| e.to_str())
                                      .and_then(|e| ext_styles.get(e))
                                      .map(|r| r.clone())
                                      .unwrap_or(Style::new())
                    }
                    else {
                        Style::new()
                    }
                };

            print!("{}", style.paint(comp_str.to_str().unwrap()));

            if component_path.is_dir() && component_path != path_full {
                let sep = std::path::MAIN_SEPARATOR.to_string();
                print!("{}", style.paint(sep));
            }
        }
        println!();
    }
}

/// Check if filename of entry starts with a dot.
fn is_hidden(entry: &DirEntry) -> bool {
    entry.file_name()
         .to_str()
         .map(|s| s.starts_with("."))
         .unwrap_or(false)
}

/// Recursively scan the given root path and search for files / pathnames
/// matching the pattern.
fn scan(root: &Path, pattern: &Regex, config: &FdOptions) {
    let walker = WalkDir::new(root)
                     .follow_links(config.follow_links)
                     .max_depth(config.max_depth)
                     .into_iter()
                     .filter_entry(|e| config.search_hidden || !is_hidden(e))
                     .filter_map(|e| e.ok())
                     .filter(|e| e.path() != root);

    for entry in walker {
        let path_rel = match entry.path().strip_prefix(root) {
            Ok(p) => p,
            Err(_) => continue
        };

        let search_str =
            if config.search_full_path {
                path_rel.to_str()
            } else {
                if !path_rel.is_file() { continue }

                path_rel.file_name()
                        .and_then(OsStr::to_str)
            };

        search_str.and_then(|s| pattern.find(s))
                  .map(|_| print_entry(&root, path_rel, &config));
    }
}

/// Print error message to stderr and exit with status `1`.
fn error(message: &str) -> ! {
    writeln!(&mut std::io::stderr(), "{}", message)
        .expect("Failed writing to stderr");
    process::exit(1);
}

/// Parse `dircolors` file.
fn parse_dircolors(path: &Path) -> std::io::Result<ExtensionStyles> {
    let file = File::open(path)?;
    let mut ext_styles = HashMap::new();

    let pattern_ansi_256 =
        Regex::new(r"^\.([A-Za-z0-9]+)\s*(?:00;)?38;5;([0-9]+)\b")
            .unwrap();

    let pattern_ansi =
        Regex::new(r"^\.([A-Za-z0-9]+)\s*(?:([0-9][0-9]);)?([0-9][0-9])\b")
            .unwrap();

    for line in BufReader::new(file).lines() {
        let line_s = line.unwrap();
        if let Some(caps) = pattern_ansi_256.captures(line_s.as_str()) {
            if let Some(ext) = caps.get(1).map(|m| m.as_str()) {
                let fg = caps.get(2)
                             .map(|m| m.as_str())
                             .and_then(|n| u8::from_str_radix(n, 10).ok())
                             .unwrap_or(7); // white
                ext_styles.insert(String::from(ext),
                                  Colour::Fixed(fg).normal());
            }
        } else if let Some(caps) = pattern_ansi.captures(line_s.as_str()) {
            if let Some(ext) = caps.get(1).map(|m| m.as_str()) {
                let color_s = caps.get(3)
                                  .map_or("", |m| m.as_str());
                let color = match color_s {
                    "31" => Colour::Red,
                    "32" => Colour::Green,
                    "33" => Colour::Yellow,
                    "34" => Colour::Blue,
                    "35" => Colour::Purple,
                    "36" => Colour::Cyan,
                    _    => Colour::White
                };
                let style_s = caps.get(2)
                                  .map_or("", |m| m.as_str());
                let style = match style_s {
                    "01" => color.bold(),
                    "03" => color.italic(),
                    "04" => color.underline(),
                    _    => color.normal()
                };
                ext_styles.insert(String::from(ext), style);
            }
        }
    }
    Ok(ext_styles)
}

fn main() {
    let args: Vec<String> = env::args().collect();

    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help message");
    opts.optflag("s", "sensitive",
                      "case-sensitive search (default: smart case)");
    opts.optflag("f", "filename",
                      "search filenames only (default: full path)");
    opts.optflag("H", "hidden",
                      "search hidden files/directories (default: off)");
    opts.optflag("F", "follow", "follow symlinks (default: off)");
    opts.optflag("n", "no-color", "do not colorize output (default: on)");
    opts.optopt("d", "max-depth",
                     format!("maximum search depth (default: {})",
                             MAX_DEPTH_DEFAULT).as_str(),
                     "D");

    let matches = match opts.parse(&args[1..]) {
        Ok(m)  => m,
        Err(e) => error(e.description())
    };

    if matches.opt_present("h") {
        let brief = "Usage: fd [options] [PATTERN]";
        print!("{}", opts.usage(&brief));
        process::exit(1);
    }

    let empty = String::new();
    let pattern = matches.free.get(0).unwrap_or(&empty);

    let current_dir_buf = match env::current_dir() {
        Ok(cd) => cd,
        Err(_) => error("Could not get current directory!")
    };
    let current_dir = current_dir_buf.as_path();

    let ext_styles = env::home_dir()
                         .map(|h| h.join(".dir_colors"))
                         .and_then(|path| parse_dircolors(&path).ok());

    let config = FdOptions {
        // The search will be case-sensitive if the command line flag is set or
        // if the pattern has an uppercase character (smart case).
        case_sensitive:    matches.opt_present("sensitive") ||
                           pattern.chars().any(char::is_uppercase),
        search_full_path: !matches.opt_present("filename"),
        search_hidden:     matches.opt_present("hidden"),
        colored:          !matches.opt_present("no-color") &&
                           stdout_isatty(),
        follow_links:      matches.opt_present("follow"),
        max_depth:
            matches.opt_str("max-depth")
                   .and_then(|ds| usize::from_str_radix(&ds, 10).ok())
                   .unwrap_or(MAX_DEPTH_DEFAULT),
        extension_styles:  ext_styles
    };

    match RegexBuilder::new(pattern)
              .case_insensitive(!config.case_sensitive)
              .build() {
        Ok(re)   => scan(&current_dir, &re, &config),
        Err(err) => error(err.description())
    }
}
<|endoftext|>


<commit_before>extern crate iron;
#[macro_use]
extern crate router;
extern crate staticfile;
extern crate mount;
extern crate urlencoded;
extern crate rustc_serialize;
extern crate html5ever;
extern crate regex;
extern crate uuid;
extern crate chrono;
extern crate bodyparser;
extern crate serde_json;

use std::net::SocketAddrV4;
use std::net::Ipv4Addr;
use std::path::Path;
use iron::prelude::*;
use iron::status;
use iron::mime::Mime;
use staticfile::Static;
use mount::Mount;
use router::{Router};
use urlencoded::UrlEncodedQuery;
use urlencoded::UrlEncodedBody;
use std::str::FromStr;
use uuid::Uuid;

#[macro_use]
extern crate string_cache;
extern crate pink_spider;

use pink_spider::error::Error;
use pink_spider::scraper::extract;
use pink_spider::model::{Model, Track, Playlist, Album, Artist, Entry, Enclosure, Provider, PaginatedCollection};
use rustc_serialize::json::{ToJson, Json};
use pink_spider::get_env;

pub fn index_entries(req: &mut Request) -> IronResult<Response> {
    let (page, per_page) = pagination_params(req);
    let entries          = Entry::find(page, per_page);
    let json_obj: Json   = entries.to_json();
    let json_str: String = json_obj.to_string();
    Ok(Response::with((status::Ok, application_json(), json_str)))
}

pub fn index<T: Model>(req: &mut Request) -> IronResult<Response> {
    let (page, per_page) = pagination_params(req);
    let enclosures       = T::find(page, per_page);
    let json_obj: Json   = enclosures.to_json();
    let json_str: String = json_obj.to_string();
    Ok(Response::with((status::Ok, application_json(), json_str)))
}

pub fn mget<T: Model>(req: &mut Request) -> IronResult<Response> {
    let ids              = try!(params_as_uuid_array(req));
    let items            = try!(T::mget(ids));
    let json_obj: Json   = items.to_json();
    let json_str: String = json_obj.to_string();
    Ok(Response::with((status::Ok, application_json(), json_str)))
}

fn params_as_uuid_array(req: &mut Request) -> IronResult<Vec<Uuid>> {
    match req.get::<bodyparser::Json>() {
        Ok(Some(serde_json::Value::Array(ids))) =>
            Ok(ids
               .iter()
               .map(|v| Uuid::parse_str(v.as_str().unwrap_or("")))
               .filter(|opt| opt.is_ok())
               .map(|opt| opt.unwrap())
               .collect()),
        _ => Err(IronError::from(Error::Unprocessable)),
    }
}

pub fn index_by_entry<T: Enclosure>(req: &mut Request) -> IronResult<Response> {
    let ref entry_id = req.extensions.get::<Router>().unwrap().find("entry_id").unwrap();
    let uuid = try!(Uuid::parse_str(entry_id).map_err(|_| Error::Unprocessable));
    let items = T::find_by_entry_id(uuid);
    let col = PaginatedCollection {
        page:     0,
        per_page: items.len() as i64,
        total:    items.len() as i64,
        items:    items,
    };
    let json_obj: Json   = col.to_json();
    let json_str: String = json_obj.to_string();
    Ok(Response::with((status::Ok, application_json(), json_str)))
}

pub fn legacy_playlistify(req: &mut Request) -> IronResult<Response> {
    pub fn playlistify2(req: &mut Request) -> Result<Response, Error> {
        let ref params  = try!(req.get_ref::<UrlEncodedQuery>());
        let url         = try!(params.get("url").ok_or(Error::BadRequest));
        let defaults    = &vec!("false".to_string());
        let force_param = params.get("force").unwrap_or(defaults);
        let force       = force_param.len() > 0 && &force_param[0] == "true";
        let mut entry   = try!(find_or_playlistify_entry(&url[0], force));
        entry.tracks    = entry.tracks
            .iter()
            .filter(|t| t.provider == Provider::YouTube || t.provider == Provider::SoundCloud)
            .map(|t| t.clone())
            .collect();
        let json_obj    = entry.to_json() as Json;
        let json_str    = json_obj.to_string() as String;
        Ok(Response::with((status::Ok, application_json(), json_str)))
    }
    playlistify2(req).map_err(|err| IronError::from(err))
}

pub fn playlistify(req: &mut Request) -> IronResult<Response> {
    pub fn playlistify2(req: &mut Request) -> Result<Response, Error> {
        let ref params  = try!(req.get_ref::<UrlEncodedQuery>());
        let url         = try!(params.get("url").ok_or(Error::BadRequest));
        let defaults    = &vec!("false".to_string());
        let force_param = params.get("force").unwrap_or(defaults);
        let force       = force_param.len() > 0 && &force_param[0] == "true";
        let entry       = try!(find_or_playlistify_entry(&url[0], force));
        let json_obj    = entry.to_json() as Json;
        let json_str    = json_obj.to_string() as String;
        Ok(Response::with((status::Ok, application_json(), json_str)))
    }
    playlistify2(req).map_err(|err| IronError::from(err))
}

pub fn find_or_playlistify_entry(url: &str, force: bool) -> Result<Entry, Error> {
    match Entry::find_by_url(url) {
        Ok(entry) => {
            println!("Get entry from database cache: {}", url);
            if force {
                println!("Update entry: {}", url);
                let entry = try!(playlistify_entry(entry));
                Ok(entry)
            } else {
                Ok(entry)
            }
        },
        Err(_) => {
            let entry = try!(Entry::create_by_url(url.to_string()));
            let entry = try!(playlistify_entry(entry));
            println!("Create new entry to database cache: {}", url);
            Ok(entry)
        },
    }
}

pub fn playlistify_entry(entry: Entry) -> Result<Entry, Error> {
    let mut e = entry.clone();
    let product = try!(extract(&entry.url));
    match product.og_obj {
        Some(og_obj) => {
            e.title       = Some(og_obj.title);
            e.description = og_obj.description;
            e.locale      = og_obj.locale;
            e.visual_url  = og_obj.images.first().map(|i| i.url.clone());
        },
        None => (),
    }
    for t in product.tracks {
        let new_track = try!(Track::find_or_create(t.provider, t.identifier.to_string()));
        let mut track = t.clone();
        track.id      = new_track.id;
        try!(track.fetch_detail().save());
        match entry.tracks.iter().find(|&t| t.id == track.id) {
            Some(_) => (),
            None    => try!(e.add_track(track.clone())),
        }
    }
    for p in product.playlists {
        let new_playlist = try!(Playlist::find_or_create(p.provider, p.identifier.to_string()));
        let mut playlist = p.clone();
        playlist.id      = new_playlist.id;
        try!(playlist.save());
        match entry.playlists.iter().find(|&p| p.id == playlist.id) {
            Some(_) => (),
            None    => try!(e.add_playlist(playlist.clone())),
        }
    }
    for a in product.albums {
        let new_album = try!(Album::find_or_create(a.provider, a.identifier.to_string()));
        let mut album = a.clone();
        album.id      = new_album.id;
        try!(album.save());
        match entry.albums.iter().find(|&a| a.id == album.id) {
            Some(_) => (),
            None    => try!(e.add_album(album.clone())),
        }
    }
    try!(e.save());
    Ok(e)
}

pub fn update<T: Enclosure>(req: &mut Request) -> IronResult<Response> {
    let mut enclosure = try!(T::find_by_id(&query_as_string(req, "id")));
    try!(enclosure.fetch_props().save());
    let res = enclosure.to_json().to_string();
    Ok(Response::with((status::Ok, application_json(), res)))
}

pub fn show<T: Enclosure>(req: &mut Request) -> IronResult<Response> {
    let provider   = req.extensions.get::<Router>().unwrap().find("provider").unwrap();
    let identifier = req.extensions.get::<Router>().unwrap().find("id").unwrap();
    let p = &Provider::new(provider.to_string());
    match T::find_by(p, identifier) {
        Ok(enclosure) => {
            Ok(Response::with((status::Ok,
                               application_json(),
                               enclosure.to_json().to_string())))
        },
        Err(e) => Ok(e.as_response())
    }
}

pub fn show_by_id<T: Model>(req: &mut Request) -> IronResult<Response> {
    let ref id = req.extensions.get::<Router>().unwrap().find("id").unwrap();
    match T::find_by_id(id) {
        Ok(enclosure) => {
            Ok(Response::with((status::Ok,
                               application_json(),
                               enclosure.to_json().to_string())))
        },
        Err(e) => Ok(e.as_response())
    }
}

fn param_as_string(req: &mut Request, key: &str) -> Option<String> {
    match req.get_ref::<UrlEncodedBody>() {
        Ok(ref params) => match params.get(key) {
            Some(val) => Some(val[0].clone()),
            None      => None
        },
        Err(_) => None
    }
}

fn query_as_string(req: &mut Request, key: &str) -> String {
    return req.extensions.get::<Router>().unwrap()
        .find(key).unwrap().to_string();
}

fn pagination_params(req: &mut Request) -> (i64, i64) {
    match req.get_ref::<UrlEncodedQuery>() {
        Ok(ref params) =>
            (params.get("page").unwrap()[0].to_string().parse::<i64>().unwrap(),
             params.get("per_page").unwrap()[0].to_string().parse::<i64>().unwrap()),
        Err(_) =>
            (0, 10)
    }
}

fn application_json() -> Mime {
    Mime::from_str("application/json").ok().unwrap()
}

pub fn main() {
    let path = Path::new("public");
    let mut mount = Mount::new();
    mount.mount("/web/", Static::new(Path::new(path)));
    let router = router!(
        web:                      get  "/*"                        => mount,
        legacy_playlistify:       get  "/playlistify"                    => legacy_playlistify,
        playlistify:              get  "/v1/playlistify"                 => playlistify,
        index_entries:            get  "/v1/entries"                     => index_entries,
        index_artists:            get  "/v1/artists"                     => index::<Artist>,
        mget_artists:             post "/v1/artists/.mget"               => mget::<Artist>,

        show_track_by_id:         get  "/v1/tracks/:id"                  => show_by_id::<Track>,
        show_track:               get  "/v1/tracks/:provider/:id"        => show::<Track>,
        mget_tracks:              post "/v1/tracks/.mget"                => mget::<Track>,
        update_track:             post "/v1/tracks/:id"                  => update::<Track>,
        index_tracks:             get  "/v1/tracks"                      => index::<Track>,
        index_tracks_by_entry:    get  "/v1/entries/:entry_id/tracks"    => index_by_entry::<Track>,

        show_playlist_by_id:      get  "/v1/playlists/:id"               => show_by_id::<Playlist>,
        show_playlist:            get  "/v1/playlists/:provider/:id"     => show::<Playlist>,
        update_playlist:          post "/v1/playlists/:id"               => update::<Playlist>,
        mget_playlists:           post "/v1/playlists/.mget"             => mget::<Playlist>,
        index_playlists:          get  "/v1/playlists"                   => index::<Playlist>,
        index_playlists_by_entry: get  "/v1/entries/:entry_id/playlists" => index_by_entry::<Playlist>,

        show_album_by_id:         get  "/v1/albums/:id"                  => show_by_id::<Album>,
        show_album:               get  "/v1/albums/:provider/:id"        => show::<Album>,
        mget_albums:              post "/v1/albums/.mget"                => mget::<Album>,
        update_album:             post "/v1/albums/:id"                  => update::<Album>,
        index_albums:             get  "/v1/albums"                      => index::<Album>,
        index_albums_by_entry:    get  "/v1/entries/:entry_id/albums"    => index_by_entry::<Album>,
    );
    let port_str = match get_env::var("PORT") {
        Some(n) => n,
        None    => "8080".to_string()
    };
    let port: u16 = match port_str.trim().parse() {
        Ok(n) => n,
        Err(_) => {
            println!("Faild to parse port");
            return;
        }
    };
    println!("PORT {}", port_str);
    let ip = Ipv4Addr::new(0, 0, 0, 0);
    Iron::new(router).http(SocketAddrV4::new(ip, port)).unwrap();
}
<commit_msg>Implement create enclosure api<commit_after>extern crate iron;
#[macro_use]
extern crate router;
extern crate staticfile;
extern crate mount;
extern crate urlencoded;
extern crate rustc_serialize;
extern crate html5ever;
extern crate regex;
extern crate uuid;
extern crate chrono;
extern crate bodyparser;
extern crate serde_json;

use std::net::SocketAddrV4;
use std::net::Ipv4Addr;
use std::path::Path;
use iron::prelude::*;
use iron::status;
use iron::mime::Mime;
use staticfile::Static;
use mount::Mount;
use router::{Router};
use urlencoded::UrlEncodedQuery;
use urlencoded::UrlEncodedBody;
use std::str::FromStr;
use uuid::Uuid;

#[macro_use]
extern crate string_cache;
extern crate pink_spider;

use pink_spider::error::Error;
use pink_spider::scraper::extract;
use pink_spider::model::{Model, Track, Playlist, Album, Artist, Entry, Enclosure, Provider, PaginatedCollection};
use rustc_serialize::json::{ToJson, Json};
use pink_spider::get_env;

pub fn index_entries(req: &mut Request) -> IronResult<Response> {
    let (page, per_page) = pagination_params(req);
    let entries          = Entry::find(page, per_page);
    let json_obj: Json   = entries.to_json();
    let json_str: String = json_obj.to_string();
    Ok(Response::with((status::Ok, application_json(), json_str)))
}

pub fn index<T: Model>(req: &mut Request) -> IronResult<Response> {
    let (page, per_page) = pagination_params(req);
    let enclosures       = T::find(page, per_page);
    let json_obj: Json   = enclosures.to_json();
    let json_str: String = json_obj.to_string();
    Ok(Response::with((status::Ok, application_json(), json_str)))
}

pub fn mget<T: Model>(req: &mut Request) -> IronResult<Response> {
    let ids              = try!(params_as_uuid_array(req));
    let items            = try!(T::mget(ids));
    let json_obj: Json   = items.to_json();
    let json_str: String = json_obj.to_string();
    Ok(Response::with((status::Ok, application_json(), json_str)))
}

fn params_as_uuid_array(req: &mut Request) -> IronResult<Vec<Uuid>> {
    match req.get::<bodyparser::Json>() {
        Ok(Some(serde_json::Value::Array(ids))) =>
            Ok(ids
               .iter()
               .map(|v| Uuid::parse_str(v.as_str().unwrap_or("")))
               .filter(|opt| opt.is_ok())
               .map(|opt| opt.unwrap())
               .collect()),
        _ => Err(IronError::from(Error::Unprocessable)),
    }
}

pub fn index_by_entry<T: Enclosure>(req: &mut Request) -> IronResult<Response> {
    let ref entry_id = req.extensions.get::<Router>().unwrap().find("entry_id").unwrap();
    let uuid = try!(Uuid::parse_str(entry_id).map_err(|_| Error::Unprocessable));
    let items = T::find_by_entry_id(uuid);
    let col = PaginatedCollection {
        page:     0,
        per_page: items.len() as i64,
        total:    items.len() as i64,
        items:    items,
    };
    let json_obj: Json   = col.to_json();
    let json_str: String = json_obj.to_string();
    Ok(Response::with((status::Ok, application_json(), json_str)))
}

pub fn legacy_playlistify(req: &mut Request) -> IronResult<Response> {
    pub fn playlistify2(req: &mut Request) -> Result<Response, Error> {
        let ref params  = try!(req.get_ref::<UrlEncodedQuery>());
        let url         = try!(params.get("url").ok_or(Error::BadRequest));
        let defaults    = &vec!("false".to_string());
        let force_param = params.get("force").unwrap_or(defaults);
        let force       = force_param.len() > 0 && &force_param[0] == "true";
        let mut entry   = try!(find_or_playlistify_entry(&url[0], force));
        entry.tracks    = entry.tracks
            .iter()
            .filter(|t| t.provider == Provider::YouTube || t.provider == Provider::SoundCloud)
            .map(|t| t.clone())
            .collect();
        let json_obj    = entry.to_json() as Json;
        let json_str    = json_obj.to_string() as String;
        Ok(Response::with((status::Ok, application_json(), json_str)))
    }
    playlistify2(req).map_err(|err| IronError::from(err))
}

pub fn playlistify(req: &mut Request) -> IronResult<Response> {
    pub fn playlistify2(req: &mut Request) -> Result<Response, Error> {
        let ref params  = try!(req.get_ref::<UrlEncodedQuery>());
        let url         = try!(params.get("url").ok_or(Error::BadRequest));
        let defaults    = &vec!("false".to_string());
        let force_param = params.get("force").unwrap_or(defaults);
        let force       = force_param.len() > 0 && &force_param[0] == "true";
        let entry       = try!(find_or_playlistify_entry(&url[0], force));
        let json_obj    = entry.to_json() as Json;
        let json_str    = json_obj.to_string() as String;
        Ok(Response::with((status::Ok, application_json(), json_str)))
    }
    playlistify2(req).map_err(|err| IronError::from(err))
}

pub fn find_or_playlistify_entry(url: &str, force: bool) -> Result<Entry, Error> {
    match Entry::find_by_url(url) {
        Ok(entry) => {
            println!("Get entry from database cache: {}", url);
            if force {
                println!("Update entry: {}", url);
                let entry = try!(playlistify_entry(entry));
                Ok(entry)
            } else {
                Ok(entry)
            }
        },
        Err(_) => {
            let entry = try!(Entry::create_by_url(url.to_string()));
            let entry = try!(playlistify_entry(entry));
            println!("Create new entry to database cache: {}", url);
            Ok(entry)
        },
    }
}

pub fn playlistify_entry(entry: Entry) -> Result<Entry, Error> {
    let mut e = entry.clone();
    let product = try!(extract(&entry.url));
    match product.og_obj {
        Some(og_obj) => {
            e.title       = Some(og_obj.title);
            e.description = og_obj.description;
            e.locale      = og_obj.locale;
            e.visual_url  = og_obj.images.first().map(|i| i.url.clone());
        },
        None => (),
    }
    for t in product.tracks {
        let new_track = try!(Track::find_or_create(t.provider, t.identifier.to_string()));
        let mut track = t.clone();
        track.id      = new_track.id;
        try!(track.fetch_detail().save());
        match entry.tracks.iter().find(|&t| t.id == track.id) {
            Some(_) => (),
            None    => try!(e.add_track(track.clone())),
        }
    }
    for p in product.playlists {
        let new_playlist = try!(Playlist::find_or_create(p.provider, p.identifier.to_string()));
        let mut playlist = p.clone();
        playlist.id      = new_playlist.id;
        try!(playlist.save());
        match entry.playlists.iter().find(|&p| p.id == playlist.id) {
            Some(_) => (),
            None    => try!(e.add_playlist(playlist.clone())),
        }
    }
    for a in product.albums {
        let new_album = try!(Album::find_or_create(a.provider, a.identifier.to_string()));
        let mut album = a.clone();
        album.id      = new_album.id;
        try!(album.save());
        match entry.albums.iter().find(|&a| a.id == album.id) {
            Some(_) => (),
            None    => try!(e.add_album(album.clone())),
        }
    }
    try!(e.save());
    Ok(e)
}

pub fn update<T: Enclosure>(req: &mut Request) -> IronResult<Response> {
    let mut enclosure = try!(T::find_by_id(&query_as_string(req, "id")));
    try!(enclosure.fetch_props().save());
    let res = enclosure.to_json().to_string();
    Ok(Response::with((status::Ok, application_json(), res)))
}

pub fn show<T: Enclosure>(req: &mut Request) -> IronResult<Response> {
    let provider   = req.extensions.get::<Router>().unwrap().find("provider").unwrap();
    let identifier = req.extensions.get::<Router>().unwrap().find("id").unwrap();
    let p = &Provider::new(provider.to_string());
    match T::find_by(p, identifier) {
        Ok(enclosure) => {
            Ok(Response::with((status::Ok,
                               application_json(),
                               enclosure.to_json().to_string())))
        },
        Err(e) => Ok(e.as_response())
    }
}

pub fn show_by_id<T: Model>(req: &mut Request) -> IronResult<Response> {
    let ref id = req.extensions.get::<Router>().unwrap().find("id").unwrap();
    match T::find_by_id(id) {
        Ok(enclosure) => {
            Ok(Response::with((status::Ok,
                               application_json(),
                               enclosure.to_json().to_string())))
        },
        Err(e) => Ok(e.as_response())
    }
}

pub fn create<T: Enclosure>(req: &mut Request) -> IronResult<Response> {
    let identifier     = try!(param_as_string(req, "identifier").ok_or(Error::BadRequest));
    let provider       = try!(param_as_string(req, "provider").ok_or(Error::BadRequest));
    let owner_id       = param_as_string(req, "owner_id");
    let url            = param_as_string(req, "url");
    let p              = Provider::new(provider.to_string());
    let mut enclosure  = T::new(p, identifier.to_string());
    enclosure.set_owner_id(owner_id);
    if let Some(url) = url {
        enclosure.set_url(url);
    }
    enclosure.fetch_props();
    try!(enclosure.save());
    Ok(Response::with((status::Ok,
                       application_json(),
                       enclosure.to_json().to_string())))
}

fn param_as_string(req: &mut Request, key: &str) -> Option<String> {
    match req.get_ref::<UrlEncodedBody>() {
        Ok(ref params) => match params.get(key) {
            Some(val) => Some(val[0].clone()),
            None      => None
        },
        Err(_) => None
    }
}

fn query_as_string(req: &mut Request, key: &str) -> String {
    return req.extensions.get::<Router>().unwrap()
        .find(key).unwrap().to_string();
}

fn pagination_params(req: &mut Request) -> (i64, i64) {
    match req.get_ref::<UrlEncodedQuery>() {
        Ok(ref params) =>
            (params.get("page").unwrap()[0].to_string().parse::<i64>().unwrap(),
             params.get("per_page").unwrap()[0].to_string().parse::<i64>().unwrap()),
        Err(_) =>
            (0, 10)
    }
}

fn application_json() -> Mime {
    Mime::from_str("application/json").ok().unwrap()
}

pub fn main() {
    let path = Path::new("public");
    let mut mount = Mount::new();
    mount.mount("/web/", Static::new(Path::new(path)));
    let router = router!(
        web:                      get  "/*"                        => mount,
        legacy_playlistify:       get  "/playlistify"                    => legacy_playlistify,
        playlistify:              get  "/v1/playlistify"                 => playlistify,
        index_entries:            get  "/v1/entries"                     => index_entries,
        index_artists:            get  "/v1/artists"                     => index::<Artist>,
        mget_artists:             post "/v1/artists/.mget"               => mget::<Artist>,

        show_track_by_id:         get  "/v1/tracks/:id"                  => show_by_id::<Track>,
        show_track:               get  "/v1/tracks/:provider/:id"        => show::<Track>,
        mget_tracks:              post "/v1/tracks/.mget"                => mget::<Track>,
        create_track:             post "/v1/tracks"                      => create::<Track>,
        update_track:             post "/v1/tracks/:id"                  => update::<Track>,
        index_tracks:             get  "/v1/tracks"                      => index::<Track>,
        index_tracks_by_entry:    get  "/v1/entries/:entry_id/tracks"    => index_by_entry::<Track>,

        show_playlist_by_id:      get  "/v1/playlists/:id"               => show_by_id::<Playlist>,
        show_playlist:            get  "/v1/playlists/:provider/:id"     => show::<Playlist>,
        create_playlist:          post "/v1/playlists"                   => create::<Playlist>,
        update_playlist:          post "/v1/playlists/:id"               => update::<Playlist>,
        mget_playlists:           post "/v1/playlists/.mget"             => mget::<Playlist>,
        index_playlists:          get  "/v1/playlists"                   => index::<Playlist>,
        index_playlists_by_entry: get  "/v1/entries/:entry_id/playlists" => index_by_entry::<Playlist>,

        show_album_by_id:         get  "/v1/albums/:id"                  => show_by_id::<Album>,
        show_album:               get  "/v1/albums/:provider/:id"        => show::<Album>,
        mget_albums:              post "/v1/albums/.mget"                => mget::<Album>,
        create_album:             post "/v1/albums"                      => create::<Album>,
        update_album:             post "/v1/albums/:id"                  => update::<Album>,
        index_albums:             get  "/v1/albums"                      => index::<Album>,
        index_albums_by_entry:    get  "/v1/entries/:entry_id/albums"    => index_by_entry::<Album>,
    );
    let port_str = match get_env::var("PORT") {
        Some(n) => n,
        None    => "8080".to_string()
    };
    let port: u16 = match port_str.trim().parse() {
        Ok(n) => n,
        Err(_) => {
            println!("Faild to parse port");
            return;
        }
    };
    println!("PORT {}", port_str);
    let ip = Ipv4Addr::new(0, 0, 0, 0);
    Iron::new(router).http(SocketAddrV4::new(ip, port)).unwrap();
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

use std::str;
use nom::{
    IResult,
    ErrorKind,
    is_hex_digit
};

fn is_pn_chars_base(c: char) -> bool {
    let u = c as u32;
    match u {
        0x41    ... 0x5A   | 0x61   ... 0x7A   |
        0xC0    ... 0xD6   | 0xD8   ... 0xF6   |
        0xF8    ... 0x2FF  | 0x370  ... 0x37D  |
        0x37F   ... 0x1FFF | 0x200C ... 0x200D |
        0x2C00  ... 0x2FEF | 0x3001 ... 0xD7FF |
        0xF900  ... 0xFDCF | 0xFDF0 ... 0xFFFD |
        0x10000 ... 0xEFFFF
          => true,
        _ => false,
    }
}

fn is_pn_chars_u(c: char) -> bool {
    is_pn_chars_base(c) || c == '_'
}

fn is_pn_chars(c: char) -> bool {
    let u = c as u32;
    match u {
        0x2d | 0xB7 | 0x30...0x39 | 0x300...0x36F | 0x203F...0x2040
          => true,
        _ => is_pn_chars_base(c),
    }
}

fn is_pn_local_esc(c: char) -> bool {
    match "_~.-!$&'()*+,;=/?#@%".find(c) {
        Some(_) => true,
        _       => false,
    }
}

fn is_ws(c: char) -> bool {
    let u = c as u32;
    u == 0x20 || u == 0x9 || u == 0xD || u == 0xA
}

fn is_anon(c: char) -> bool {
    c == '[' || c == ']' || is_ws(c)
}

fn is_echar(c: char) -> bool {
    c == '\\' || c == 't' || c == 'b' || c == 'n' || c == 'r' || c == 'f' || c == '"'
}

/* [159s] ECHAR */
named!(echar<&str, &str>, verify!(
    take_s!(2),
    |val:&str| {
        let len = val.char_indices().count();
        val.char_indices().all(|(idx, c)| {
            if idx == 0 {
                c == '\\'
            } else {
                is_echar(c)
            }
        })
    }
));

/* [161s] WS */
named!(ws<&str, &str>, take_while_s!(is_ws));

/* [162s] ANON */
named!(anon<&str, &str>, verify!(
    take_while_s!(is_anon),
    |val:&str| {
        let len = val.char_indices().count();
        val.char_indices().all(|(idx, c)| {
            if idx == 0 {
                c == '['
            } else if idx == len - 1 {
                c == ']'
            } else {
                is_ws(c)
            }
        })
    }
));

/* [163s] PN_CHARS_BASE */
named!(pn_chars_base<&str, &str>, verify!(
    take_s!(1),
    |val:&str| {
        if let Some(c) = val.chars().next() {
            return is_pn_chars_base(c)
        }
        false
    }
));

/* [164s] PN_CHARS_U */
named!(pn_chars_u<&str, &str>, verify!(
    take_s!(1),
    |val:&str| {
        if let Some(c) = val.chars().next() {
            return is_pn_chars_u(c)
        }
        false
    }
));

/* [166s] PN_CHARS */
named!(pn_chars<&str, &str>, verify!(
    take_s!(1),
    |val:&str| {
        if let Some(c) = val.chars().next() {
            return is_pn_chars(c)
        }
        false
    }
));

/* [167s] PN_PREFIX */
named!(pn_prefix<&str, &str>, verify!(
    take_until!(":"),
    |val:&str| {
        let len = val.char_indices().count();
        val.char_indices().all(|(idx, c)| {
            if idx == 0 {
                is_pn_chars_base(c)
            } else if idx == len - 1 {
                c != '.'
            } else {
                is_pn_chars(c) || c == '.'
            }
        })
    }
));

fn is_pn_local(c: char) -> bool {
    is_pn_chars(c) ||
    c == '.'  || c == ':'              ||
    c == '%'  || is_hex_digit(c as u8) ||
    c == '\\' || is_pn_local_esc(c)
}
/* [168s] PN_LOCAL */
named!(pn_local<&str, &str>, verify!(
    take_while_s!(is_pn_local),
    |val:&str| {
        let len = val.char_indices().count();
        let mut percent_count = 0;
        let mut pn_local_esc_count = 0;
        val.char_indices().all(|(idx, c)| {
            if percent_count > 0 {
                percent_count = percent_count - 1;
                is_hex_digit(c as u8)
            } else if c == '%' {
                percent_count = 2;
                true
            } else if pn_local_esc_count > 0 {
                pn_local_esc_count = pn_local_esc_count - 1;
                is_pn_local_esc(c)
            } else if c == '\\' {
                pn_local_esc_count = 1;
                true
            } else if idx == 0 {
                is_pn_chars_u(c) || c == ':'
            } else if idx == len - 1 {
                is_pn_chars(c) || c == ':'
            } else {
                is_pn_chars(c) || c == ':' || c == '.'
            }
        }) && percent_count == 0 && pn_local_esc_count == 0
    }
));

/* [169s] PLX */
named!(plx<&str, &str>, alt!(percent | pn_local_esc));

/* [170s] PERCENT */
named!(percent<&str, &str>, verify!(
    take_s!(3),
    |val:&str| {
        let bytes = val.as_bytes();
        bytes[0] == 0x25 && is_hex_digit(bytes[1]) && is_hex_digit(bytes[2])
    }
));

/* [172s]  PN_LOCAL_ESC */
named!(pn_local_esc<&str, &str>, verify!(
    take_s!(2),
    |val:&str| {
        let c1 = val.chars().nth(0).unwrap();
        let c2 = val.chars().nth(1).unwrap();
        c1 == '\\' && is_pn_local_esc(c2)
    }
));

fn main() {
    assert_eq!(echar("\\ta")             , IResult::Done("a", "\\t")          );
    assert_eq!(ws("   a")                , IResult::Done("a", "   ")          );
    assert_eq!(anon("[ ]a")              , IResult::Done("a", "[ ]")          );
    assert_eq!(pn_chars_base("a%2Ab")    , IResult::Done("%2Ab", "a")         );
    assert_eq!(pn_chars_u("_a")          , IResult::Done("a"   , "_")         );
    assert_eq!(pn_chars("-_a")           , IResult::Done("_a"  , "-")         );
    assert_eq!(pn_chars(":a2Ab")         , IResult::Error(ErrorKind::Verify)  );
    assert_eq!(pn_prefix("hog.e:")       , IResult::Done(":", "hog.e")        );
    assert_eq!(pn_prefix("hoge.:")       , IResult::Error(ErrorKind::Verify)  );
    assert_eq!(pn_local("hoge:fuga piyo"), IResult::Done(" piyo", "hoge:fuga"));
    assert_eq!(pn_local("hoge:%28 piyo") , IResult::Done(" piyo", "hoge:%28") );
    assert_eq!(pn_local("hoge:%2 piyo")  , IResult::Error(ErrorKind::Verify)  );
    assert_eq!(pn_local("hoge:%__ piyo") , IResult::Error(ErrorKind::Verify)  );
    assert_eq!(pn_local("hoge:\\* piyo") , IResult::Done(" piyo", "hoge:\\*") );
    assert_eq!(pn_local("%28\\* piyo")   , IResult::Done(" piyo", "%28\\*")   );
    assert_eq!(pn_local("%28\\ piyo")    , IResult::Error(ErrorKind::Verify)  );
    assert_eq!(plx("%2Abc")              , IResult::Done("bc"   , "%2A")      );
    assert_eq!(plx("\\.%2A")             , IResult::Done("%2A"  , "\\.")      );
    assert_eq!(percent("%2Abc")          , IResult::Done("bc"   , "%2A")      );
    assert_eq!(pn_local_esc("\\.a b c")  , IResult::Done("a b c", "\\.")      );
}
<commit_msg>Implement UCHAR<commit_after>#[macro_use]
extern crate nom;

use std::str;
use nom::{
    IResult,
    ErrorKind,
    is_hex_digit
};

fn is_pn_chars_base(c: char) -> bool {
    let u = c as u32;
    match u {
        0x41    ... 0x5A   | 0x61   ... 0x7A   |
        0xC0    ... 0xD6   | 0xD8   ... 0xF6   |
        0xF8    ... 0x2FF  | 0x370  ... 0x37D  |
        0x37F   ... 0x1FFF | 0x200C ... 0x200D |
        0x2C00  ... 0x2FEF | 0x3001 ... 0xD7FF |
        0xF900  ... 0xFDCF | 0xFDF0 ... 0xFFFD |
        0x10000 ... 0xEFFFF
          => true,
        _ => false,
    }
}

fn is_pn_chars_u(c: char) -> bool {
    is_pn_chars_base(c) || c == '_'
}

fn is_pn_chars(c: char) -> bool {
    let u = c as u32;
    match u {
        0x2d | 0xB7 | 0x30...0x39 | 0x300...0x36F | 0x203F...0x2040
          => true,
        _ => is_pn_chars_base(c),
    }
}

fn is_pn_local_esc(c: char) -> bool {
    match "_~.-!$&'()*+,;=/?#@%".find(c) {
        Some(_) => true,
        _       => false,
    }
}

fn is_ws(c: char) -> bool {
    let u = c as u32;
    u == 0x20 || u == 0x9 || u == 0xD || u == 0xA
}

fn is_anon(c: char) -> bool {
    c == '[' || c == ']' || is_ws(c)
}

fn is_uchar(c: char) -> bool {
    c == '\\' || c == 'u' || is_hex_digit(c as u8)
}

fn is_echar(c: char) -> bool {
    c == '\\' || c == 't' || c == 'b' || c == 'n' || c == 'r' || c == 'f' || c == '"'
}

/* [159s] UCHAR */
named!(uchar<&str, &str>, alt!(
    verify!(
        take_s!(6),
        |val:&str| {
            let len = val.char_indices().count();
            val.char_indices().all(|(idx, c)| {
                if idx == 0 {
                    c == '\\'
                } else if idx == 1 {
                    c == 'u'
                } else {
                    is_hex_digit(c as u8)
                }
            })
        }
    ) |
    verify!(
        take_s!(10),
        |val:&str| {
            let len = val.char_indices().count();
            val.char_indices().all(|(idx, c)| {
                if idx == 0 {
                    c == '\\'
                } else if idx == 1 {
                    c == 'U'
                } else {
                    is_hex_digit(c as u8)
                }
            })
        }
    )
));

/* [159s] ECHAR */
named!(echar<&str, &str>, verify!(
    take_s!(2),
    |val:&str| {
        let len = val.char_indices().count();
        val.char_indices().all(|(idx, c)| {
            if idx == 0 {
                c == '\\'
            } else {
                is_echar(c)
            }
        })
    }
));

/* [161s] WS */
named!(ws<&str, &str>, take_while_s!(is_ws));

/* [162s] ANON */
named!(anon<&str, &str>, verify!(
    take_while_s!(is_anon),
    |val:&str| {
        let len = val.char_indices().count();
        val.char_indices().all(|(idx, c)| {
            if idx == 0 {
                c == '['
            } else if idx == len - 1 {
                c == ']'
            } else {
                is_ws(c)
            }
        })
    }
));

/* [163s] PN_CHARS_BASE */
named!(pn_chars_base<&str, &str>, verify!(
    take_s!(1),
    |val:&str| {
        if let Some(c) = val.chars().next() {
            return is_pn_chars_base(c)
        }
        false
    }
));

/* [164s] PN_CHARS_U */
named!(pn_chars_u<&str, &str>, verify!(
    take_s!(1),
    |val:&str| {
        if let Some(c) = val.chars().next() {
            return is_pn_chars_u(c)
        }
        false
    }
));

/* [166s] PN_CHARS */
named!(pn_chars<&str, &str>, verify!(
    take_s!(1),
    |val:&str| {
        if let Some(c) = val.chars().next() {
            return is_pn_chars(c)
        }
        false
    }
));

/* [167s] PN_PREFIX */
named!(pn_prefix<&str, &str>, verify!(
    take_until!(":"),
    |val:&str| {
        let len = val.char_indices().count();
        val.char_indices().all(|(idx, c)| {
            if idx == 0 {
                is_pn_chars_base(c)
            } else if idx == len - 1 {
                c != '.'
            } else {
                is_pn_chars(c) || c == '.'
            }
        })
    }
));

fn is_pn_local(c: char) -> bool {
    is_pn_chars(c) ||
    c == '.'  || c == ':'              ||
    c == '%'  || is_hex_digit(c as u8) ||
    c == '\\' || is_pn_local_esc(c)
}
/* [168s] PN_LOCAL */
named!(pn_local<&str, &str>, verify!(
    take_while_s!(is_pn_local),
    |val:&str| {
        let len = val.char_indices().count();
        let mut percent_count = 0;
        let mut pn_local_esc_count = 0;
        val.char_indices().all(|(idx, c)| {
            if percent_count > 0 {
                percent_count = percent_count - 1;
                is_hex_digit(c as u8)
            } else if c == '%' {
                percent_count = 2;
                true
            } else if pn_local_esc_count > 0 {
                pn_local_esc_count = pn_local_esc_count - 1;
                is_pn_local_esc(c)
            } else if c == '\\' {
                pn_local_esc_count = 1;
                true
            } else if idx == 0 {
                is_pn_chars_u(c) || c == ':'
            } else if idx == len - 1 {
                is_pn_chars(c) || c == ':'
            } else {
                is_pn_chars(c) || c == ':' || c == '.'
            }
        }) && percent_count == 0 && pn_local_esc_count == 0
    }
));

/* [169s] PLX */
named!(plx<&str, &str>, alt!(percent | pn_local_esc));

/* [170s] PERCENT */
named!(percent<&str, &str>, verify!(
    take_s!(3),
    |val:&str| {
        let bytes = val.as_bytes();
        bytes[0] == 0x25 && is_hex_digit(bytes[1]) && is_hex_digit(bytes[2])
    }
));

/* [172s]  PN_LOCAL_ESC */
named!(pn_local_esc<&str, &str>, verify!(
    take_s!(2),
    |val:&str| {
        let c1 = val.chars().nth(0).unwrap();
        let c2 = val.chars().nth(1).unwrap();
        c1 == '\\' && is_pn_local_esc(c2)
    }
));

fn main() {
    assert_eq!(uchar("\\u02FFa")         , IResult::Done("a", "\\u02FF")      );
    assert_eq!(uchar("\\U02FFAABBa")     , IResult::Done("a", "\\U02FFAABB")  );
    assert_eq!(echar("\\ta")             , IResult::Done("a", "\\t")          );
    assert_eq!(ws("   a")                , IResult::Done("a", "   ")          );
    assert_eq!(anon("[ ]a")              , IResult::Done("a", "[ ]")          );
    assert_eq!(pn_chars_base("a%2Ab")    , IResult::Done("%2Ab", "a")         );
    assert_eq!(pn_chars_u("_a")          , IResult::Done("a"   , "_")         );
    assert_eq!(pn_chars("-_a")           , IResult::Done("_a"  , "-")         );
    assert_eq!(pn_chars(":a2Ab")         , IResult::Error(ErrorKind::Verify)  );
    assert_eq!(pn_prefix("hog.e:")       , IResult::Done(":", "hog.e")        );
    assert_eq!(pn_prefix("hoge.:")       , IResult::Error(ErrorKind::Verify)  );
    assert_eq!(pn_local("hoge:fuga piyo"), IResult::Done(" piyo", "hoge:fuga"));
    assert_eq!(pn_local("hoge:%28 piyo") , IResult::Done(" piyo", "hoge:%28") );
    assert_eq!(pn_local("hoge:%2 piyo")  , IResult::Error(ErrorKind::Verify)  );
    assert_eq!(pn_local("hoge:%__ piyo") , IResult::Error(ErrorKind::Verify)  );
    assert_eq!(pn_local("hoge:\\* piyo") , IResult::Done(" piyo", "hoge:\\*") );
    assert_eq!(pn_local("%28\\* piyo")   , IResult::Done(" piyo", "%28\\*")   );
    assert_eq!(pn_local("%28\\ piyo")    , IResult::Error(ErrorKind::Verify)  );
    assert_eq!(plx("%2Abc")              , IResult::Done("bc"   , "%2A")      );
    assert_eq!(plx("\\.%2A")             , IResult::Done("%2A"  , "\\.")      );
    assert_eq!(percent("%2Abc")          , IResult::Done("bc"   , "%2A")      );
    assert_eq!(pn_local_esc("\\.a b c")  , IResult::Done("a b c", "\\.")      );
}
<|endoftext|>


<commit_before>struct Item(&'static str);

struct Location {
    description: &'static str,
    items: Vec<Item>,
}

// how to do actions?
// as an enum? sounds reasonable.
// what properties do they have?
// a keyword which is typed in
// one or more arguments, possibly a variable number
// something which happens when they are invoked

// "look": print the area description
// "take + item": move the item to the player's inventory
// "go + direction": move to the area in that direction
// "use + item (+ object)": maybe remove the item, invoke a (targeted?) effect

fn main() {
    let item1 = Item("Little key");
    let item2 = Item("Big key");
    let hall = Location{ description: "A wide open space. Streams of lava flow on both sides of the entry gate.",
                         items: vec![item1, item2] };
}
<commit_msg>This seems to be a valid way to declare an enum. Can probably do more with them than I am currently envisioning, especially with the help of a macro for defining actions.<commit_after>struct Item(&'static str);

struct Location {
    description: &'static str,
    items: Vec<Item>,
}

// how to do actions?
// as an enum? sounds reasonable.
// what properties do they have?
// a keyword which is typed in
// one or more arguments, possibly a variable number
// something which happens when they are invoked

// "look": print the area description
// "take + item": move the item to the player's inventory
// "go + direction": move to the area in that direction
// "use + item (+ object)": maybe remove the item, invoke a (targeted?) effect

// one option: just match the enum value, parse the rest and act based on a match
enum Action {
    Look,
    Take,
    Go,
    Use,
}

fn main() {
    let item1 = Item("Little key");
    let item2 = Item("Big key");
    let hall = Location{ description: "A wide open space. Streams of lava flow on both sides of the entry gate.",
                         items: vec![item1, item2] };
}
<|endoftext|>