<commit_before>use std::io;
use std::os::getenv;
use std::path::BytesContainer;
use std::str::from_utf8_lossy;
use get_environ = std::os::env;
use std::io::fs::{mkdir, rename, symlink, unlink, readlink};
use std::io::process::{ExitStatus, Command, Ignored, InheritFd};
use std::io::stdio::{stdout, stderr};

use super::sha256::Sha256;
use super::sha256::Digest;

use argparse::{ArgumentParser, Store, StoreTrue};

use super::env::{Environ, Container};
use super::options::env_options;
use super::clean::run_rmdirs;
use super::linux::ensure_dir;

fn makedirs(path: &Path) -> Result<(),String> {
    if path.exists() {
        return Ok(());
    }
    try!(makedirs(&path.dir_path()));
    return match mkdir(path, io::UserRWX) {
        Ok(()) => Ok(()),
        Err(e) => Err(format!("Can't mkdir: {}", e)),
    };
}

pub fn build_command(environ: &mut Environ, args: Vec<String>)
    -> Result<int, String>
{
    let mut cname = "devel".to_string();
    let mut force = false;
    {
        let mut ap = ArgumentParser::new();
        ap.refer(&mut cname)
            .add_argument("container", box Store::<String>,
                "A name of the container to build")
            .required();
        ap.refer(&mut force)
            .add_option(["--force"], box StoreTrue,
                "Force rebuild of container event if it already exists");
        env_options(environ, &mut ap);
        match ap.parse(args, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => return Ok(122),
        }
    }
    let mut container = try!(environ.get_container(&cname));
    try!(build_container(environ, &mut container, force));
    try!(link_container(environ, &container));

    return Ok(0);
}

pub fn link_container(environ: &Environ, container: &Container)
    -> Result<(), String>
{
    let container_root = container.container_root.as_ref().unwrap();
    let cdir = container_root.filename().unwrap();
    let tmptarget = environ.local_vagga.join(
        (".lnk.".container_into_owned_bytes() + cdir).as_slice());
    if tmptarget.exists() {
        match unlink(&tmptarget) {
            Ok(()) => {}
            Err(x) => return Err(format!("Error removing file: {}", x)),
        }
    }
    let target = environ.local_vagga.join(container.name.as_slice());
    debug!("Linking {} -> {}", container_root.display(), target.display())
    let relative_root = Path::new(".roots").join(cdir);
    match symlink(&relative_root, &tmptarget)
          .and(rename(&tmptarget, &target)) {
        Ok(()) => {}
        Err(x) => return Err(format!("Can't symlink new root: {}", x)),
    }
    if !container.name.eq(&container.fullname) {
        let target = environ.local_vagga.join(container.fullname.as_slice());
        debug!("Linking {} -> {}", container_root.display(), target.display())
        match symlink(&relative_root, &tmptarget)
              .and(rename(&tmptarget, &target)) {
            Ok(()) => {}
            Err(x) => return Err(format!("Can't symlink new root: {}", x)),
        }
    }
    return Ok(());
}

pub fn build_container(environ: &Environ, container: &mut Container,
                       force: bool)
    -> Result <bool, String>
{
    info!("Checking {}", container.name);

    let builder = &container.builder;
    let bldpath = match environ.find_builder(builder) {
        Some(b) => b,
        None => return Err(format!("Can't find builder {}, \
            check your VAGGA_PATH", builder)),
    };
    info!("Builder full path is {}", bldpath.display());
    let cache_dir = environ.local_vagga.join_many(
        [".cache", builder.as_slice()]);

    // TODO(tailhook) which path should be here?
    let path = getenv("PATH").unwrap_or(
        "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin"
        .to_string());

    let mut env: Vec<(&[u8], &[u8])> = Vec::new();
    let mut caller_env: Vec<(String, String)> = Vec::new();
    let mut parameters: Vec<(String, String)> = Vec::new();
    env.push(("HOME".as_bytes(), "/homeless-shelter".as_bytes()));
    env.push(("PATH".as_bytes(), path.as_bytes()));
    env.push(("container_name".as_bytes(), container.name.as_bytes()));
    env.push(("container_fullname".as_bytes(), container.fullname.as_bytes()));
    env.push(("cache_dir".as_bytes(), cache_dir.as_vec()));
    env.push(("project_root".as_bytes(), environ.project_root.as_vec()));
    for (k, v) in get_environ().move_iter() {
        let pk = "CALLER_".to_string() + k;
        let pv = v;
        caller_env.push((pk, pv));
    }
    for (k, v) in container.parameters.iter() {
        parameters.push((builder + "_" + *k, v.clone()));
    }
    for &(ref k, ref v) in caller_env.iter() {
        env.push((k.container_as_bytes(), v.container_as_bytes()));
    }
    for &(ref k, ref v) in parameters.iter() {
        env.push((k.container_as_bytes(), v.container_as_bytes()));
    }

    let version_sh = bldpath.join("version.sh");
    let mut digest = Sha256::new();
    if version_sh.exists() {
        digest.input_str(builder.as_slice());
        digest.input_str(":");
        match Command::new(&version_sh).env(env.as_slice())
            .cwd(&environ.project_root)
            .stdin(Ignored).stderr(InheritFd(2)).output() {
            Ok(out) => match out.status {
                ExitStatus(0) => {
                    debug!("Version data ```{}```",
                           from_utf8_lossy(out.output.as_slice()));
                    digest.input(out.output.as_slice());
                }
                e => {
                    return Err(format!("Error running {}: {}",
                        version_sh.display(), e));
                }
            },
            Err(e) => {
                return Err(format!("Error running {}: {}",
                    version_sh.display(), e));
            }
        }
    } else {
        warn!("This backend has no versioning. Using primitive one.");
        digest.input_str(builder.as_slice());
        digest.input_str(":");
        for (k, v) in container.parameters.iter() {
            digest.input_str(k.as_slice());
            digest.input_str("=");
            digest.input_str(v.as_slice());
            digest.input_str(";");
        }
    }
    if container.uids.len() > 0 {
        digest.input_str("uids:");
        for rng in container.uids.iter() {
            digest.input_uint(rng.start as u64);
            digest.input_uint(rng.end as u64);
        }
    }
    if container.gids.len() > 0 {
        digest.input_str("gids:");
        for rng in container.gids.iter() {
            digest.input_uint(rng.start as u64);
            digest.input_uint(rng.end as u64);
        }
    }
    match container.provision {
        Some(ref x) => digest.input_str(x.as_slice()),
        None => {}
    }

    let fullhash = digest.result_str();
    let hash = fullhash.as_slice().slice_to(7);

    let build_sh = bldpath.join("build.sh");
    if !build_sh.exists() {
        return Err(format!("Builder {} does not exist", builder));
    }

    let cdir = format!("{}.{}", container.fullname, hash);
    let container_root = environ.local_vagga.join_many(
        [".roots", cdir.as_slice()]);

    if container_root.exists() && !force {
        info!("Container {} already built as {}",
            container.name, container_root.display());
        container.container_root = Some(container_root);
        return Ok(false);
    }

    let artifacts_dir = environ.local_vagga.join_many(
        [".artifacts", cdir.as_slice()]);
    let container_tmp = environ.local_vagga.join_many(
        [".roots", (cdir + ".tmp").as_slice()]);

    info!("Building {} by {}", container_root.display(), build_sh.display());

    if container_tmp.exists() {
        try!(run_rmdirs(environ, vec!(container_tmp.clone())));
    }
    if artifacts_dir.exists() {
        try!(run_rmdirs(environ, vec!(artifacts_dir.clone())));
    }
    try!(makedirs(&container_tmp));

    env.push(("vagga_exe".as_bytes(), environ.vagga_exe.container_as_bytes()));
    env.push(("vagga_inventory".as_bytes(),
        environ.vagga_inventory.container_as_bytes()));
    env.push(("artifacts_dir".as_bytes(), artifacts_dir.as_vec()));
    env.push(("container_hash".as_bytes(), hash.as_bytes()));
    env.push(("container_root".as_bytes(), container_tmp.as_vec()));

    let mut cmd = Command::new(environ.vagga_exe.as_vec());
    cmd.arg("_userns");
    if container.uids.len() > 0 {
        cmd.arg("--uid-ranges");
        let lst: Vec<String> = container.uids.iter()
                .map(|r| format!("{}-{}", r.start, r.end)).collect();
        cmd.arg(lst.connect(","));
    }
    if container.gids.len() > 0 {
        cmd.arg("--gid-ranges");
        let lst: Vec<String> = container.gids.iter()
                .map(|r| format!("{}-{}", r.start, r.end)).collect();
        cmd.arg(lst.connect(","));
    }
    cmd.arg(build_sh);
    cmd.env(env.as_slice());
    cmd.cwd(&environ.project_root);
    cmd.stdin(InheritFd(0)).stdout(InheritFd(1)).stderr(InheritFd(2));
    match cmd.status() {
        Ok(ExitStatus(0)) => {}
        Ok(x) => return Err(format!("Builder exited with status {}", x)),
        Err(x) => return Err(format!("Can't spawn: {}", x)),
    }

    if container.provision.is_some() {
        let mut pcmd = Command::new(environ.vagga_exe.as_vec());
        pcmd.env(env.as_slice());
        pcmd.arg("_chroot");
        pcmd.arg("--writeable");
        pcmd.arg("--inventory");
        if container.uids.len() > 0 {
            cmd.arg("--uid-ranges");
            let lst: Vec<String> = container.uids.iter()
                    .map(|r| format!("{}-{}", r.start, r.end)).collect();
            cmd.arg(lst.connect(","));
        }
        if container.gids.len() > 0 {
            cmd.arg("--gid-ranges");
            let lst: Vec<String> = container.gids.iter()
                    .map(|r| format!("{}-{}", r.start, r.end)).collect();
            cmd.arg(lst.connect(","));
        }
        pcmd.arg(container_tmp.as_vec());
        pcmd.args(container.shell.as_slice());
        pcmd.arg(container.provision.as_ref().unwrap().as_slice());
        pcmd.cwd(&environ.project_root);
        pcmd.stdin(InheritFd(0)).stdout(InheritFd(1)).stderr(InheritFd(2));

        match pcmd.status() {
            Ok(ExitStatus(0)) => {}
            Ok(x) => return Err(format!("Provision exited with status {}", x)),
            Err(x) => return Err(format!("Can't spawn provisor: {}", x)),
        }
    }

    for dir in ["proc", "sys", "dev", "work", "tmp", "etc"].iter() {
        try!(ensure_dir(&container_tmp.join(*dir)));
    }

    let container_old = environ.local_vagga.join_many(
        [".roots", (cdir + ".old").as_slice()]);
    if container_root.exists() {
        if container_old.exists() {
            try!(run_rmdirs(environ, vec!(container_old.clone())));
        }
        match rename(&container_root, &container_old) {
            Ok(()) => {}
            Err(x) => return Err(format!("Can't rename old root: {}", x)),
        }
    }

    match rename(&container_tmp, &container_root) {
        Ok(()) => {}
        Err(x) => return Err(format!("Can't rename root: {}", x)),
    }

    if container_old.exists() {
        try!(run_rmdirs(environ, vec!(container_old.clone())));
    }
    info!("Done building {} as {}",
        container.name, container_root.display());

    container.container_root = Some(container_root);

    return Ok(true);
}

pub fn ensure_container(env: &Environ, container: &mut Container)
    -> Result<(), String>
{
    if env.settings.version_check {
        try!(build_container(env, container, false));
        try!(link_container(env, container));
    } else {
        let lnk = env.local_vagga.join(container.fullname.as_slice());
        container.container_root = match readlink(&lnk) {
            Ok(path) => Some(lnk.dir_path().join(path)),
            Err(e) => return Err(format!("Container {} not found: {}",
                                         container.fullname, e)),
        };
    };
    return Ok(());
}
<commit_msg>Propagate RUST_LOG to builder script<commit_after>use std::io;
use std::os::getenv;
use std::path::BytesContainer;
use std::str::from_utf8_lossy;
use get_environ = std::os::env;
use std::io::fs::{mkdir, rename, symlink, unlink, readlink};
use std::io::process::{ExitStatus, Command, Ignored, InheritFd};
use std::io::stdio::{stdout, stderr};

use super::sha256::Sha256;
use super::sha256::Digest;

use argparse::{ArgumentParser, Store, StoreTrue};

use super::env::{Environ, Container};
use super::options::env_options;
use super::clean::run_rmdirs;
use super::linux::ensure_dir;

fn makedirs(path: &Path) -> Result<(),String> {
    if path.exists() {
        return Ok(());
    }
    try!(makedirs(&path.dir_path()));
    return match mkdir(path, io::UserRWX) {
        Ok(()) => Ok(()),
        Err(e) => Err(format!("Can't mkdir: {}", e)),
    };
}

pub fn build_command(environ: &mut Environ, args: Vec<String>)
    -> Result<int, String>
{
    let mut cname = "devel".to_string();
    let mut force = false;
    {
        let mut ap = ArgumentParser::new();
        ap.refer(&mut cname)
            .add_argument("container", box Store::<String>,
                "A name of the container to build")
            .required();
        ap.refer(&mut force)
            .add_option(["--force"], box StoreTrue,
                "Force rebuild of container event if it already exists");
        env_options(environ, &mut ap);
        match ap.parse(args, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => return Ok(122),
        }
    }
    let mut container = try!(environ.get_container(&cname));
    try!(build_container(environ, &mut container, force));
    try!(link_container(environ, &container));

    return Ok(0);
}

pub fn link_container(environ: &Environ, container: &Container)
    -> Result<(), String>
{
    let container_root = container.container_root.as_ref().unwrap();
    let cdir = container_root.filename().unwrap();
    let tmptarget = environ.local_vagga.join(
        (".lnk.".container_into_owned_bytes() + cdir).as_slice());
    if tmptarget.exists() {
        match unlink(&tmptarget) {
            Ok(()) => {}
            Err(x) => return Err(format!("Error removing file: {}", x)),
        }
    }
    let target = environ.local_vagga.join(container.name.as_slice());
    debug!("Linking {} -> {}", container_root.display(), target.display())
    let relative_root = Path::new(".roots").join(cdir);
    match symlink(&relative_root, &tmptarget)
          .and(rename(&tmptarget, &target)) {
        Ok(()) => {}
        Err(x) => return Err(format!("Can't symlink new root: {}", x)),
    }
    if !container.name.eq(&container.fullname) {
        let target = environ.local_vagga.join(container.fullname.as_slice());
        debug!("Linking {} -> {}", container_root.display(), target.display())
        match symlink(&relative_root, &tmptarget)
              .and(rename(&tmptarget, &target)) {
            Ok(()) => {}
            Err(x) => return Err(format!("Can't symlink new root: {}", x)),
        }
    }
    return Ok(());
}

pub fn build_container(environ: &Environ, container: &mut Container,
                       force: bool)
    -> Result <bool, String>
{
    info!("Checking {}", container.name);

    let builder = &container.builder;
    let bldpath = match environ.find_builder(builder) {
        Some(b) => b,
        None => return Err(format!("Can't find builder {}, \
            check your VAGGA_PATH", builder)),
    };
    info!("Builder full path is {}", bldpath.display());
    let cache_dir = environ.local_vagga.join_many(
        [".cache", builder.as_slice()]);

    // TODO(tailhook) which path should be here?
    let path = getenv("PATH").unwrap_or(
        "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin"
        .to_string());

    let mut env: Vec<(&[u8], &[u8])> = Vec::new();
    let mut caller_env: Vec<(String, String)> = Vec::new();
    let mut parameters: Vec<(String, String)> = Vec::new();
    env.push(("HOME".as_bytes(), "/homeless-shelter".as_bytes()));
    env.push(("PATH".as_bytes(), path.as_bytes()));
    env.push(("container_name".as_bytes(), container.name.as_bytes()));
    env.push(("container_fullname".as_bytes(), container.fullname.as_bytes()));
    env.push(("cache_dir".as_bytes(), cache_dir.as_vec()));
    env.push(("project_root".as_bytes(), environ.project_root.as_vec()));
    for (k, v) in get_environ().move_iter() {
        let pk = "CALLER_".to_string() + k;
        let pv = v;
        caller_env.push((pk, pv));
    }
    for (k, v) in container.parameters.iter() {
        parameters.push((builder + "_" + *k, v.clone()));
    }
    for &(ref k, ref v) in caller_env.iter() {
        env.push((k.container_as_bytes(), v.container_as_bytes()));
    }
    for &(ref k, ref v) in parameters.iter() {
        env.push((k.container_as_bytes(), v.container_as_bytes()));
    }

    let version_sh = bldpath.join("version.sh");
    let mut digest = Sha256::new();
    if version_sh.exists() {
        digest.input_str(builder.as_slice());
        digest.input_str(":");
        match Command::new(&version_sh).env(env.as_slice())
            .cwd(&environ.project_root)
            .stdin(Ignored).stderr(InheritFd(2)).output() {
            Ok(out) => match out.status {
                ExitStatus(0) => {
                    debug!("Version data ```{}```",
                           from_utf8_lossy(out.output.as_slice()));
                    digest.input(out.output.as_slice());
                }
                e => {
                    return Err(format!("Error running {}: {}",
                        version_sh.display(), e));
                }
            },
            Err(e) => {
                return Err(format!("Error running {}: {}",
                    version_sh.display(), e));
            }
        }
    } else {
        warn!("This backend has no versioning. Using primitive one.");
        digest.input_str(builder.as_slice());
        digest.input_str(":");
        for (k, v) in container.parameters.iter() {
            digest.input_str(k.as_slice());
            digest.input_str("=");
            digest.input_str(v.as_slice());
            digest.input_str(";");
        }
    }
    if container.uids.len() > 0 {
        digest.input_str("uids:");
        for rng in container.uids.iter() {
            digest.input_uint(rng.start as u64);
            digest.input_uint(rng.end as u64);
        }
    }
    if container.gids.len() > 0 {
        digest.input_str("gids:");
        for rng in container.gids.iter() {
            digest.input_uint(rng.start as u64);
            digest.input_uint(rng.end as u64);
        }
    }
    match container.provision {
        Some(ref x) => digest.input_str(x.as_slice()),
        None => {}
    }

    let fullhash = digest.result_str();
    let hash = fullhash.as_slice().slice_to(7);

    let build_sh = bldpath.join("build.sh");
    if !build_sh.exists() {
        return Err(format!("Builder {} does not exist", builder));
    }

    let cdir = format!("{}.{}", container.fullname, hash);
    let container_root = environ.local_vagga.join_many(
        [".roots", cdir.as_slice()]);

    if container_root.exists() && !force {
        info!("Container {} already built as {}",
            container.name, container_root.display());
        container.container_root = Some(container_root);
        return Ok(false);
    }

    let artifacts_dir = environ.local_vagga.join_many(
        [".artifacts", cdir.as_slice()]);
    let container_tmp = environ.local_vagga.join_many(
        [".roots", (cdir + ".tmp").as_slice()]);

    info!("Building {} by {}", container_root.display(), build_sh.display());

    if container_tmp.exists() {
        try!(run_rmdirs(environ, vec!(container_tmp.clone())));
    }
    if artifacts_dir.exists() {
        try!(run_rmdirs(environ, vec!(artifacts_dir.clone())));
    }
    try!(makedirs(&container_tmp));

    env.push(("vagga_exe".as_bytes(), environ.vagga_exe.container_as_bytes()));
    env.push(("vagga_inventory".as_bytes(),
        environ.vagga_inventory.container_as_bytes()));
    env.push(("artifacts_dir".as_bytes(), artifacts_dir.as_vec()));
    env.push(("container_hash".as_bytes(), hash.as_bytes()));
    env.push(("container_root".as_bytes(), container_tmp.as_vec()));
    let rustlog = getenv("RUST_LOG");
    match rustlog {
        Some(ref x) => env.push(("RUST_LOG".as_bytes(), x.as_bytes())),
        None => {}
    }

    let mut cmd = Command::new(environ.vagga_exe.as_vec());
    cmd.arg("_userns");
    if container.uids.len() > 0 {
        cmd.arg("--uid-ranges");
        let lst: Vec<String> = container.uids.iter()
                .map(|r| format!("{}-{}", r.start, r.end)).collect();
        cmd.arg(lst.connect(","));
    }
    if container.gids.len() > 0 {
        cmd.arg("--gid-ranges");
        let lst: Vec<String> = container.gids.iter()
                .map(|r| format!("{}-{}", r.start, r.end)).collect();
        cmd.arg(lst.connect(","));
    }
    cmd.arg(build_sh);
    cmd.env(env.as_slice());
    cmd.cwd(&environ.project_root);
    cmd.stdin(InheritFd(0)).stdout(InheritFd(1)).stderr(InheritFd(2));
    match cmd.status() {
        Ok(ExitStatus(0)) => {}
        Ok(x) => return Err(format!("Builder exited with status {}", x)),
        Err(x) => return Err(format!("Can't spawn: {}", x)),
    }

    if container.provision.is_some() {
        let mut pcmd = Command::new(environ.vagga_exe.as_vec());
        pcmd.env(env.as_slice());
        pcmd.arg("_chroot");
        pcmd.arg("--writeable");
        pcmd.arg("--inventory");
        if container.uids.len() > 0 {
            cmd.arg("--uid-ranges");
            let lst: Vec<String> = container.uids.iter()
                    .map(|r| format!("{}-{}", r.start, r.end)).collect();
            cmd.arg(lst.connect(","));
        }
        if container.gids.len() > 0 {
            cmd.arg("--gid-ranges");
            let lst: Vec<String> = container.gids.iter()
                    .map(|r| format!("{}-{}", r.start, r.end)).collect();
            cmd.arg(lst.connect(","));
        }
        pcmd.arg(container_tmp.as_vec());
        pcmd.args(container.shell.as_slice());
        pcmd.arg(container.provision.as_ref().unwrap().as_slice());
        pcmd.cwd(&environ.project_root);
        pcmd.stdin(InheritFd(0)).stdout(InheritFd(1)).stderr(InheritFd(2));

        match pcmd.status() {
            Ok(ExitStatus(0)) => {}
            Ok(x) => return Err(format!("Provision exited with status {}", x)),
            Err(x) => return Err(format!("Can't spawn provisor: {}", x)),
        }
    }

    for dir in ["proc", "sys", "dev", "work", "tmp", "etc"].iter() {
        try!(ensure_dir(&container_tmp.join(*dir)));
    }

    let container_old = environ.local_vagga.join_many(
        [".roots", (cdir + ".old").as_slice()]);
    if container_root.exists() {
        if container_old.exists() {
            try!(run_rmdirs(environ, vec!(container_old.clone())));
        }
        match rename(&container_root, &container_old) {
            Ok(()) => {}
            Err(x) => return Err(format!("Can't rename old root: {}", x)),
        }
    }

    match rename(&container_tmp, &container_root) {
        Ok(()) => {}
        Err(x) => return Err(format!("Can't rename root: {}", x)),
    }

    if container_old.exists() {
        try!(run_rmdirs(environ, vec!(container_old.clone())));
    }
    info!("Done building {} as {}",
        container.name, container_root.display());

    container.container_root = Some(container_root);

    return Ok(true);
}

pub fn ensure_container(env: &Environ, container: &mut Container)
    -> Result<(), String>
{
    if env.settings.version_check {
        try!(build_container(env, container, false));
        try!(link_container(env, container));
    } else {
        let lnk = env.local_vagga.join(container.fullname.as_slice());
        container.container_root = match readlink(&lnk) {
            Ok(path) => Some(lnk.dir_path().join(path)),
            Err(e) => return Err(format!("Container {} not found: {}",
                                         container.fullname, e)),
        };
    };
    return Ok(());
}
<|endoftext|>


<commit_before>extern crate image;

use image::{GenericImage, Pixel};

use std::io::File;
use std::rand;
use std::rand::distributions::{Normal, IndependentSample};

fn main() {
    println!("24 days of Rust - image (day 12)");
    let img = image::open(&Path::new("data/in.jpg")).ok().expect("Opening image failed");
    let filtered = img.fliph();
    let out = File::create(&Path::new("out.jpg")).unwrap();
    let _ = filtered.save(out, image::JPEG).ok().expect("Saving image failed");

    let kernel = [-1.0f32, -1.0, -1.0,
                  -1.0, 8.0, -1.0,
                  -1.0, -1.0, -1.0];
    let filtered = img.filter3x3(&kernel);
    let out = File::create(&Path::new("out.jpg")).unwrap();
    let _ = filtered.save(out, image::JPEG).ok().expect("Saving image failed");

    let (width, height) = img.dimensions();
    let mut rng = rand::task_rng();
    let normal = Normal::new(15.0, 15.0);
    let mut noisy = img.brighten(-25);
    for x in range(0, width) {
        for y in range(0, height) {
            let offset = normal.ind_sample(&mut rng) as u8;
            let px = img.get_pixel(x, y).map(|v| v + offset);
            noisy.put_pixel(x, y, px);
        }
    }
    let out = File::create(&Path::new("out.jpg")).unwrap();
    let _ = noisy.save(out, image::JPEG).ok().expect("Saving image failed");
}
<commit_msg>Save as PNG.<commit_after>extern crate image;

use image::{GenericImage, Pixel};

use std::io::File;
use std::rand;
use std::rand::distributions::{Normal, IndependentSample};

fn main() {
    println!("24 days of Rust - image (day 12)");
    let img = image::open(&Path::new("data/in.jpg")).ok().expect("Opening image failed");
    let filtered = img.fliph();
    let out = File::create(&Path::new("out.png")).unwrap();
    let _ = filtered.save(out, image::PNG).ok().expect("Saving image failed");

    let kernel = [-1.0f32, -1.0, -1.0,
                  -1.0, 8.0, -1.0,
                  -1.0, -1.0, -1.0];
    let filtered = img.filter3x3(&kernel);
    let out = File::create(&Path::new("out.jpg")).unwrap();
    let _ = filtered.save(out, image::JPEG).ok().expect("Saving image failed");

    let (width, height) = img.dimensions();
    let mut rng = rand::task_rng();
    let normal = Normal::new(15.0, 15.0);
    let mut noisy = img.brighten(-25);
    for x in range(0, width) {
        for y in range(0, height) {
            let offset = normal.ind_sample(&mut rng) as u8;
            let px = img.get_pixel(x, y).map(|v| v + offset);
            noisy.put_pixel(x, y, px);
        }
    }
    let out = File::create(&Path::new("out.jpg")).unwrap();
    let _ = noisy.save(out, image::JPEG).ok().expect("Saving image failed");
}
<|endoftext|>


<commit_before>use crate::context::ContextError;
use std::any::TypeId;
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr;

#[cfg(backtrace)]
use std::backtrace::{Backtrace, BacktraceStatus};

/// The `Error` type, a wrapper around a dynamic error type.
///
/// `Error` works a lot like `Box<dyn std::error::Error>`, but with these
/// differences:
///
/// - `Error` requires that the error is `Send`, `Sync`, and `'static`.
/// - `Error` guarantees that a backtrace is available, even if the underlying
///   error type does not provide one.
/// - `Error` is represented as a narrow pointer — exactly one word in
///   size instead of two.
pub struct Error {
    inner: Box<ErrorImpl<()>>,
}

impl Error {
    /// Create a new error object from any error type.
    ///
    /// The error type must be threadsafe and `'static`, so that the `Error`
    /// will be as well.
    ///
    /// If the error type does not provide a backtrace, a backtrace will be
    /// created here to ensure that a backtrace exists.
    pub fn new<E>(error: E) -> Self
    where
        E: StdError + Send + Sync + 'static,
    {
        Error::construct(error, TypeId::of::<E>())
    }

    pub(crate) fn new_adhoc<M>(message: M) -> Self
    where
        M: Display + Debug + Send + Sync + 'static,
    {
        Error::construct(MessageError(message), TypeId::of::<M>())
    }

    fn construct<E>(error: E, type_id: TypeId) -> Self
    where
        E: StdError + Send + Sync + 'static,
    {
        #[cfg(backtrace)]
        let backtrace = match error.backtrace() {
            Some(_) => None,
            None => Some(Backtrace::capture()),
        };

        unsafe {
            let obj = mem::transmute::<&dyn StdError, TraitObject>(&error);
            let vtable = obj.vtable;
            let inner = Box::new(ErrorImpl {
                vtable,
                type_id,
                #[cfg(backtrace)]
                backtrace,
                error,
            });
            Error {
                inner: mem::transmute::<Box<ErrorImpl<E>>, Box<ErrorImpl<()>>>(inner),
            }
        }
    }

    /// Wrap the error value with additional context.
    pub fn context<C>(self, context: C) -> Self
    where
        C: Display + Send + Sync + 'static,
    {
        Error::from(ContextError {
            error: self,
            context,
        })
    }

    /// Get the backtrace for this Error.
    ///
    /// Backtraces are only available on the nightly channel. Tracking issue:
    /// [rust-lang/rust#53487][tracking].
    ///
    /// In order for the backtrace to be meaningful, the environment variable
    /// `RUST_LIB_BACKTRACE=1` must be defined. Backtraces are somewhat
    /// expensive to capture in Rust, so we don't necessarily want to be
    /// capturing them all over the place all the time.
    ///
    /// [tracking]: https://github.com/rust-lang/rust/issues/53487
    #[cfg(backtrace)]
    pub fn backtrace(&self) -> &Backtrace {
        // NB: this unwrap can only fail if the underlying error's backtrace
        // method is nondeterministic, which would only happen in maliciously
        // constructed code
        self.inner
            .backtrace
            .as_ref()
            .or_else(|| self.inner.error().backtrace())
            .expect("backtrace capture failed")
    }

    /// An iterator of the chain of source errors contained by this Error.
    ///
    /// This iterator will visit every error in the cause chain of this error
    /// object, beginning with the error that this error object was created
    /// from.
    pub fn chain(&self) -> Chain {
        Chain {
            next: Some(self.inner.error()),
        }
    }

    /// Returns `true` if `E` is the type wrapped by this error object.
    pub fn is<E>(&self) -> bool
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        TypeId::of::<E>() == self.inner.type_id
    }

    /// Attempt to downcast the error object to a concrete type.
    pub fn downcast<E>(self) -> Result<E, Self>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if let Some(error) = self.downcast_ref::<E>() {
            unsafe {
                let error = ptr::read(error);
                drop(ptr::read(&self.inner));
                mem::forget(self);
                Ok(error)
            }
        } else {
            Err(self)
        }
    }

    /// Downcast this error object by reference.
    pub fn downcast_ref<E>(&self) -> Option<&E>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if self.is::<E>() {
            unsafe { Some(&*(self.inner.error() as *const dyn StdError as *const E)) }
        } else {
            None
        }
    }

    /// Downcast this error object by mutable reference.
    pub fn downcast_mut<E>(&mut self) -> Option<&mut E>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if self.is::<E>() {
            unsafe { Some(&mut *(self.inner.error_mut() as *mut dyn StdError as *mut E)) }
        } else {
            None
        }
    }
}

impl<E> From<E> for Error
where
    E: StdError + Send + Sync + 'static,
{
    fn from(error: E) -> Self {
        Error::new(error)
    }
}

impl Deref for Error {
    type Target = dyn StdError + Send + Sync + 'static;

    fn deref(&self) -> &Self::Target {
        self.inner.error()
    }
}

impl DerefMut for Error {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.inner.error_mut()
    }
}

impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "{}", self.inner.error())?;

        let mut chain = self.chain().skip(1).enumerate();
        if let Some((n, error)) = chain.next() {
            writeln!(f, "\ncaused by:")?;
            writeln!(f, "\t{}: {}", n, error)?;
            for (n, error) in chain {
                writeln!(f, "\t{}: {}", n, error)?;
            }
        }

        #[cfg(backtrace)]
        {
            let backtrace = self.backtrace();
            match backtrace.status() {
                BacktraceStatus::Captured => {
                    writeln!(f, "\n{}", backtrace)?;
                }
                BacktraceStatus::Disabled => {
                    writeln!(
                        f,
                        "\nbacktrace disabled; run with RUST_LIB_BACKTRACE=1 environment variable to display a backtrace"
                    )?;
                }
                _ => {}
            }
        }

        Ok(())
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.inner.error())
    }
}

unsafe impl Send for Error {}
unsafe impl Sync for Error {}

impl Drop for Error {
    fn drop(&mut self) {
        unsafe { ptr::drop_in_place(self.inner.error_mut()) }
    }
}

// repr C to ensure that `E` remains in the final position
#[repr(C)]
struct ErrorImpl<E> {
    vtable: *const (),
    type_id: TypeId,
    #[cfg(backtrace)]
    backtrace: Option<Backtrace>,
    error: E,
}

// repr C to ensure that transmuting from trait objects is safe
#[repr(C)]
struct TraitObject {
    data: *const (),
    vtable: *const (),
}

#[repr(transparent)]
struct MessageError<M>(M);

impl<M> Debug for MessageError<M>
where
    M: Display + Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.0, f)
    }
}

impl<M> Display for MessageError<M>
where
    M: Display + Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.0, f)
    }
}

impl<M> StdError for MessageError<M> where M: Display + Debug + 'static {}

impl ErrorImpl<()> {
    fn error(&self) -> &(dyn StdError + Send + Sync + 'static) {
        let object = TraitObject {
            data: &self.error,
            vtable: self.vtable,
        };

        unsafe { mem::transmute::<TraitObject, &(dyn StdError + Send + Sync + 'static)>(object) }
    }

    fn error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
        let object = TraitObject {
            data: &mut self.error,
            vtable: self.vtable,
        };

        unsafe {
            mem::transmute::<TraitObject, &mut (dyn StdError + Send + Sync + 'static)>(object)
        }
    }
}

/// Iterator of a chain of source errors.
pub struct Chain<'a> {
    next: Option<&'a (dyn StdError + 'static)>,
}

impl<'a> Iterator for Chain<'a> {
    type Item = &'a (dyn StdError + 'static);

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.next.take()?;
        self.next = next.source();
        Some(next)
    }
}

#[cfg(test)]
mod repr_correctness {
    use super::*;
    use std::marker::Unpin;
    use std::mem;
    use std::sync::atomic::AtomicBool;
    use std::sync::atomic::Ordering::SeqCst;
    use std::sync::Arc;

    #[test]
    fn size_of_error() {
        assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>());
    }

    #[test]
    fn error_autotraits() {
        fn assert<E: Unpin + Send + Sync + 'static>() {}
        assert::<Error>();
    }

    #[test]
    fn drop_works() {
        #[derive(Debug)]
        struct DetectDrop {
            has_dropped: Arc<AtomicBool>,
        }

        impl StdError for DetectDrop {}

        impl Display for DetectDrop {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "does something")
            }
        }

        impl Drop for DetectDrop {
            fn drop(&mut self) {
                let already_dropped = self.has_dropped.swap(true, SeqCst);
                assert!(!already_dropped);
            }
        }

        let has_dropped = Arc::new(AtomicBool::new(false));

        drop(Error::from(DetectDrop {
            has_dropped: has_dropped.clone(),
        }));

        assert!(has_dropped.load(SeqCst));
    }
}
<commit_msg>Link to Context trait from Error::context method<commit_after>use crate::context::ContextError;
use std::any::TypeId;
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr;

#[cfg(backtrace)]
use std::backtrace::{Backtrace, BacktraceStatus};

/// The `Error` type, a wrapper around a dynamic error type.
///
/// `Error` works a lot like `Box<dyn std::error::Error>`, but with these
/// differences:
///
/// - `Error` requires that the error is `Send`, `Sync`, and `'static`.
/// - `Error` guarantees that a backtrace is available, even if the underlying
///   error type does not provide one.
/// - `Error` is represented as a narrow pointer — exactly one word in
///   size instead of two.
pub struct Error {
    inner: Box<ErrorImpl<()>>,
}

impl Error {
    /// Create a new error object from any error type.
    ///
    /// The error type must be threadsafe and `'static`, so that the `Error`
    /// will be as well.
    ///
    /// If the error type does not provide a backtrace, a backtrace will be
    /// created here to ensure that a backtrace exists.
    pub fn new<E>(error: E) -> Self
    where
        E: StdError + Send + Sync + 'static,
    {
        Error::construct(error, TypeId::of::<E>())
    }

    pub(crate) fn new_adhoc<M>(message: M) -> Self
    where
        M: Display + Debug + Send + Sync + 'static,
    {
        Error::construct(MessageError(message), TypeId::of::<M>())
    }

    fn construct<E>(error: E, type_id: TypeId) -> Self
    where
        E: StdError + Send + Sync + 'static,
    {
        #[cfg(backtrace)]
        let backtrace = match error.backtrace() {
            Some(_) => None,
            None => Some(Backtrace::capture()),
        };

        unsafe {
            let obj = mem::transmute::<&dyn StdError, TraitObject>(&error);
            let vtable = obj.vtable;
            let inner = Box::new(ErrorImpl {
                vtable,
                type_id,
                #[cfg(backtrace)]
                backtrace,
                error,
            });
            Error {
                inner: mem::transmute::<Box<ErrorImpl<E>>, Box<ErrorImpl<()>>>(inner),
            }
        }
    }

    /// Wrap the error value with additional context.
    ///
    /// For attaching context to a `Result` as it is propagated, the
    /// [`Context`][crate::Context] extension trait may be more convenient than
    /// this function.
    pub fn context<C>(self, context: C) -> Self
    where
        C: Display + Send + Sync + 'static,
    {
        Error::from(ContextError {
            error: self,
            context,
        })
    }

    /// Get the backtrace for this Error.
    ///
    /// Backtraces are only available on the nightly channel. Tracking issue:
    /// [rust-lang/rust#53487][tracking].
    ///
    /// In order for the backtrace to be meaningful, the environment variable
    /// `RUST_LIB_BACKTRACE=1` must be defined. Backtraces are somewhat
    /// expensive to capture in Rust, so we don't necessarily want to be
    /// capturing them all over the place all the time.
    ///
    /// [tracking]: https://github.com/rust-lang/rust/issues/53487
    #[cfg(backtrace)]
    pub fn backtrace(&self) -> &Backtrace {
        // NB: this unwrap can only fail if the underlying error's backtrace
        // method is nondeterministic, which would only happen in maliciously
        // constructed code
        self.inner
            .backtrace
            .as_ref()
            .or_else(|| self.inner.error().backtrace())
            .expect("backtrace capture failed")
    }

    /// An iterator of the chain of source errors contained by this Error.
    ///
    /// This iterator will visit every error in the cause chain of this error
    /// object, beginning with the error that this error object was created
    /// from.
    pub fn chain(&self) -> Chain {
        Chain {
            next: Some(self.inner.error()),
        }
    }

    /// Returns `true` if `E` is the type wrapped by this error object.
    pub fn is<E>(&self) -> bool
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        TypeId::of::<E>() == self.inner.type_id
    }

    /// Attempt to downcast the error object to a concrete type.
    pub fn downcast<E>(self) -> Result<E, Self>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if let Some(error) = self.downcast_ref::<E>() {
            unsafe {
                let error = ptr::read(error);
                drop(ptr::read(&self.inner));
                mem::forget(self);
                Ok(error)
            }
        } else {
            Err(self)
        }
    }

    /// Downcast this error object by reference.
    pub fn downcast_ref<E>(&self) -> Option<&E>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if self.is::<E>() {
            unsafe { Some(&*(self.inner.error() as *const dyn StdError as *const E)) }
        } else {
            None
        }
    }

    /// Downcast this error object by mutable reference.
    pub fn downcast_mut<E>(&mut self) -> Option<&mut E>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if self.is::<E>() {
            unsafe { Some(&mut *(self.inner.error_mut() as *mut dyn StdError as *mut E)) }
        } else {
            None
        }
    }
}

impl<E> From<E> for Error
where
    E: StdError + Send + Sync + 'static,
{
    fn from(error: E) -> Self {
        Error::new(error)
    }
}

impl Deref for Error {
    type Target = dyn StdError + Send + Sync + 'static;

    fn deref(&self) -> &Self::Target {
        self.inner.error()
    }
}

impl DerefMut for Error {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.inner.error_mut()
    }
}

impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "{}", self.inner.error())?;

        let mut chain = self.chain().skip(1).enumerate();
        if let Some((n, error)) = chain.next() {
            writeln!(f, "\ncaused by:")?;
            writeln!(f, "\t{}: {}", n, error)?;
            for (n, error) in chain {
                writeln!(f, "\t{}: {}", n, error)?;
            }
        }

        #[cfg(backtrace)]
        {
            let backtrace = self.backtrace();
            match backtrace.status() {
                BacktraceStatus::Captured => {
                    writeln!(f, "\n{}", backtrace)?;
                }
                BacktraceStatus::Disabled => {
                    writeln!(
                        f,
                        "\nbacktrace disabled; run with RUST_LIB_BACKTRACE=1 environment variable to display a backtrace"
                    )?;
                }
                _ => {}
            }
        }

        Ok(())
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.inner.error())
    }
}

unsafe impl Send for Error {}
unsafe impl Sync for Error {}

impl Drop for Error {
    fn drop(&mut self) {
        unsafe { ptr::drop_in_place(self.inner.error_mut()) }
    }
}

// repr C to ensure that `E` remains in the final position
#[repr(C)]
struct ErrorImpl<E> {
    vtable: *const (),
    type_id: TypeId,
    #[cfg(backtrace)]
    backtrace: Option<Backtrace>,
    error: E,
}

// repr C to ensure that transmuting from trait objects is safe
#[repr(C)]
struct TraitObject {
    data: *const (),
    vtable: *const (),
}

#[repr(transparent)]
struct MessageError<M>(M);

impl<M> Debug for MessageError<M>
where
    M: Display + Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.0, f)
    }
}

impl<M> Display for MessageError<M>
where
    M: Display + Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.0, f)
    }
}

impl<M> StdError for MessageError<M> where M: Display + Debug + 'static {}

impl ErrorImpl<()> {
    fn error(&self) -> &(dyn StdError + Send + Sync + 'static) {
        let object = TraitObject {
            data: &self.error,
            vtable: self.vtable,
        };

        unsafe { mem::transmute::<TraitObject, &(dyn StdError + Send + Sync + 'static)>(object) }
    }

    fn error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
        let object = TraitObject {
            data: &mut self.error,
            vtable: self.vtable,
        };

        unsafe {
            mem::transmute::<TraitObject, &mut (dyn StdError + Send + Sync + 'static)>(object)
        }
    }
}

/// Iterator of a chain of source errors.
pub struct Chain<'a> {
    next: Option<&'a (dyn StdError + 'static)>,
}

impl<'a> Iterator for Chain<'a> {
    type Item = &'a (dyn StdError + 'static);

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.next.take()?;
        self.next = next.source();
        Some(next)
    }
}

#[cfg(test)]
mod repr_correctness {
    use super::*;
    use std::marker::Unpin;
    use std::mem;
    use std::sync::atomic::AtomicBool;
    use std::sync::atomic::Ordering::SeqCst;
    use std::sync::Arc;

    #[test]
    fn size_of_error() {
        assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>());
    }

    #[test]
    fn error_autotraits() {
        fn assert<E: Unpin + Send + Sync + 'static>() {}
        assert::<Error>();
    }

    #[test]
    fn drop_works() {
        #[derive(Debug)]
        struct DetectDrop {
            has_dropped: Arc<AtomicBool>,
        }

        impl StdError for DetectDrop {}

        impl Display for DetectDrop {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "does something")
            }
        }

        impl Drop for DetectDrop {
            fn drop(&mut self) {
                let already_dropped = self.has_dropped.swap(true, SeqCst);
                assert!(!already_dropped);
            }
        }

        let has_dropped = Arc::new(AtomicBool::new(false));

        drop(Error::from(DetectDrop {
            has_dropped: has_dropped.clone(),
        }));

        assert!(has_dropped.load(SeqCst));
    }
}
<|endoftext|>


<commit_before>use libc::c_int;
use std::error::Error;
use std::fmt;

use ffi::nfq_errno;

#[derive(Debug)]
pub enum ErrorReason {
    OpenHandle,
    Bind,
    Unbind,
    CreateQueue,
    SetQueueMode,
    SetQueueMaxlen,
    SetVerdict,
    Unknown
}

pub struct NFQError {
    reason: ErrorReason,
    description: String,
    cause: Option<Box<Error>>,
}

impl fmt::Debug for NFQError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let msg = format!("{:?}: {:?} (cause: {:?})",
                          self.reason, self.description, self.cause);
        formatter.write_str(msg.as_ref())
    }
}

impl fmt::Display for NFQError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let msg = format!("{:?} ({:?})", self.reason, self.description);
        formatter.write_str(msg.as_ref())
    }
}

impl Error for NFQError {
    fn description(&self) -> &str {
        self.description.as_ref()
    }
    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|c| &**c)
    }
}

pub fn error(reason: ErrorReason, msg: &str, res: Option<c_int>) -> NFQError {
    let errno = unsafe { nfq_errno };
    let desc = match res {
        Some(r) => format!("{} (errno: {}, res: {})", msg, errno, r),
        None => format!("{}, (errno: {})", msg, errno)
    };
    NFQError {
        reason: reason,
        description: desc,
        cause: None,
    }
}
<commit_msg>Clean up warnings in error.rs<commit_after>use libc::c_int;
use std::error::Error;
use std::fmt;

use ffi::nfq_errno;

#[allow(dead_code)]
#[derive(Debug)]
pub enum ErrorReason {
    OpenHandle,
    Bind,
    Unbind,
    CreateQueue,
    SetQueueMode,
    SetQueueMaxlen,
    SetVerdict,
    Unknown
}

pub struct NFQError {
    reason: ErrorReason,
    description: String,
    cause: Option<Box<Error>>,
}

impl fmt::Debug for NFQError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let msg = format!("{:?}: {:?} (cause: {:?})",
                          self.reason, self.description, self.cause);
        formatter.write_str(msg.as_ref())
    }
}

impl fmt::Display for NFQError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let msg = format!("{:?} ({:?})", self.reason, self.description);
        formatter.write_str(msg.as_ref())
    }
}

impl Error for NFQError {
    fn description(&self) -> &str {
        self.description.as_ref()
    }
    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|c| &**c)
    }
}

pub fn error(reason: ErrorReason, msg: &str, res: Option<c_int>) -> NFQError {
    let errno = nfq_errno;
    let desc = match res {
        Some(r) => format!("{} (errno: {}, res: {})", msg, errno, r),
        None => format!("{}, (errno: {})", msg, errno)
    };
    NFQError {
        reason: reason,
        description: desc,
        cause: None,
    }
}
<|endoftext|>


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

use std::collections::BTreeMap;
use std::fs::{self, File};
use std::io::Write;
use std::path::{Path, PathBuf};
use std::time::{UNIX_EPOCH, SystemTime};
use std::fmt;
use rustc_serialize::json::{ToJson, Json};
use fs::svc_var_path;

// Macros to help hooking in the event logger into an Iron chain,
// and calling into the chained event logger.
#[macro_export]
macro_rules! define_event_log {
    () => {
        pub struct EventLog;
        impl typemap::Key for EventLog {
            type Value = EventLogger;
        }
    }
}

#[macro_export]
macro_rules! log_event {
    ($req:ident, $evt:expr) => {{
        let el = ($req).get::<persistent::Read<EventLog>>().unwrap();
        el.record_event($evt)
    }};
}

// Supported events
#[derive(Debug, Clone)]
pub enum Event<'a> {
    ProjectCreate {
        origin: &'a str,
        package: &'a str,
        account: &'a str,
    },
}

impl<'a> fmt::Display for Event<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let msg = match *self {
            Event::ProjectCreate { origin: _, package: _, account: _ } => "project-create",
        };
        write!(f, "{}", msg)
    }
}

impl<'a> ToJson for Event<'a> {
    fn to_json(&self) -> Json {
        let mut m = BTreeMap::new();
        m.insert("name".to_string(), self.to_string().to_json());

        match *self {
            Event::ProjectCreate { origin: ref o, package: ref p, account: ref a } => {
                m.insert("origin".to_string(), o.to_json());
                m.insert("package".to_string(), p.to_json());
                m.insert("account".to_string(), a.to_json());
            }
        };
        Json::Object(m)
    }
}

// Sample envelope JSON payload
// {
//   "timestamp": "1479330000.13442404",
//   "version": 1,
//   "event": {
//     "name": "project-create",
//     "origin" : "myorigin"
//     "package" : "mypackage"
//     "account" : "133508078967455744"
//   }
// }

pub const SCHEMA_VERSION: u32 = 1;

#[derive(Debug, Clone)]
pub struct Envelope<'a> {
    version: u32,
    timestamp: String,
    event: Event<'a>,
}

impl<'a> Envelope<'a> {
    pub fn new(event: &Event<'a>) -> Self {
        Envelope {
            version: SCHEMA_VERSION,
            timestamp: timestamp(),
            event: event.clone(),
        }
    }
}

impl<'a> ToJson for Envelope<'a> {
    fn to_json(&self) -> Json {
        let mut m = BTreeMap::new();
        m.insert("version".to_string(), self.version.to_json());
        m.insert("timestamp".to_string(), self.timestamp.to_json());
        m.insert("event".to_string(), self.event.to_json());

        Json::Object(m)
    }
}

fn write_file(parent_dir: &Path, file_path: &Path, content: &str) {
    fs::create_dir_all(parent_dir).expect("Unable to create directory");
    let mut file = File::create(&file_path).expect("Unable to create file");
    file.write_all(content.as_bytes()).expect("Unable to write file");
}

fn timestamp() -> String {
    let (secs, subsec_nanos) = match SystemTime::now().duration_since(UNIX_EPOCH) {
        Ok(duration) => (duration.as_secs(), duration.subsec_nanos()),
        Err(e) => {
            error!("Cannot generate system time: {}", e);
            return "0.0".to_string();
        }
    };
    format!("{}.{}", secs, subsec_nanos)
}

pub struct EventLogger {
    log_dir: PathBuf,
    enabled: bool,
}

impl EventLogger {
    pub fn new(service_name: &str, enabled: bool) -> Self {
        EventLogger {
            log_dir: svc_var_path(&service_name),
            enabled: enabled,
        }
    }

    pub fn record_event(&self, event: Event) {
        if self.enabled {
            let envelope = Envelope::new(&event);
            let file_path = self.log_dir.join(format!("event-{}.json", &envelope.timestamp));
            write_file(&self.log_dir, &file_path, &envelope.to_json().to_string());
        }
    }
}

#[cfg(test)]
mod test {
    use super::{EventLogger, Envelope, Event};
    use rustc_serialize::json::ToJson;

    #[test]
    fn event_to_json() {
        let event: Event = Event::ProjectCreate {
            origin: "myorigin",
            package: "mypackage",
            account: "myaccount",
        };

        let expected = r#"{"account":"myaccount","name":"project-create","origin":"myorigin","package":"mypackage"}"#;
        assert!(event.to_json().to_string() == expected.to_string());
    }

    #[test]
    fn envelope_to_json() {
        let event: Event = Event::ProjectCreate {
            origin: "myorigin",
            package: "mypackage",
            account: "myaccount",
        };

        let envelope = Envelope::new(&event);
        let expected =
            r#"{"event":{"account":"myaccount","name":"project-create","origin":"myorigin","package":"mypackage"}"#;
        assert!(envelope.to_json().to_string().starts_with(expected));
    }

    #[test]
    fn event_logger_path() {
        let event_logger: EventLogger = EventLogger::new("foo", true);
        let expected = r#"foo"#;
        match event_logger.log_dir.to_str() {
            Some(s) => assert!(s.contains(expected)),
            None => assert!(false),
        }
    }
}
<commit_msg>More infra and events for builder services<commit_after>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::BTreeMap;
use std::fs::{self, File};
use std::io::Write;
use std::path::{Path, PathBuf};
use std::time::{UNIX_EPOCH, SystemTime};
use std::fmt;
use rustc_serialize::json::{ToJson, Json};
use fs::svc_var_path;

// Macros to help hooking in the event logger into an Iron chain,
// and calling into the chained event logger.
#[macro_export]
macro_rules! define_event_log {
    () => {
        pub struct EventLog;
        impl typemap::Key for EventLog {
            type Value = EventLogger;
        }
    }
}

#[macro_export]
macro_rules! log_event {
    ($req:ident, $evt:expr) => {{
        let el = ($req).get::<persistent::Read<EventLog>>().unwrap();
        el.record_event($evt)
    }};
}

// Supported events
#[derive(Debug, Clone)]
pub enum Event<'a> {
    ProjectCreate {
        origin: &'a str,
        package: &'a str,
        account: &'a str,
    },
    PackageUpload {
        origin: &'a str,
        package: &'a str,
        version: &'a str,
        release: &'a str,
        account: &'a str,
    },
    OriginKeyUpload {
        origin: &'a str,
        version: &'a str,
        account: &'a str,
    },
    OriginSecretKeyUpload {
        origin: &'a str,
        version: &'a str,
        account: &'a str,
    },
    OriginInvitationSend {
        origin: &'a str,
        user: &'a str,
        id: &'a str,
        account: &'a str,
    },
    OriginInvitationAccept { id: &'a str, account: &'a str },
    OriginInvitationIgnore { id: &'a str, account: &'a str },
    JobCreate { package: &'a str, account: &'a str },
    GithubAuthenticate { user: &'a str, account: &'a str },
}

impl<'a> fmt::Display for Event<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let msg = match *self {
            Event::ProjectCreate { origin: _, package: _, account: _ } => "project-create",
            Event::PackageUpload { origin: _, package: _, version: _, release: _, account: _ } => {
                "package-upload"
            }
            Event::OriginKeyUpload { origin: _, version: _, account: _ } => "origin-key-upload",
            Event::OriginSecretKeyUpload { origin: _, version: _, account: _ } => "origin-secret-key-upload",
            Event::OriginInvitationSend { origin: _, user: _, id: _, account: _ } => "origin-invitation-send",
            Event::OriginInvitationAccept { id: _, account: _ } => "origin-invitation-accept",
            Event::OriginInvitationIgnore { id: _, account: _ } => "origin-invitation-ignore",
            Event::JobCreate { package: _, account: _ } => "job-create",
            Event::GithubAuthenticate { user: _, account: _ } => "github-authenticate",
        };

        write!(f, "{}", msg)
    }
}

impl<'a> ToJson for Event<'a> {
    fn to_json(&self) -> Json {
        let mut m = BTreeMap::new();
        m.insert("name".to_string(), self.to_string().to_json());

        match *self {
            Event::ProjectCreate { origin: ref o, package: ref p, account: ref a } => {
                m.insert("origin".to_string(), o.to_json());
                m.insert("package".to_string(), p.to_json());
                m.insert("account".to_string(), a.to_json());
            }
            Event::PackageUpload { origin: ref o,
                                   package: ref p,
                                   version: ref v,
                                   release: ref r,
                                   account: ref a } => {
                m.insert("origin".to_string(), o.to_json());
                m.insert("package".to_string(), p.to_json());
                m.insert("version".to_string(), v.to_json());
                m.insert("release".to_string(), r.to_json());
                m.insert("account".to_string(), a.to_json());
            }
            Event::OriginInvitationSend { origin: ref o,
                                          user: ref u,
                                          id: ref i,
                                          account: ref a } => {
                m.insert("origin".to_string(), o.to_json());
                m.insert("user".to_string(), u.to_json());
                m.insert("id".to_string(), i.to_json());
                m.insert("account".to_string(), a.to_json());
            }
            Event::OriginInvitationAccept { id: ref i, account: ref a } => {
                m.insert("id".to_string(), i.to_json());
                m.insert("account".to_string(), a.to_json());
            }
            Event::OriginInvitationIgnore { id: ref i, account: ref a } => {
                m.insert("id".to_string(), i.to_json());
                m.insert("account".to_string(), a.to_json());
            }
            Event::JobCreate { package: ref p, account: ref a } => {
                m.insert("package".to_string(), p.to_json());
                m.insert("account".to_string(), a.to_json());
            }
            Event::GithubAuthenticate { user: ref u, account: ref a } => {
                m.insert("user".to_string(), u.to_json());
                m.insert("account".to_string(), a.to_json());
            }
            Event::OriginKeyUpload { origin: ref o, version: ref v, account: ref a } => {
                m.insert("origin".to_string(), o.to_json());
                m.insert("version".to_string(), v.to_json());
                m.insert("account".to_string(), a.to_json());
            }
            Event::OriginSecretKeyUpload { origin: ref o, version: ref v, account: ref a } => {
                m.insert("origin".to_string(), o.to_json());
                m.insert("version".to_string(), v.to_json());
                m.insert("account".to_string(), a.to_json());
            }
        };
        Json::Object(m)
    }
}

// Sample envelope JSON payload
// {
//   "timestamp": "1479330000.13442404",
//   "version": 1,
//   "event": {
//     "name": "project-create",
//     "origin" : "myorigin"
//     "package" : "mypackage"
//     "account" : "133508078967455744"
//   }
// }

pub const SCHEMA_VERSION: u32 = 1;

#[derive(Debug, Clone)]
pub struct Envelope<'a> {
    version: u32,
    timestamp: String,
    event: Event<'a>,
}

impl<'a> Envelope<'a> {
    pub fn new(event: &Event<'a>) -> Self {
        Envelope {
            version: SCHEMA_VERSION,
            timestamp: timestamp(),
            event: event.clone(),
        }
    }
}

impl<'a> ToJson for Envelope<'a> {
    fn to_json(&self) -> Json {
        let mut m = BTreeMap::new();
        m.insert("version".to_string(), self.version.to_json());
        m.insert("timestamp".to_string(), self.timestamp.to_json());
        m.insert("event".to_string(), self.event.to_json());

        Json::Object(m)
    }
}

fn write_file(parent_dir: &Path, file_path: &Path, content: &str) {
    fs::create_dir_all(parent_dir).expect("Unable to create directory");
    let mut file = File::create(&file_path).expect("Unable to create file");
    file.write_all(content.as_bytes()).expect("Unable to write file");
}

fn timestamp() -> String {
    let (secs, subsec_nanos) = match SystemTime::now().duration_since(UNIX_EPOCH) {
        Ok(duration) => (duration.as_secs(), duration.subsec_nanos()),
        Err(e) => {
            error!("Cannot generate system time: {}", e);
            return "0.0".to_string();
        }
    };
    format!("{}.{}", secs, subsec_nanos)
}

pub struct EventLogger {
    log_dir: PathBuf,
    enabled: bool,
}

impl EventLogger {
    pub fn new(service_name: &str, enabled: bool) -> Self {
        EventLogger {
            log_dir: svc_var_path(&service_name),
            enabled: enabled,
        }
    }

    pub fn record_event(&self, event: Event) {
        if self.enabled {
            let envelope = Envelope::new(&event);
            let file_path = self.log_dir.join(format!("event-{}.json", &envelope.timestamp));
            write_file(&self.log_dir, &file_path, &envelope.to_json().to_string());
        }
    }
}

#[cfg(test)]
mod test {
    use super::{EventLogger, Envelope, Event};
    use rustc_serialize::json::ToJson;

    #[test]
    fn event_to_json() {
        let event: Event = Event::ProjectCreate {
            origin: "myorigin",
            package: "mypackage",
            account: "myaccount",
        };

        let expected = r#"{"account":"myaccount","name":"project-create","origin":"myorigin","package":"mypackage"}"#;
        assert!(event.to_json().to_string() == expected.to_string());
    }

    #[test]
    fn envelope_to_json() {
        let event: Event = Event::ProjectCreate {
            origin: "myorigin",
            package: "mypackage",
            account: "myaccount",
        };

        let envelope = Envelope::new(&event);
        let expected =
            r#"{"event":{"account":"myaccount","name":"project-create","origin":"myorigin","package":"mypackage"}"#;
        assert!(envelope.to_json().to_string().starts_with(expected));
    }

    #[test]
    fn event_logger_path() {
        let event_logger: EventLogger = EventLogger::new("foo", true);
        let expected = r#"foo"#;
        match event_logger.log_dir.to_str() {
            Some(s) => assert!(s.contains(expected)),
            None => assert!(false),
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::ops::Deref;
use std::slice::Iter;

use chrono::{DateTime, UTC};

use api::{CratesIO, ApiResponse, VersionData};
use errors::*;

#[derive(Debug)]
pub struct Version {
    pub num: String, // XXX should be semver::Version
    pub downloads: i32,
    pub created_at: DateTime<UTC>,
    pub updated_at: DateTime<UTC>,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
}

impl Version {
    fn from_versiondata(data: &VersionData) -> Self {
        Version {
            num: data.num.clone(),
            downloads: data.downloads,
            created_at: data.created_at,
            updated_at: data.updated_at,
            features: data.features.clone(),
            yanked: data.yanked,
        }
    }
}

#[derive(Debug)]
pub struct Versions {
    versions: Vec<Version>,
}

impl Versions {
    fn by_id(id: i32, versions: &[VersionData]) -> Option<&VersionData> {
        for v in versions {
            if id == v.id {
                return Some(v);
            }
        }
        None
    }

    fn from_crate_data(data: &ApiResponse) -> Self {
        let mut versions = Vec::new();
        if let Some(vers) = data.krate.versions.as_ref() {
            for id in vers {
                if let Some(versiondata) = Versions::by_id(*id, &data.versions) {
                    versions.push(Version::from_versiondata(versiondata))
                }
            }
        }
        Versions { versions: versions }
    }

    pub fn iter(&self) -> Iter<Version> {
        self.versions.iter()
    }
}

impl Deref for Versions {
    type Target = [Version];
    fn deref(&self) -> &[Version] {
        &self.versions
    }
}

#[derive(Debug)]
pub struct Crate {
    pub id: String,
    pub name: String,
    pub updated_at: DateTime<UTC>,
    pub created_at: DateTime<UTC>,
    pub downloads: i32,
    pub max_version: String, // XXX Should be semver::Version
    pub description: Option<String>,
    pub homepage: Option<String>,
    pub documentation: Option<String>,
    pub readme: Option<String>,
    pub license: Option<String>,
    pub repository: Option<String>,
    pub max_upload_size: Option<i32>,
    pub versions: Versions,
}

impl Crate {
    pub fn from_apiresponse(data: &ApiResponse) -> Result<Self> {
        let versions = Versions::from_crate_data(data);
        Ok(Crate {
               id: data.krate.id.clone(),
               name: data.krate.name.clone(),
               updated_at: data.krate.updated_at,
               created_at: data.krate.created_at,
               downloads: data.krate.downloads,
               max_version: data.krate.max_version.clone(),
               description: data.krate.description.clone(),
               homepage: data.krate.homepage.clone(),
               documentation: data.krate.documentation.clone(),
               readme: None,
               license: data.krate.license.clone(),
               repository: data.krate.repository.clone(),
               max_upload_size: None,
               versions: versions,
           })
    }

    pub fn by_name(name: &str) -> Result<Self> {
        let data = CratesIO::query(name)?.as_data()?;
        Crate::from_apiresponse(&data)
    }
}
<commit_msg>Add keywords<commit_after>use std::collections::HashMap;
use std::ops::Deref;
use std::slice::Iter;

use chrono::{DateTime, UTC};

use api::{CratesIO, ApiResponse, VersionData};
use errors::*;

#[derive(Debug)]
pub struct Version {
    pub num: String, // XXX should be semver::Version
    pub downloads: i32,
    pub created_at: DateTime<UTC>,
    pub updated_at: DateTime<UTC>,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
}

impl Version {
    fn from_versiondata(data: &VersionData) -> Self {
        Version {
            num: data.num.clone(),
            downloads: data.downloads,
            created_at: data.created_at,
            updated_at: data.updated_at,
            features: data.features.clone(),
            yanked: data.yanked,
        }
    }
}

#[derive(Debug)]
pub struct Versions {
    versions: Vec<Version>,
}

impl Versions {
    fn by_id(id: i32, versions: &[VersionData]) -> Option<&VersionData> {
        for v in versions {
            if id == v.id {
                return Some(v);
            }
        }
        None
    }

    fn from_crate_data(data: &ApiResponse) -> Self {
        let mut versions = Vec::new();
        if let Some(vers) = data.krate.versions.as_ref() {
            for id in vers {
                if let Some(versiondata) = Versions::by_id(*id, &data.versions) {
                    versions.push(Version::from_versiondata(versiondata))
                }
            }
        }
        Versions { versions: versions }
    }

    pub fn iter(&self) -> Iter<Version> {
        self.versions.iter()
    }
}

impl Deref for Versions {
    type Target = [Version];
    fn deref(&self) -> &[Version] {
        &self.versions
    }
}

#[derive(Debug)]
pub struct Crate {
    pub id: String,
    pub name: String,
    pub updated_at: DateTime<UTC>,
    pub created_at: DateTime<UTC>,
    pub downloads: i32,
    pub max_version: String, // XXX Should be semver::Version
    pub description: Option<String>,
    pub homepage: Option<String>,
    pub documentation: Option<String>,
    pub readme: Option<String>,
    pub license: Option<String>,
    pub repository: Option<String>,
    pub max_upload_size: Option<i32>,
    pub versions: Versions,
    pub keywords: Vec<String>,
}

impl Crate {
    pub fn from_apiresponse(data: &ApiResponse) -> Result<Self> {
        let versions = Versions::from_crate_data(data);
        let keywords = data.krate.keywords.clone().unwrap_or(Vec::new());
        Ok(Crate {
               id: data.krate.id.clone(),
               name: data.krate.name.clone(),
               updated_at: data.krate.updated_at,
               created_at: data.krate.created_at,
               downloads: data.krate.downloads,
               max_version: data.krate.max_version.clone(),
               description: data.krate.description.clone(),
               homepage: data.krate.homepage.clone(),
               documentation: data.krate.documentation.clone(),
               readme: None,
               license: data.krate.license.clone(),
               repository: data.krate.repository.clone(),
               max_upload_size: None,
               versions: versions,
               keywords: keywords,
           })
    }

    pub fn by_name(name: &str) -> Result<Self> {
        let data = CratesIO::query(name)?.as_data()?;
        Crate::from_apiresponse(&data)
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2014 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use std::vec::Vec;

use input_reader::InputReader;
use token::Token;
use token;

pub struct Lexer {
    priv input: InputReader,
    priv tokens: Vec<Token>
}

pub enum LexResult {
    Ok,
    Err(~str),
    End
}

impl Lexer {
    pub fn new(input: InputReader) -> Lexer {
        Lexer {
            input: input,
            tokens: Vec::new()
        }
    }

    pub fn execute(&mut self) -> Vec<Token> {
        loop {
            match self.lex_line() {
                Ok          => {/* continue */},
                Err(msg)    => { println!("error: {}", msg); break },
                End         => break
           }
        }
        self.tokens.clone()
    }

    fn next_is(&mut self, c: char) -> bool {
        match self.input.get() {
            Some(next_c) => {
                if next_c == c {
                    true
                } else {
                    self.input.unget(next_c);
                    false
                }
            },
            None         => {
                self.input.unget_eof();
                false
            }
        }
    }

    fn get_all(&mut self, c: char) -> bool {
        let mut len = 0;
        loop {
            match self.input.get() {
                Some(next_c) => {
                    if next_c == c {
                        len += 1;
                    } else {
                        self.input.unget(next_c);
                        break
                    }
                },
                None => { self.input.unget_eof(); break }
            }
        }
        if len > 0 {
            self.tokens.push(token::INDENT(c, len));
            true
        } else { false }
    }

    fn handle_indent(&mut self) {
        while self.get_all(' ') ||
            self.get_all('\t') {}
    }

    fn handle_plain_text(&mut self) {
        let mut content = ~"";
        loop {
            match self.input.get() {
                Some('\n')  => { self.input.unget('\n'); break },
                Some(c)     => content.push_char(c),
                None        => { self.input.unget_eof(); break }
            }
        }
        // remove whitespace before the text
        content = clean_plain_text_before(content.shift_char(), content);

        // remove whitespace after the text
        content = clean_plain_text_after(content.pop_char(), content);

        if content.len() > 0 {
            self.tokens.push(token::PLAIN_TEXT(content));
        }
    }

    fn handle_comments(&mut self) -> bool {
        match self.input.get() {
            Some('-')    => {
                match self.input.get() {
                    Some('#')    => {
                        self.tokens.push(token::HAML_COMMENT);
                        self.handle_plain_text();
                        true
                    }
                    Some(next_c) => {
                        self.input.unget(next_c);
                        self.input.unget('-');
                        false
                    },
                    None         => {
                        self.input.unget_eof();
                        self.input.unget('-');
                        false
                    }
                }
            }
            Some('/')    => {
                self.tokens.push(token::HTML_COMMENT);
                self.handle_plain_text();
                true
            }
            Some(next_c) => { self.input.unget(next_c); false },
            None         => { self.input.unget_eof(); false }
        }
    }

    fn handle_doctype(&mut self) {
        if self.next_is('!') {
            if self.next_is('!') {
                self.tokens.push(token::DOCTYPE)
            } else {
                self.input.unget('!');
                self.input.unget('!');
            }
        } else {
            self.input.unget('!')
        }
    }

    fn handle_identifier(&mut self) -> ~str{
        let mut name = ~"";
        loop {
            match self.input.get() {
                Some(c) => {
                    if c.is_alphanumeric() || c == '-' || c == '_' {
                        name.push_char(c);
                    } else {
                        self.input.unget(c);
                        break
                    }
                }
                None    =>  { self.input.unget_eof(); break }
            }
        }
        name
    }

    fn handle_tag(&mut self) {
        // check first if there is a '%' tag
        match self.input.get() {
            Some('%')     => {
                let identifier = self.handle_identifier();
                self.tokens.push(token::TAG(identifier));
            },
            Some(c_other) => self.input.unget(c_other),
            None          => self.input.unget_eof()
        };
        // then check for additionnal '.' class or '#' id
        loop {
            match self.input.get() {
                Some('!') => { self.handle_doctype(); break },
                Some('#') => {
                    let identifier = self.handle_identifier();
                    self.tokens.push(token::ID(identifier));
                },
                Some('.') => {
                    let identifier = self.handle_identifier();
                    self.tokens.push(token::CLASS(identifier));
                },
                Some(c_next) => { self.input.unget(c_next); break },
                None         => { self.input.unget_eof(); break }
            }
        }
    }

    fn handle_attribute(&mut self) {
        unimplemented!()
    }

    fn handle_escape_line(&mut self) {
        match self.input.get() {
            Some('\\')   => {
                self.input.unget('\\');
                self.handle_plain_text();
            },
            Some(next_c) => self.input.unget(next_c),
            None         => self.input.unget_eof()
        }
    }

    fn handle_assign(&mut self) {
        match self.input.get() {
            Some('=')    => self.tokens.push(token::ASSIGN),
            Some(next_c) => self.input.unget(next_c),
            None         => self.input.unget_eof()
        }
    }

    fn check_blankline(&mut self) {
        let i = self.tokens.len() - 1;
        if i == 0 { // only one token -> '\n'
            self.tokens.pop();
        } else {
            match self.tokens.get(i - 1) {
                &token::INDENT(_, _) => {
                    let pos = get_blankline_begin(&self.tokens, i - 1);
                    self.tokens.truncate(pos);
                },
                _                   => { /* do nothing  */ }
            }
        }

    }

    fn lex_line(&mut self) -> LexResult {
        self.handle_indent();
        self.handle_escape_line();
        // no comments found -> try to find a tag
        if !self.handle_comments() {
            self.handle_tag();
            // self.handle_attribute();
            self.handle_assign();
            self.handle_plain_text();
        }
        match self.input.get() {
            Some(_) => {
                self.tokens.push(token::EOL);
                self.check_blankline();
                Ok
            },
            None    => { self.tokens.push(token::EOF); End }
        }
    }
}

fn get_blankline_begin(v: &Vec<Token>, i: uint) -> uint {
    match v.get(i) {
        &token::INDENT(_, _) => {
            if i == 0 {
                i
            } else {
                get_blankline_begin(v, i - 1)
            }
        },
        _                   => i + 1
    }

}

fn clean_plain_text_after(c: Option<char>, mut content: ~str) -> ~str {
    match c {
        Some(' ') | Some('\t') => clean_plain_text_after(content.pop_char(),
                                                       content),
        Some(c)                => { content.push_char(c); content }
        _                      => content
    }
}

fn clean_plain_text_before(c: Option<char>, mut content: ~str) -> ~str {
    match c {
        Some(' ') | Some('\t') => clean_plain_text_before(content.shift_char(),
                                                       content),
        Some(c)                => { content.unshift_char(c); content }
        _                      => content
    }
}

<commit_msg>clean code<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2014 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use std::vec::Vec;

use input_reader::InputReader;
use token::Token;
use token;

pub struct Lexer {
    priv input: InputReader,
    priv tokens: Vec<Token>
}

pub enum LexResult {
    Ok,
    Err(~str),
    End
}

impl Lexer {
    pub fn new(input: InputReader) -> Lexer {
        Lexer {
            input: input,
            tokens: Vec::new()
        }
    }

    pub fn execute(&mut self) -> Vec<Token> {
        loop {
            match self.lex_line() {
                Ok          => {/* continue */},
                Err(msg)    => { println!("error: {}", msg); break },
                End         => break
           }
        }
        self.tokens.clone()
    }

    fn next_is(&mut self, c: char) -> bool {
        match self.input.get() {
            Some(next_c) => {
                if next_c == c {
                    true
                } else {
                    self.input.unget(next_c);
                    false
                }
            },
            None         => {
                self.input.unget_eof();
                false
            }
        }
    }

    fn get_all(&mut self, c: char) -> bool {
        let mut len = 0;
        loop {
            match self.input.get() {
                Some(next_c) => {
                    if next_c == c {
                        len += 1;
                    } else {
                        self.input.unget(next_c);
                        break
                    }
                },
                None => { self.input.unget_eof(); break }
            }
        }
        if len > 0 {
            self.tokens.push(token::INDENT(c, len));
            true
        } else { false }
    }

    fn handle_indent(&mut self) {
        while self.get_all(' ') ||
            self.get_all('\t') {}
    }

    fn handle_plain_text(&mut self) {
        fn clean_plain_text_after(c: Option<char>, mut content: ~str) -> ~str {
            match c {
                Some(' ') | Some('\t') =>
                    clean_plain_text_after(content.pop_char(), content),
                Some(c)                => { content.push_char(c); content }
                _                      => content
            }
        }

        fn clean_plain_text_before(c: Option<char>, mut content: ~str) -> ~str {
            match c {
                Some(' ') | Some('\t') =>
                    clean_plain_text_before(content.shift_char(), content),
                Some(c)                => { content.unshift_char(c); content }
                _                      => content
            }
        }

        let mut content = ~"";
        loop {
            match self.input.get() {
                Some('\n')  => { self.input.unget('\n'); break },
                Some(c)     => content.push_char(c),
                None        => { self.input.unget_eof(); break }
            }
        }

        // remove whitespace before the text
        content = clean_plain_text_before(content.shift_char(), content);
        // remove whitespace after the text
        content = clean_plain_text_after(content.pop_char(), content);

        if content.len() > 0 {
            self.tokens.push(token::PLAIN_TEXT(content));
        }
    }

    fn handle_comments(&mut self) -> bool {
        match self.input.get() {
            Some('-')    => {
                match self.input.get() {
                    Some('#')    => {
                        self.tokens.push(token::HAML_COMMENT);
                        self.handle_plain_text();
                        true
                    }
                    Some(next_c) => {
                        self.input.unget(next_c);
                        self.input.unget('-');
                        false
                    },
                    None         => {
                        self.input.unget_eof();
                        self.input.unget('-');
                        false
                    }
                }
            }
            Some('/')    => {
                self.tokens.push(token::HTML_COMMENT);
                self.handle_plain_text();
                true
            }
            Some(next_c) => { self.input.unget(next_c); false },
            None         => { self.input.unget_eof(); false }
        }
    }

    fn handle_doctype(&mut self) {
        if self.next_is('!') {
            if self.next_is('!') {
                self.tokens.push(token::DOCTYPE)
            } else {
                self.input.unget('!');
                self.input.unget('!');
            }
        } else {
            self.input.unget('!')
        }
    }

    fn handle_identifier(&mut self) -> ~str{
        let mut name = ~"";
        loop {
            match self.input.get() {
                Some(c) => {
                    if c.is_alphanumeric() || c == '-' || c == '_' {
                        name.push_char(c);
                    } else {
                        self.input.unget(c);
                        break
                    }
                }
                None    =>  { self.input.unget_eof(); break }
            }
        }
        name
    }

    fn handle_tag(&mut self) {
        // check first if there is a '%' tag
        match self.input.get() {
            Some('%')     => {
                let identifier = self.handle_identifier();
                self.tokens.push(token::TAG(identifier));
            },
            Some(c_other) => self.input.unget(c_other),
            None          => self.input.unget_eof()
        };
        // then check for additionnal '.' class or '#' id
        loop {
            match self.input.get() {
                Some('!') => { self.handle_doctype(); break },
                Some('#') => {
                    let identifier = self.handle_identifier();
                    self.tokens.push(token::ID(identifier));
                },
                Some('.') => {
                    let identifier = self.handle_identifier();
                    self.tokens.push(token::CLASS(identifier));
                },
                Some(c_next) => { self.input.unget(c_next); break },
                None         => { self.input.unget_eof(); break }
            }
        }
    }

    fn handle_attribute(&mut self) {
        unimplemented!()
    }

    fn handle_escape_line(&mut self) {
        match self.input.get() {
            Some('\\')   => {
                self.input.unget('\\');
                self.handle_plain_text();
            },
            Some(next_c) => self.input.unget(next_c),
            None         => self.input.unget_eof()
        }
    }

    fn handle_assign(&mut self) {
        match self.input.get() {
            Some('=')    => self.tokens.push(token::ASSIGN),
            Some(next_c) => self.input.unget(next_c),
            None         => self.input.unget_eof()
        }
    }

    fn check_blankline(&mut self) {
        fn get_blankline_begin(v: &Vec<Token>, i: uint) -> uint {
            match v.get(i) {
                &token::INDENT(_, _) => {
                    if i == 0 { i }
                    else { get_blankline_begin(v, i - 1) }
                },
                _                   => i + 1
            }
        }

        let i = self.tokens.len() - 1;
        if i == 0 { // only one token -> EOL
            self.tokens.pop();
        } else { // line with only INDENT + EOL tokens
            match self.tokens.get(i - 1) {
                &token::INDENT(_, _) => {
                    let pos = get_blankline_begin(&self.tokens, i - 1);
                    self.tokens.truncate(pos);
                },
                _                   => { /* do nothing  */ }
            }
        }

    }

    fn lex_line(&mut self) -> LexResult {
        self.handle_indent();
        self.handle_escape_line();
        // no comments found -> try to find a tag
        if !self.handle_comments() {
            self.handle_tag();
            // self.handle_attribute();
            self.handle_assign();
            self.handle_plain_text();
        }
        match self.input.get() {
            Some(_) => {
                self.tokens.push(token::EOL);
                self.check_blankline();
                Ok
            },
            None    => { self.tokens.push(token::EOF); End }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Set a limit of 1000 tokens when searching for the function name<commit_after><|endoftext|>