<commit_before>extern crate env_logger;
extern crate git2;
#[macro_use]
extern crate log;
extern crate tools;
extern crate unicode_normalization;

use std::borrow::Borrow;
use std::collections::HashMap;
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;

use git2::{DiffFindOptions, ObjectType, Oid, Patch, Repository, Sort};
use tools::config::index_blame;
use tools::git_ops;
use unicode_normalization::UnicodeNormalization;

fn get_hg_rev(git_repo: &Repository, git_oid: &Oid) -> Option<String> {
    // TODO: start a helper process and stream I/O to it instead of spawning a new process every time
    let output = Command::new("git")
        .arg("cinnabar")
        .arg("git2hg")
        .arg(format!("{}", git_oid))
        .current_dir(git_repo.path())
        .output()
        .unwrap();
    if !output.status.success() {
        panic!("`git cinnabar git2hg {}` returned error code {:?}", git_oid, output.status.code());
    }
    match git_ops::decode_bytes(output.stdout).lines().next() {
        Some(r) if r != "0000000000000000000000000000000000000000" => Some(r.to_string()),
        _ => None,
    }
}

fn count_lines(blob: &git2::Blob) -> usize {
    let data = blob.content();
    if data.is_empty() {
        return 0;
    }
    let mut linecount = 0;
    for b in data {
        if *b == b'\n' {
            linecount += 1;
        }
    }
    if data[data.len() - 1] != b'\n' {
        linecount += 1;
    }
    linecount
}

fn unmodified_lines(
    blob: &git2::Blob,
    parent_blob: &git2::Blob,
) -> Result<Vec<(usize, usize)>, git2::Error> {
    let mut unchanged = Vec::new();

    let patch = Patch::from_blobs(parent_blob, None, blob, None, None)?;

    if patch.delta().flags().is_binary() {
        return Ok(unchanged);
    }

    fn add_delta(lineno: usize, delta: i32) -> usize {
        ((lineno as i32) + delta) as usize
    }

    let mut latest_line: usize = 0;
    let mut delta: i32 = 0;

    for hunk_index in 0..patch.num_hunks() {
        for line_index in 0..patch.num_lines_in_hunk(hunk_index)? {
            let line = patch.line_in_hunk(hunk_index, line_index)?;

            if let Some(lineno) = line.new_lineno() {
                let lineno = lineno as usize;
                for i in latest_line..lineno - 1 {
                    unchanged.push((i, add_delta(i, delta)));
                }
                latest_line = (lineno - 1) + 1;
            }

            match line.origin() {
                '+' => delta -= 1,
                '-' => delta += 1,
                ' ' => {
                    assert_eq!(
                        line.old_lineno().unwrap() as usize,
                        add_delta(line.new_lineno().unwrap() as usize, delta)
                    );
                    unchanged.push((
                        (line.new_lineno().unwrap() - 1) as usize,
                        (line.old_lineno().unwrap() - 1) as usize,
                    ));
                }
                _ => (),
            };
        }
    }

    let linecount = count_lines(blob);
    for i in latest_line..linecount {
        unchanged.push((i, add_delta(i, delta)));
    }
    Ok(unchanged)
}

fn blame_for_path(
    file_movement: &HashMap<Oid, HashMap<Oid, PathBuf>>,
    git_repo: &git2::Repository,
    commit: &git2::Commit,
    blame_repo: &git2::Repository,
    blame_parents: &[git2::Commit],
    path: &Path,
) -> Result<String, git2::Error> {
    let blob = commit
        .tree()?
        .get_path(path)?
        .to_object(git_repo)?
        .peel_to_blob()?;
    let linecount = count_lines(&blob);
    // TODO: drop this author field entirely, I don't think it gets consumed by anything
    let commit_id = commit.id();
    let author = commit
        .author()
        .name()
        .map(|n| n.nfkd().filter(|c| c.is_ascii()).collect::<String>())
        .unwrap_or_default();
    let mut blame = Vec::with_capacity(linecount);
    for line in 1..=linecount {
        blame.push(format!("{}:%:{}:{}", commit_id, line, author));
    }

    for (parent, blame_parent) in commit.parents().zip(blame_parents.iter()).rev() {
        let parent_path = file_movement
            .get(&parent.id())
            .and_then(|m| m.get(&blob.id()))
            .map(|p| p.borrow())
            .unwrap_or(path);
        let parent_blob = match parent.tree()?.get_path(parent_path) {
            Ok(t) if t.kind() == Some(ObjectType::Blob) => t.to_object(git_repo)?.peel_to_blob()?,
            _ => {
                continue;
            }
        };
        let parent_blame_blob = match blame_parent.tree()?.get_path(parent_path) {
            Ok(entry) => entry.to_object(blame_repo)?.peel_to_blob()?,
            _ => continue,
        };
        let parent_blame = std::str::from_utf8(parent_blame_blob.content())
            .unwrap() // We only ever put ascii in the blame blob (for now)
            .lines()
            .collect::<Vec<&str>>();

        let path_unchanged = path == parent_path;
        for (lineno, parent_lineno) in unmodified_lines(&blob, &parent_blob)? {
            if path_unchanged {
                blame[lineno] = String::from(parent_blame[parent_lineno]);
                continue;
            }
            let mut pieces = parent_blame[parent_lineno].splitn(4, ':');
            let p_rev = pieces.next().unwrap();
            let mut p_fname = pieces.next().unwrap();
            let p_lineno = pieces.next().unwrap();
            let p_author = pieces.next().unwrap();
            if p_fname == "%" {
                p_fname = parent_path.to_str().unwrap();
            }
            blame[lineno] = format!("{}:{}:{}:{}", p_rev, p_fname, p_lineno, p_author);
        }
    }
    // Extra entry so the `join` call after adds a trailing newline
    blame.push(String::new());
    Ok(blame.join("\n"))
}

fn build_blame_tree(
    builder: &mut git2::TreeBuilder,
    file_movement: &HashMap<Oid, HashMap<Oid, PathBuf>>,
    git_repo: &git2::Repository,
    commit: &git2::Commit,
    blame_repo: &git2::Repository,
    blame_parents: &[git2::Commit],
    mut path: PathBuf,
) -> Result<(), git2::Error> {
    let tree_at_path = if path == PathBuf::new() {
        commit.tree()?
    } else {
        commit
            .tree()?
            .get_path(&path)?
            .to_object(git_repo)?
            .peel_to_tree()?
    };
    'outer: for entry in tree_at_path.iter() {
        path.push(entry.name().unwrap());
        for (i, parent) in commit.parents().enumerate() {
            if let Ok(parent_entry) = parent.tree()?.get_path(&path) {
                if parent_entry.id() == entry.id() {
                    // Item at `path` is the same in the tree for `commit` as in the tree
                    // for `parent`, so the blame must be the same too
                    let blame_parent_entry = blame_parents[i].tree()?.get_path(&path)?;
                    builder.insert(
                        entry.name().unwrap(),
                        blame_parent_entry.id(),
                        entry.filemode(),
                    )?;
                    path.pop();
                    continue 'outer;
                }
            }
        }

        match entry.kind() {
            Some(ObjectType::Blob) => {
                let blame_text = blame_for_path(
                    file_movement,
                    git_repo,
                    commit,
                    blame_repo,
                    blame_parents,
                    &path,
                )?;
                builder.insert(
                    entry.name().unwrap(),
                    blame_repo.blob(&blame_text.as_bytes())?,
                    entry.filemode(),
                )?;
            }
            Some(ObjectType::Commit) => {
                // This is a submodule, just treat it as an empty dir. We could
                // probably also skip over it entirely.
                let entry_builder = blame_repo.treebuilder(None)?;
                builder.insert(
                    entry.name().unwrap(),
                    entry_builder.write()?,
                    entry.filemode(),
                )?;
            }
            Some(ObjectType::Tree) => {
                let mut entry_builder = blame_repo.treebuilder(None)?;
                build_blame_tree(
                    &mut entry_builder,
                    file_movement,
                    git_repo,
                    commit,
                    blame_repo,
                    blame_parents,
                    path.clone(),
                )?;
                builder.insert(
                    entry.name().unwrap(),
                    entry_builder.write()?,
                    entry.filemode(),
                )?;
            }
            _ => {
                panic!(
                    "Unexpected entry kind {:?} found in tree for commit {:?} at path {:?}",
                    entry.kind(),
                    commit.id(),
                    path
                );
            }
        };

        path.pop();
    }

    Ok(())
}

fn main() {
    env_logger::init();

    let args: Vec<_> = env::args().collect();
    let git_repo = Repository::open(&args[1]).unwrap();
    let blame_repo = Repository::open(&args[2]).unwrap();
    let use_cinnabar = env::var("CINNABAR").map(|v| v == "1").unwrap_or(false);
    let blame_ref = env::var("BLAME_REF").ok().unwrap_or("HEAD".to_string());

    info!("Reading existing blame map of ref {}...", blame_ref);
    let mut blame_map = if let Ok(oid) = blame_repo.refname_to_id(&blame_ref) {
        let (blame_map, _) = index_blame(&blame_repo, Some(oid));
        blame_map
    } else {
        HashMap::new()
    };

    let mut refobj = blame_repo
        .find_reference(&blame_ref)
        .ok()
        .and_then(|r| r.resolve().ok());

    let mut walk = git_repo.revwalk().unwrap();
    walk.set_sorting(Sort::TOPOLOGICAL | Sort::REVERSE).unwrap();
    walk.push(git_repo.refname_to_id(&blame_ref).unwrap())
        .unwrap();
    let revs_to_process = walk
        .map(|r| r.unwrap()) // walk produces Result<git2::Oid> so we unwrap to just the Oid
        .filter(|git_oid| !blame_map.contains_key(git_oid))
        .collect::<Vec<_>>();
    let rev_count = revs_to_process.len();

    info!("Transforming new commits...");

    let mut rev_done = 0;
    for git_oid in revs_to_process {
        rev_done += 1;

        let hg_rev = if use_cinnabar {
            get_hg_rev(&git_repo, &git_oid)
        } else {
            // we don't support mapfiles any more.
            None
        };

        info!(
            "Transforming {} (hg {:?}) progress {}/{}",
            git_oid, hg_rev, rev_done, rev_count
        );
        let commit = git_repo.find_commit(git_oid).unwrap();
        let blame_parents = commit
            .parent_ids()
            .map(|pid| blame_repo.find_commit(blame_map[&pid]).unwrap())
            .collect::<Vec<_>>();

        let mut file_movement = HashMap::new();
        if commit.parent_count() == 1 {
            let mut movement = HashMap::new();
            let mut diff = git_repo
                .diff_tree_to_tree(
                    Some(&commit.parent(0).unwrap().tree().unwrap()),
                    Some(&commit.tree().unwrap()),
                    None,
                )
                .unwrap();
            diff.find_similar(Some(
                DiffFindOptions::new().copies(true).rename_limit(1000000),
            ))
            .unwrap();
            for delta in diff.deltas() {
                if !delta.old_file().id().is_zero()
                    && !delta.new_file().id().is_zero()
                    && delta.old_file().path() != delta.new_file().path()
                {
                    movement.insert(
                        delta.new_file().id(),
                        delta.old_file().path().unwrap().to_path_buf(),
                    );
                }
            }
            file_movement.insert(commit.parent_id(0).unwrap(), movement);
        }

        let mut builder = blame_repo.treebuilder(None).unwrap();
        build_blame_tree(
            &mut builder,
            &file_movement,
            &git_repo,
            &commit,
            &blame_repo,
            &blame_parents,
            PathBuf::new(),
        )
        .unwrap();
        let tree_oid = builder.write().unwrap();

        let commit_msg = if let Some(hg_rev) = hg_rev {
            format!("git {}\nhg {}\n", git_oid, hg_rev)
        } else {
            format!("git {}\n", git_oid)
        };

        let commit_ref = if refobj.is_some() {
            None
        } else {
            // This should only happen on the first commit, if the blame_ref
            // doesn't exist yet in the destination repo
            Some(blame_ref.as_str())
        };
        let blame_oid = blame_repo
            .commit(
                commit_ref,
                &commit.author(),
                &commit.committer(),
                &commit_msg,
                &blame_repo.find_tree(tree_oid).unwrap(),
                &blame_parents.iter().collect::<Vec<_>>(),
            )
            .unwrap();

        if let Some(ref mut refobj) = refobj {
            *refobj = refobj.set_target(blame_oid, "").unwrap();
        } else {
            refobj = blame_repo
                .find_reference(&blame_ref)
                .ok()
                .and_then(|r| r.resolve().ok());
            assert!(refobj.is_some());
        }

        blame_map.insert(git_oid, blame_oid);
        info!("  -> {}", blame_oid);
    }
}
<commit_msg>Bug 1627532 - Enhancement to stream cinnabar results.<commit_after>extern crate env_logger;
extern crate git2;
#[macro_use]
extern crate log;
extern crate tools;
extern crate unicode_normalization;

use std::borrow::Borrow;
use std::collections::HashMap;
use std::env;
use std::io::{BufRead, BufReader, Write};
use std::path::{Path, PathBuf};
use std::process::{Child, Command, Stdio};

use git2::{DiffFindOptions, ObjectType, Oid, Patch, Repository, Sort};
use tools::config::index_blame;
use unicode_normalization::UnicodeNormalization;

fn get_hg_rev(helper: &mut Child, git_oid: &Oid) -> Option<String> {
    write!(helper.stdin.as_mut().unwrap(), "git2hg {}\n", git_oid).unwrap();
    let mut reader = BufReader::new(helper.stdout.as_mut().unwrap());
    loop {
        let mut result = String::new();
        reader.read_line(&mut result).unwrap();
        if result.starts_with("changeset ") {
            return result.split(' ').nth(1).map(str::trim).map(str::to_string);
        }
        if result.trim().chars().all(|c| c == '0') {
            return None;
        }
        // else loop again. cinnabar-helper emits a bunch of other info that we don't care about
    }
}

fn start_cinnabar_helper(git_repo: &Repository) -> Child {
    Command::new("git")
        .arg("cinnabar-helper")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .current_dir(git_repo.path())
        .spawn()
        .unwrap()
}

fn count_lines(blob: &git2::Blob) -> usize {
    let data = blob.content();
    if data.is_empty() {
        return 0;
    }
    let mut linecount = 0;
    for b in data {
        if *b == b'\n' {
            linecount += 1;
        }
    }
    if data[data.len() - 1] != b'\n' {
        linecount += 1;
    }
    linecount
}

fn unmodified_lines(
    blob: &git2::Blob,
    parent_blob: &git2::Blob,
) -> Result<Vec<(usize, usize)>, git2::Error> {
    let mut unchanged = Vec::new();

    let patch = Patch::from_blobs(parent_blob, None, blob, None, None)?;

    if patch.delta().flags().is_binary() {
        return Ok(unchanged);
    }

    fn add_delta(lineno: usize, delta: i32) -> usize {
        ((lineno as i32) + delta) as usize
    }

    let mut latest_line: usize = 0;
    let mut delta: i32 = 0;

    for hunk_index in 0..patch.num_hunks() {
        for line_index in 0..patch.num_lines_in_hunk(hunk_index)? {
            let line = patch.line_in_hunk(hunk_index, line_index)?;

            if let Some(lineno) = line.new_lineno() {
                let lineno = lineno as usize;
                for i in latest_line..lineno - 1 {
                    unchanged.push((i, add_delta(i, delta)));
                }
                latest_line = (lineno - 1) + 1;
            }

            match line.origin() {
                '+' => delta -= 1,
                '-' => delta += 1,
                ' ' => {
                    assert_eq!(
                        line.old_lineno().unwrap() as usize,
                        add_delta(line.new_lineno().unwrap() as usize, delta)
                    );
                    unchanged.push((
                        (line.new_lineno().unwrap() - 1) as usize,
                        (line.old_lineno().unwrap() - 1) as usize,
                    ));
                }
                _ => (),
            };
        }
    }

    let linecount = count_lines(blob);
    for i in latest_line..linecount {
        unchanged.push((i, add_delta(i, delta)));
    }
    Ok(unchanged)
}

fn blame_for_path(
    file_movement: &HashMap<Oid, HashMap<Oid, PathBuf>>,
    git_repo: &git2::Repository,
    commit: &git2::Commit,
    blame_repo: &git2::Repository,
    blame_parents: &[git2::Commit],
    path: &Path,
) -> Result<String, git2::Error> {
    let blob = commit
        .tree()?
        .get_path(path)?
        .to_object(git_repo)?
        .peel_to_blob()?;
    let linecount = count_lines(&blob);
    // TODO: drop this author field entirely, I don't think it gets consumed by anything
    let commit_id = commit.id();
    let author = commit
        .author()
        .name()
        .map(|n| n.nfkd().filter(|c| c.is_ascii()).collect::<String>())
        .unwrap_or_default();
    let mut blame = Vec::with_capacity(linecount);
    for line in 1..=linecount {
        blame.push(format!("{}:%:{}:{}", commit_id, line, author));
    }

    for (parent, blame_parent) in commit.parents().zip(blame_parents.iter()).rev() {
        let parent_path = file_movement
            .get(&parent.id())
            .and_then(|m| m.get(&blob.id()))
            .map(|p| p.borrow())
            .unwrap_or(path);
        let parent_blob = match parent.tree()?.get_path(parent_path) {
            Ok(t) if t.kind() == Some(ObjectType::Blob) => t.to_object(git_repo)?.peel_to_blob()?,
            _ => {
                continue;
            }
        };
        let parent_blame_blob = match blame_parent.tree()?.get_path(parent_path) {
            Ok(entry) => entry.to_object(blame_repo)?.peel_to_blob()?,
            _ => continue,
        };
        let parent_blame = std::str::from_utf8(parent_blame_blob.content())
            .unwrap() // We only ever put ascii in the blame blob (for now)
            .lines()
            .collect::<Vec<&str>>();

        let path_unchanged = path == parent_path;
        for (lineno, parent_lineno) in unmodified_lines(&blob, &parent_blob)? {
            if path_unchanged {
                blame[lineno] = String::from(parent_blame[parent_lineno]);
                continue;
            }
            let mut pieces = parent_blame[parent_lineno].splitn(4, ':');
            let p_rev = pieces.next().unwrap();
            let mut p_fname = pieces.next().unwrap();
            let p_lineno = pieces.next().unwrap();
            let p_author = pieces.next().unwrap();
            if p_fname == "%" {
                p_fname = parent_path.to_str().unwrap();
            }
            blame[lineno] = format!("{}:{}:{}:{}", p_rev, p_fname, p_lineno, p_author);
        }
    }
    // Extra entry so the `join` call after adds a trailing newline
    blame.push(String::new());
    Ok(blame.join("\n"))
}

fn build_blame_tree(
    builder: &mut git2::TreeBuilder,
    file_movement: &HashMap<Oid, HashMap<Oid, PathBuf>>,
    git_repo: &git2::Repository,
    commit: &git2::Commit,
    blame_repo: &git2::Repository,
    blame_parents: &[git2::Commit],
    mut path: PathBuf,
) -> Result<(), git2::Error> {
    let tree_at_path = if path == PathBuf::new() {
        commit.tree()?
    } else {
        commit
            .tree()?
            .get_path(&path)?
            .to_object(git_repo)?
            .peel_to_tree()?
    };
    'outer: for entry in tree_at_path.iter() {
        path.push(entry.name().unwrap());
        for (i, parent) in commit.parents().enumerate() {
            if let Ok(parent_entry) = parent.tree()?.get_path(&path) {
                if parent_entry.id() == entry.id() {
                    // Item at `path` is the same in the tree for `commit` as in the tree
                    // for `parent`, so the blame must be the same too
                    let blame_parent_entry = blame_parents[i].tree()?.get_path(&path)?;
                    builder.insert(
                        entry.name().unwrap(),
                        blame_parent_entry.id(),
                        entry.filemode(),
                    )?;
                    path.pop();
                    continue 'outer;
                }
            }
        }

        match entry.kind() {
            Some(ObjectType::Blob) => {
                let blame_text = blame_for_path(
                    file_movement,
                    git_repo,
                    commit,
                    blame_repo,
                    blame_parents,
                    &path,
                )?;
                builder.insert(
                    entry.name().unwrap(),
                    blame_repo.blob(&blame_text.as_bytes())?,
                    entry.filemode(),
                )?;
            }
            Some(ObjectType::Commit) => {
                // This is a submodule, just treat it as an empty dir. We could
                // probably also skip over it entirely.
                let entry_builder = blame_repo.treebuilder(None)?;
                builder.insert(
                    entry.name().unwrap(),
                    entry_builder.write()?,
                    entry.filemode(),
                )?;
            }
            Some(ObjectType::Tree) => {
                let mut entry_builder = blame_repo.treebuilder(None)?;
                build_blame_tree(
                    &mut entry_builder,
                    file_movement,
                    git_repo,
                    commit,
                    blame_repo,
                    blame_parents,
                    path.clone(),
                )?;
                builder.insert(
                    entry.name().unwrap(),
                    entry_builder.write()?,
                    entry.filemode(),
                )?;
            }
            _ => {
                panic!(
                    "Unexpected entry kind {:?} found in tree for commit {:?} at path {:?}",
                    entry.kind(),
                    commit.id(),
                    path
                );
            }
        };

        path.pop();
    }

    Ok(())
}

fn main() {
    env_logger::init();

    let args: Vec<_> = env::args().collect();
    let git_repo = Repository::open(&args[1]).unwrap();
    let blame_repo = Repository::open(&args[2]).unwrap();
    let use_cinnabar = env::var("CINNABAR").map(|v| v == "1").unwrap_or(false);
    let mut hg_helper = if use_cinnabar {
        Some(start_cinnabar_helper(&git_repo))
    } else {
        None
    };
    let blame_ref = env::var("BLAME_REF").ok().unwrap_or("HEAD".to_string());

    info!("Reading existing blame map of ref {}...", blame_ref);
    let mut blame_map = if let Ok(oid) = blame_repo.refname_to_id(&blame_ref) {
        let (blame_map, _) = index_blame(&blame_repo, Some(oid));
        blame_map
    } else {
        HashMap::new()
    };

    let mut refobj = blame_repo
        .find_reference(&blame_ref)
        .ok()
        .and_then(|r| r.resolve().ok());

    let mut walk = git_repo.revwalk().unwrap();
    walk.set_sorting(Sort::TOPOLOGICAL | Sort::REVERSE).unwrap();
    walk.push(git_repo.refname_to_id(&blame_ref).unwrap())
        .unwrap();
    let revs_to_process = walk
        .map(|r| r.unwrap()) // walk produces Result<git2::Oid> so we unwrap to just the Oid
        .filter(|git_oid| !blame_map.contains_key(git_oid))
        .collect::<Vec<_>>();
    let rev_count = revs_to_process.len();

    info!("Transforming new commits...");

    let mut rev_done = 0;
    for git_oid in revs_to_process {
        rev_done += 1;

        let hg_rev = match hg_helper {
            Some(ref mut helper) => get_hg_rev(helper, &git_oid),
            None => None, // we don't support mapfiles any more.
        };

        info!(
            "Transforming {} (hg {:?}) progress {}/{}",
            git_oid, hg_rev, rev_done, rev_count
        );
        let commit = git_repo.find_commit(git_oid).unwrap();
        let blame_parents = commit
            .parent_ids()
            .map(|pid| blame_repo.find_commit(blame_map[&pid]).unwrap())
            .collect::<Vec<_>>();

        let mut file_movement = HashMap::new();
        if commit.parent_count() == 1 {
            let mut movement = HashMap::new();
            let mut diff = git_repo
                .diff_tree_to_tree(
                    Some(&commit.parent(0).unwrap().tree().unwrap()),
                    Some(&commit.tree().unwrap()),
                    None,
                )
                .unwrap();
            diff.find_similar(Some(
                DiffFindOptions::new().copies(true).rename_limit(1000000),
            ))
            .unwrap();
            for delta in diff.deltas() {
                if !delta.old_file().id().is_zero()
                    && !delta.new_file().id().is_zero()
                    && delta.old_file().path() != delta.new_file().path()
                {
                    movement.insert(
                        delta.new_file().id(),
                        delta.old_file().path().unwrap().to_path_buf(),
                    );
                }
            }
            file_movement.insert(commit.parent_id(0).unwrap(), movement);
        }

        let mut builder = blame_repo.treebuilder(None).unwrap();
        build_blame_tree(
            &mut builder,
            &file_movement,
            &git_repo,
            &commit,
            &blame_repo,
            &blame_parents,
            PathBuf::new(),
        )
        .unwrap();
        let tree_oid = builder.write().unwrap();

        let commit_msg = if let Some(hg_rev) = hg_rev {
            format!("git {}\nhg {}\n", git_oid, hg_rev)
        } else {
            format!("git {}\n", git_oid)
        };

        let commit_ref = if refobj.is_some() {
            None
        } else {
            // This should only happen on the first commit, if the blame_ref
            // doesn't exist yet in the destination repo
            Some(blame_ref.as_str())
        };
        let blame_oid = blame_repo
            .commit(
                commit_ref,
                &commit.author(),
                &commit.committer(),
                &commit_msg,
                &blame_repo.find_tree(tree_oid).unwrap(),
                &blame_parents.iter().collect::<Vec<_>>(),
            )
            .unwrap();

        if let Some(ref mut refobj) = refobj {
            *refobj = refobj.set_target(blame_oid, "").unwrap();
        } else {
            refobj = blame_repo
                .find_reference(&blame_ref)
                .ok()
                .and_then(|r| r.resolve().ok());
            assert!(refobj.is_some());
        }

        blame_map.insert(git_oid, blame_oid);
        info!("  -> {}", blame_oid);
    }

    if let Some(mut helper) = hg_helper {
        helper.kill().unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright © 2015, Peter Atashian
// Licensed under the MIT License <LICENSE.md>
pub fn link(name: &str, bundled: bool) {
    use std::env::var;
    let target = var("TARGET").unwrap();
    let target: Vec<_> = target.split('-').collect();
    if target.len() > 2 && target[2] == "windows" {
        println!("cargo:rustc-link-lib=dylib={}", name);
        if bundled && target[3] == "gnu" {
            let dir = var("CARGO_MANIFEST_DIR").unwrap();
            println!("cargo:rustc-link-search=native={}/{}", dir, target[0]);
        }
    }
}
<commit_msg>build: also be careful about indexing for "gnu"<commit_after>// Copyright © 2015, Peter Atashian
// Licensed under the MIT License <LICENSE.md>
pub fn link(name: &str, bundled: bool) {
    use std::env::var;
    let target = var("TARGET").unwrap();
    let target: Vec<_> = target.split('-').collect();
    if target.len() > 2 && target[2] == "windows" {
        println!("cargo:rustc-link-lib=dylib={}", name);
        if bundled && target.len() > 3 && target[3] == "gnu" {
            let dir = var("CARGO_MANIFEST_DIR").unwrap();
            println!("cargo:rustc-link-search=native={}/{}", dir, target[0]);
        }
    }
}
<|endoftext|>


<commit_before>use async_input::AsyncInput;
use base::*;
use time::*;
use filters::*;
use std;
use output;
use ui;

struct InputMixer {
    input: AsyncInput,
    current_frame: Frame,
    current_frame_pos: usize,
    volume: ui::Gain,
    gain: ui::Gain,
    multiplier: f32,
}

impl InputMixer {
    fn new(input: AsyncInput) -> InputMixer {
        let mut r = InputMixer {
            input: input,
            current_frame: Frame::new(1, Time::zero(), 0),
            current_frame_pos: 0,
            volume: ui::Gain { db: -20.0 },
            gain: ui::Gain { db: 0.0 },
            multiplier: 1.0,
        };
        r.update_multiplier();
        r
    }

    fn set_input_gain(&mut self, input_gain: ui::Gain) {
        self.gain = input_gain;
        self.update_multiplier();
    }

    fn set_master_volume(&mut self, volume: ui::Gain) {
        self.volume = volume;
        self.update_multiplier();
    }

    fn update_multiplier(&mut self) {
        self.multiplier = 10f32.powf((self.volume.db + self.gain.db) / 20.0);
    }

    fn mix_into(&mut self, mixed_frame: &mut Frame, deadline: Time) -> Result<bool> {
        let mut pos = 0;
        while pos < mixed_frame.len() {
            if self.current_frame_pos >= self.current_frame.len() {
                match try!(self.input.read(deadline - Time::now())) {
                    None => return Ok(pos > 0),
                    Some(frame) => {
                        // If the frame is too old then drop it.
                        if frame.timestamp < mixed_frame.timestamp {
                            continue;
                        }
                        self.current_frame = frame;
                        self.current_frame_pos = 0;
                    }
                }
            }

            mixed_frame.left[pos] +=
                self.multiplier * self.current_frame.left[self.current_frame_pos];
            mixed_frame.right[pos] +=
                self.multiplier * self.current_frame.right[self.current_frame_pos];
            self.current_frame_pos += 1;
            pos += 1;
        }

        Ok(true)
    }
}

pub struct FilteredOutput {
    output: Box<output::Output>,
    filter: ParallelFirFilter,
    enabled: bool,
    ui_msg_receiver: ui::UiMessageReceiver,
}

impl FilteredOutput {
    pub fn new(
        output: Box<output::Output>,
        filter: ParallelFirFilter,
        shared_state: &ui::SharedState,
    ) -> Box<output::Output> {
        Box::new(FilteredOutput {
            output: output,
            filter: filter,
            enabled: true,
            ui_msg_receiver: shared_state.lock().add_observer(),
        })
    }
}

impl output::Output for FilteredOutput {
    fn write(&mut self, mut frame: Frame) -> Result<()> {
        for msg in self.ui_msg_receiver.try_iter() {
            match msg {
                ui::UiMessage::SetEnableDrc { enable } => self.enabled = enable,
                _ => (),
            }
        }
        if self.enabled {
            self.filter.apply(&mut frame);
        }
        self.output.write(frame)
    }

    fn deactivate(&mut self) {
        self.output.deactivate();
    }

    fn sample_rate(&self) -> usize {
        self.output.sample_rate()
    }

    fn period_size(&self) -> usize {
        self.output.sample_rate()
    }

    fn measured_sample_rate(&self) -> f64 {
        self.output.measured_sample_rate()
    }
}

const OUTPUT_SHUTDOWN_SECONDS: i64 = 30;
const STANDBY_SECONDS: i64 = 3600;

pub fn run_mixer_loop(
    mut inputs: Vec<AsyncInput>,
    mut outputs: Vec<Box<output::Output>>,
    sample_rate: usize,
    period_duration: TimeDelta,
    resampler_window: usize,
    shared_state: ui::SharedState,
) -> Result<()> {
    let ui_channel = shared_state.lock().add_observer();

    let mut mixers: Vec<Box<InputMixer>> = inputs
        .drain(..)
        .map(|i| Box::new(InputMixer::new(i)))
        .collect();

    let mut last_data_time = Time::now();
    let mut state = ui::StreamState::Active;
    let mut selected_output = 0;

    let mut loudness_filter =
        StereoFilter::<LoudnessFilter>::new(SimpleFilterParams::new(sample_rate, 10.0));
    let mut voice_boost_filter: Option<StereoFilter<VoiceBoostFilter>> = None;
    let mut crossfeed_filter = CrossfeedFilter::new(sample_rate);

    let mut exclusive_mux_mode = true;

    let period_size = (period_duration * sample_rate as i64 / TimeDelta::seconds(1)) as usize;
    let resampler_delay = TimeDelta::seconds(1) * resampler_window as i64 / sample_rate as i64;
    let mix_delay = period_duration * 3 + resampler_delay;
    let target_output_delay = mix_delay + period_duration * 5 + resampler_delay;

    let mut stream_start_time = Time::now() - mix_delay;
    let mut stream_pos: i64 = 0;

    loop {
        let frame_timestamp = get_sample_timestamp(stream_start_time, sample_rate, stream_pos);
        let mut frame = Frame::new(sample_rate, frame_timestamp, period_size);
        stream_pos += frame.len() as i64;

        let mut have_data = false;
        let mut mix_deadline = frame.end_timestamp() + mix_delay;

        let now = Time::now();
        if now > mix_deadline + period_duration {
            println!(
                "ERROR: Mixer missed deadline. Resetting stream. {:?}",
                now - mix_deadline
            );
            frame.timestamp = frame.end_timestamp();
            stream_pos += frame.len() as i64;
            mix_deadline = frame.end_timestamp() + mix_delay;
        }

        for m in mixers.iter_mut() {
            have_data |= try!(m.mix_into(&mut frame, mix_deadline));
            if have_data && exclusive_mux_mode {
                break;
            }
        }

        let new_state = match (have_data, (Time::now() - last_data_time).in_seconds()) {
            (true, _) => {
                last_data_time = now;
                ui::StreamState::Active
            }
            (false, t) if t < OUTPUT_SHUTDOWN_SECONDS => ui::StreamState::Active,
            (false, t) if t < STANDBY_SECONDS => ui::StreamState::Inactive,
            (false, _) => ui::StreamState::Standby,
        };

        if state != new_state {
            state = new_state;
            println!("INFO: state: {}", state.as_str());
            shared_state.lock().on_stream_state(state);
            if state != ui::StreamState::Active {
                for ref mut out in &mut outputs {
                    out.deactivate();
                }
            }
        }

        if state == ui::StreamState::Active {
            loudness_filter.apply(&mut frame);
            match voice_boost_filter.as_mut() {
                Some(ref mut f) => {
                    f.apply(&mut frame);
                }
                None => (),
            }
            frame = crossfeed_filter.apply(frame);

            frame.timestamp += target_output_delay;
            //  println!("out: {:?}", frame.timestamp -  Time::now());
            try!(outputs[selected_output].write(frame));
        } else {
            std::thread::sleep(TimeDelta::milliseconds(500).as_duration());
            stream_start_time = Time::now() - mix_delay;
            stream_pos = 0;
        }

        for msg in ui_channel.try_iter() {
            match msg {
                ui::UiMessage::SelectOutput { output } => {
                    outputs[output].deactivate();
                    selected_output = output;
                }
                ui::UiMessage::SetMasterVolume { volume, loudness } => {
                    for i in mixers.iter_mut() {
                        i.set_master_volume(volume)
                    }
                    loudness_filter.set_params(SimpleFilterParams::new(sample_rate, loudness.db));
                }
                ui::UiMessage::SetInputGain { device, gain } => {
                    mixers[device as usize].set_input_gain(gain);
                }
                ui::UiMessage::SetEnableDrc { enable: _ } => (),
                ui::UiMessage::SetVoiceBoost { boost } => if boost.db > 0.0 {
                    let p = SimpleFilterParams::new(sample_rate, boost.db);
                    if voice_boost_filter.is_some() {
                        voice_boost_filter.as_mut().unwrap().set_params(p);
                    } else {
                        voice_boost_filter = Some(StereoFilter::<VoiceBoostFilter>::new(
                            SimpleFilterParams::new(sample_rate, boost.db),
                        ))
                    }
                } else {
                    voice_boost_filter = None
                },
                ui::UiMessage::SetCrossfeed { level, delay_ms } => {
                    crossfeed_filter.set_params(level, delay_ms);
                }
                ui::UiMessage::SetMuxMode {
                    mux_mode: ui::MuxMode::Exclusive,
                } => {
                    exclusive_mux_mode = true;
                }
                ui::UiMessage::SetMuxMode {
                    mux_mode: ui::MuxMode::Mixer,
                } => {
                    exclusive_mux_mode = false;
                }
            }
        }
    }
}
<commit_msg>lower latency<commit_after>use async_input::AsyncInput;
use base::*;
use time::*;
use filters::*;
use std;
use output;
use ui;

struct InputMixer {
    input: AsyncInput,
    current_frame: Frame,
    current_frame_pos: usize,
    volume: ui::Gain,
    gain: ui::Gain,
    multiplier: f32,
}

impl InputMixer {
    fn new(input: AsyncInput) -> InputMixer {
        let mut r = InputMixer {
            input: input,
            current_frame: Frame::new(1, Time::zero(), 0),
            current_frame_pos: 0,
            volume: ui::Gain { db: -20.0 },
            gain: ui::Gain { db: 0.0 },
            multiplier: 1.0,
        };
        r.update_multiplier();
        r
    }

    fn set_input_gain(&mut self, input_gain: ui::Gain) {
        self.gain = input_gain;
        self.update_multiplier();
    }

    fn set_master_volume(&mut self, volume: ui::Gain) {
        self.volume = volume;
        self.update_multiplier();
    }

    fn update_multiplier(&mut self) {
        self.multiplier = 10f32.powf((self.volume.db + self.gain.db) / 20.0);
    }

    fn mix_into(&mut self, mixed_frame: &mut Frame, deadline: Time) -> Result<bool> {
        let mut pos = 0;
        while pos < mixed_frame.len() {
            if self.current_frame_pos >= self.current_frame.len() {
                match try!(self.input.read(deadline - Time::now())) {
                    None => return Ok(pos > 0),
                    Some(frame) => {
                        // If the frame is too old then drop it.
                        if frame.timestamp < mixed_frame.timestamp {
                            continue;
                        }
                        self.current_frame = frame;
                        self.current_frame_pos = 0;
                    }
                }
            }

            mixed_frame.left[pos] +=
                self.multiplier * self.current_frame.left[self.current_frame_pos];
            mixed_frame.right[pos] +=
                self.multiplier * self.current_frame.right[self.current_frame_pos];
            self.current_frame_pos += 1;
            pos += 1;
        }

        Ok(true)
    }
}

pub struct FilteredOutput {
    output: Box<output::Output>,
    filter: ParallelFirFilter,
    enabled: bool,
    ui_msg_receiver: ui::UiMessageReceiver,
}

impl FilteredOutput {
    pub fn new(
        output: Box<output::Output>,
        filter: ParallelFirFilter,
        shared_state: &ui::SharedState,
    ) -> Box<output::Output> {
        Box::new(FilteredOutput {
            output: output,
            filter: filter,
            enabled: true,
            ui_msg_receiver: shared_state.lock().add_observer(),
        })
    }
}

impl output::Output for FilteredOutput {
    fn write(&mut self, mut frame: Frame) -> Result<()> {
        for msg in self.ui_msg_receiver.try_iter() {
            match msg {
                ui::UiMessage::SetEnableDrc { enable } => self.enabled = enable,
                _ => (),
            }
        }
        if self.enabled {
            self.filter.apply(&mut frame);
        }
        self.output.write(frame)
    }

    fn deactivate(&mut self) {
        self.output.deactivate();
    }

    fn sample_rate(&self) -> usize {
        self.output.sample_rate()
    }

    fn period_size(&self) -> usize {
        self.output.sample_rate()
    }

    fn measured_sample_rate(&self) -> f64 {
        self.output.measured_sample_rate()
    }
}

const OUTPUT_SHUTDOWN_SECONDS: i64 = 30;
const STANDBY_SECONDS: i64 = 3600;

pub fn run_mixer_loop(
    mut inputs: Vec<AsyncInput>,
    mut outputs: Vec<Box<output::Output>>,
    sample_rate: usize,
    period_duration: TimeDelta,
    resampler_window: usize,
    shared_state: ui::SharedState,
) -> Result<()> {
    let ui_channel = shared_state.lock().add_observer();

    let mut mixers: Vec<Box<InputMixer>> = inputs
        .drain(..)
        .map(|i| Box::new(InputMixer::new(i)))
        .collect();

    let mut last_data_time = Time::now();
    let mut state = ui::StreamState::Active;
    let mut selected_output = 0;

    let mut loudness_filter =
        StereoFilter::<LoudnessFilter>::new(SimpleFilterParams::new(sample_rate, 10.0));
    let mut voice_boost_filter: Option<StereoFilter<VoiceBoostFilter>> = None;
    let mut crossfeed_filter = CrossfeedFilter::new(sample_rate);

    let mut exclusive_mux_mode = true;

    let period_size = (period_duration * sample_rate as i64 / TimeDelta::seconds(1)) as usize;
    let resampler_delay = TimeDelta::seconds(1) * resampler_window as i64 / sample_rate as i64;
    let mix_delay = period_duration * 2 + resampler_delay;
    let target_output_delay = mix_delay + period_duration * 2 + resampler_delay;

    let mut stream_start_time = Time::now() - mix_delay;
    let mut stream_pos: i64 = 0;

    loop {
        let frame_timestamp = get_sample_timestamp(stream_start_time, sample_rate, stream_pos);
        let mut frame = Frame::new(sample_rate, frame_timestamp, period_size);
        stream_pos += frame.len() as i64;

        let mut have_data = false;
        let mut mix_deadline = frame.end_timestamp() + mix_delay;

        let now = Time::now();
        if now > mix_deadline + period_duration {
            println!(
                "ERROR: Mixer missed deadline. Resetting stream. {:?}",
                now - mix_deadline
            );
            frame.timestamp = frame.end_timestamp();
            stream_pos += frame.len() as i64;
            mix_deadline = frame.end_timestamp() + mix_delay;
        }

        for m in mixers.iter_mut() {
            have_data |= try!(m.mix_into(&mut frame, mix_deadline));
            if have_data && exclusive_mux_mode {
                break;
            }
        }

        let new_state = match (have_data, (Time::now() - last_data_time).in_seconds()) {
            (true, _) => {
                last_data_time = now;
                ui::StreamState::Active
            }
            (false, t) if t < OUTPUT_SHUTDOWN_SECONDS => ui::StreamState::Active,
            (false, t) if t < STANDBY_SECONDS => ui::StreamState::Inactive,
            (false, _) => ui::StreamState::Standby,
        };

        if state != new_state {
            state = new_state;
            println!("INFO: state: {}", state.as_str());
            shared_state.lock().on_stream_state(state);
            if state != ui::StreamState::Active {
                for ref mut out in &mut outputs {
                    out.deactivate();
                }
            }
        }

        if state == ui::StreamState::Active {
            loudness_filter.apply(&mut frame);
            match voice_boost_filter.as_mut() {
                Some(ref mut f) => {
                    f.apply(&mut frame);
                }
                None => (),
            }
            frame = crossfeed_filter.apply(frame);

            frame.timestamp += target_output_delay;
            //  println!("out: {:?}", frame.timestamp -  Time::now());
            try!(outputs[selected_output].write(frame));
        } else {
            std::thread::sleep(TimeDelta::milliseconds(500).as_duration());
            stream_start_time = Time::now() - mix_delay;
            stream_pos = 0;
        }

        for msg in ui_channel.try_iter() {
            match msg {
                ui::UiMessage::SelectOutput { output } => {
                    outputs[output].deactivate();
                    selected_output = output;
                }
                ui::UiMessage::SetMasterVolume { volume, loudness } => {
                    for i in mixers.iter_mut() {
                        i.set_master_volume(volume)
                    }
                    loudness_filter.set_params(SimpleFilterParams::new(sample_rate, loudness.db));
                }
                ui::UiMessage::SetInputGain { device, gain } => {
                    mixers[device as usize].set_input_gain(gain);
                }
                ui::UiMessage::SetEnableDrc { enable: _ } => (),
                ui::UiMessage::SetVoiceBoost { boost } => if boost.db > 0.0 {
                    let p = SimpleFilterParams::new(sample_rate, boost.db);
                    if voice_boost_filter.is_some() {
                        voice_boost_filter.as_mut().unwrap().set_params(p);
                    } else {
                        voice_boost_filter = Some(StereoFilter::<VoiceBoostFilter>::new(
                            SimpleFilterParams::new(sample_rate, boost.db),
                        ))
                    }
                } else {
                    voice_boost_filter = None
                },
                ui::UiMessage::SetCrossfeed { level, delay_ms } => {
                    crossfeed_filter.set_params(level, delay_ms);
                }
                ui::UiMessage::SetMuxMode {
                    mux_mode: ui::MuxMode::Exclusive,
                } => {
                    exclusive_mux_mode = true;
                }
                ui::UiMessage::SetMuxMode {
                    mux_mode: ui::MuxMode::Mixer,
                } => {
                    exclusive_mux_mode = false;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate itertools;

use std::collections::HashMap;

use self::itertools::Itertools;
use self::rustc_serialize::json;

use ngrams::ngrams;

pub struct Model {
    pub ngram_ranks: HashMap<String, usize>,
}

impl Model {
    pub fn build_from_text(text: &str) -> Model {
        let mut ngram_counts = HashMap::new();
        for n in 1..6 {
            for ngram in ngrams(text, n) {
                // If you don't want to unecessarily allocate strings, this is
                // the only way to do it. This RFC should fix this if it ever
                // gets accepted: // https://github.com/rust-lang/rfcs/pull/1533
                if let Some(count) = ngram_counts.get_mut(ngram) {
                    *count += 1;
                    continue;
                }
                ngram_counts.insert(ngram.to_owned(), 1);
            }
        }

        let ngrams = ngram_counts
            .into_iter()
            .sorted_by(|a, b| Ord::cmp(&b.1, &a.1))
            .into_iter()
            .take(300)
            .map(|(ngram, _count)| ngram);

        // Nicer way to build a hash map.
        Model { ngram_ranks: ngrams.enumerate().map(|(a, b)| (b, a)).collect() }
    }

    pub fn deserialize(bytes: Vec<u8>) -> Model {
        let string = String::from_utf8(bytes).unwrap();
        let ngram_ranks = json::decode(string.as_str()).unwrap();
        Model { ngram_ranks: ngram_ranks }
    }

    pub fn serialize(&self) -> Vec<u8> {
        json::encode(&self.ngram_ranks).unwrap().into_bytes()
    }

    pub fn compare(&self, other: &Model) -> usize {
        let max_difference = other.ngram_ranks.len();
        let mut difference = 0;
        for (ngram, rank) in self.ngram_ranks.iter() {
            difference += match other.ngram_ranks.get(ngram) {
                Some(other_rank) => get_difference(*rank, *other_rank),
                None => max_difference,
            }
        }
        difference
    }
}

fn get_difference(a: usize, b: usize) -> usize {
    if a > b { a - b } else { b - a }
}
<commit_msg>Use a more idiomatic way to iterate over ngram_ranks<commit_after>extern crate rustc_serialize;
extern crate itertools;

use std::collections::HashMap;

use self::itertools::Itertools;
use self::rustc_serialize::json;

use ngrams::ngrams;

pub struct Model {
    pub ngram_ranks: HashMap<String, usize>,
}

impl Model {
    pub fn build_from_text(text: &str) -> Model {
        let mut ngram_counts = HashMap::new();
        for n in 1..6 {
            for ngram in ngrams(text, n) {
                // If you don't want to unecessarily allocate strings, this is
                // the only way to do it. This RFC should fix this if it ever
                // gets accepted: // https://github.com/rust-lang/rfcs/pull/1533
                if let Some(count) = ngram_counts.get_mut(ngram) {
                    *count += 1;
                    continue;
                }
                ngram_counts.insert(ngram.to_owned(), 1);
            }
        }

        let ngrams = ngram_counts
            .into_iter()
            .sorted_by(|a, b| Ord::cmp(&b.1, &a.1))
            .into_iter()
            .take(300)
            .map(|(ngram, _count)| ngram);

        // Nicer way to build a hash map.
        Model { ngram_ranks: ngrams.enumerate().map(|(a, b)| (b, a)).collect() }
    }

    pub fn deserialize(bytes: Vec<u8>) -> Model {
        let string = String::from_utf8(bytes).unwrap();
        let ngram_ranks = json::decode(string.as_str()).unwrap();
        Model { ngram_ranks: ngram_ranks }
    }

    pub fn serialize(&self) -> Vec<u8> {
        json::encode(&self.ngram_ranks).unwrap().into_bytes()
    }

    pub fn compare(&self, other: &Model) -> usize {
        let max_difference = other.ngram_ranks.len();
        let mut difference = 0;
        for (ngram, rank) in &self.ngram_ranks {
            difference += match other.ngram_ranks.get(ngram) {
                Some(other_rank) => get_difference(*rank, *other_rank),
                None => max_difference,
            }
        }
        difference
    }
}

fn get_difference(a: usize, b: usize) -> usize {
    if a > b { a - b } else { b - a }
}
<|endoftext|>


<commit_before>//! Functions for adding synthetic noise to images.

use image::{
    GenericImage,
    ImageBuffer,
    Pixel
};

use rand::{
    SeedableRng,
    StdRng
};

use rand::distributions::{
    IndependentSample,
    Normal,
    Range
};

use definitions::{
    Clamp,
    HasBlack,
    HasWhite,
    Image
};

use conv::{
    ValueInto
};

use math::{
    cast
};

/// Adds independent additive Gaussian noise to all channels
/// of an image, with the given mean and standard deviation.
pub fn gaussian_noise<I>(image: &I, mean: f64, stddev: f64, seed: usize)
        -> Image<I::Pixel>
    where I: GenericImage,
          I::Pixel: 'static,
          <I::Pixel as Pixel>::Subpixel: ValueInto<f64> + Clamp<f64> {

    let mut out = ImageBuffer::new(image.width(), image.height());
    out.copy_from(image, 0, 0);
    gaussian_noise_mut(&mut out, mean, stddev, seed);
    out
}

/// Adds independent additive Gaussian noise to all channels
/// of an image in place, with the given mean and standard deviation.
pub fn gaussian_noise_mut<I>(image: &mut I, mean: f64, stddev: f64, seed: usize)
    where I: GenericImage,
          <I::Pixel as Pixel>::Subpixel: ValueInto<f64> + Clamp<f64> {

    let seed_array: &[_] = &[seed];
    let mut rng: StdRng = SeedableRng::from_seed(seed_array);

    let normal = Normal::new(mean, stddev);

    for y in 0..image.height() {
        for x in 0..image.width() {
            let mut pix = unsafe { image.unsafe_get_pixel(x, y) };
            let num_channels = I::Pixel::channel_count() as usize;

            for c in 0..num_channels {
                let noise = normal.ind_sample(&mut rng);
                let channel: f64 = cast(pix.channels()[c]);
                pix.channels_mut()[c]
                    = <I::Pixel as Pixel>::Subpixel::clamp(channel + noise);
            }

            unsafe { image.unsafe_put_pixel(x, y, pix) };
        }
    }
}

/// Converts pixels to black or white at the given `rate` (between 0.0 and 1.0).
/// Black and white occur with equal probability.
pub fn salt_and_pepper_noise<I>(image: &I, rate: f64, seed: usize)
        -> Image<I::Pixel>
    where I: GenericImage, I::Pixel: HasBlack + HasWhite + 'static {

    let mut out = ImageBuffer::new(image.width(), image.height());
    out.copy_from(image, 0, 0);
    salt_and_pepper_noise_mut(&mut out, rate, seed);
    out
}

/// Converts pixels to black or white in place at the given `rate` (between 0.0 and 1.0).
/// Black and white occur with equal probability.
pub fn salt_and_pepper_noise_mut<I>(image: &mut I, rate: f64, seed: usize)
    where I: GenericImage, I::Pixel: HasBlack + HasWhite {

    let seed_array: &[_] = &[seed];
    let mut rng: StdRng = SeedableRng::from_seed(seed_array);

    let uniform = Range::new(0.0, 1.0);

    for y in 0..image.height() {
        for x in 0..image.width() {

            if uniform.ind_sample(&mut rng) > rate {
                continue;
            }

            unsafe {
                if uniform.ind_sample(&mut rng) >= 0.5 {
                    image.unsafe_put_pixel(x, y, I::Pixel::white());
                }
                else {
                    image.unsafe_put_pixel(x, y, I::Pixel::black());
                }
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use image::{GrayImage};
    use test::{Bencher, black_box};

    #[bench]
    fn bench_gaussian_noise_mut(b: &mut Bencher) {
        let mut image = GrayImage::new(100, 100);
        b.iter(||{
            gaussian_noise_mut(&mut image, 30.0, 40.0, 1usize);
        });
        black_box(image);
    }

    #[bench]
    fn bench_salt_and_pepper_noise_mut(b: &mut Bencher) {
        let mut image = GrayImage::new(100, 100);
        b.iter(||{
            salt_and_pepper_noise_mut(&mut image, 0.3, 1usize);
        });
        black_box(image);
    }
}
<commit_msg>Run rustfmt on noise.rs<commit_after>//! Functions for adding synthetic noise to images.

use image::{GenericImage, ImageBuffer, Pixel};
use rand::{SeedableRng, StdRng};
use rand::distributions::{IndependentSample, Normal, Range};
use definitions::{Clamp, HasBlack, HasWhite, Image};
use conv::ValueInto;
use math::cast;

/// Adds independent additive Gaussian noise to all channels
/// of an image, with the given mean and standard deviation.
pub fn gaussian_noise<I>(image: &I, mean: f64, stddev: f64, seed: usize) -> Image<I::Pixel>
where
    I: GenericImage,
    I::Pixel: 'static,
    <I::Pixel as Pixel>::Subpixel: ValueInto<f64> + Clamp<f64>,
{

    let mut out = ImageBuffer::new(image.width(), image.height());
    out.copy_from(image, 0, 0);
    gaussian_noise_mut(&mut out, mean, stddev, seed);
    out
}

/// Adds independent additive Gaussian noise to all channels
/// of an image in place, with the given mean and standard deviation.
pub fn gaussian_noise_mut<I>(image: &mut I, mean: f64, stddev: f64, seed: usize)
where
    I: GenericImage,
    <I::Pixel as Pixel>::Subpixel: ValueInto<f64> + Clamp<f64>,
{

    let seed_array: &[_] = &[seed];
    let mut rng: StdRng = SeedableRng::from_seed(seed_array);

    let normal = Normal::new(mean, stddev);

    for y in 0..image.height() {
        for x in 0..image.width() {
            let mut pix = unsafe { image.unsafe_get_pixel(x, y) };
            let num_channels = I::Pixel::channel_count() as usize;

            for c in 0..num_channels {
                let noise = normal.ind_sample(&mut rng);
                let channel: f64 = cast(pix.channels()[c]);
                pix.channels_mut()[c] = <I::Pixel as Pixel>::Subpixel::clamp(channel + noise);
            }

            unsafe { image.unsafe_put_pixel(x, y, pix) };
        }
    }
}

/// Converts pixels to black or white at the given `rate` (between 0.0 and 1.0).
/// Black and white occur with equal probability.
pub fn salt_and_pepper_noise<I>(image: &I, rate: f64, seed: usize) -> Image<I::Pixel>
where
    I: GenericImage,
    I::Pixel: HasBlack + HasWhite + 'static,
{

    let mut out = ImageBuffer::new(image.width(), image.height());
    out.copy_from(image, 0, 0);
    salt_and_pepper_noise_mut(&mut out, rate, seed);
    out
}

/// Converts pixels to black or white in place at the given `rate` (between 0.0 and 1.0).
/// Black and white occur with equal probability.
pub fn salt_and_pepper_noise_mut<I>(image: &mut I, rate: f64, seed: usize)
where
    I: GenericImage,
    I::Pixel: HasBlack + HasWhite,
{

    let seed_array: &[_] = &[seed];
    let mut rng: StdRng = SeedableRng::from_seed(seed_array);

    let uniform = Range::new(0.0, 1.0);

    for y in 0..image.height() {
        for x in 0..image.width() {

            if uniform.ind_sample(&mut rng) > rate {
                continue;
            }

            unsafe {
                if uniform.ind_sample(&mut rng) >= 0.5 {
                    image.unsafe_put_pixel(x, y, I::Pixel::white());
                } else {
                    image.unsafe_put_pixel(x, y, I::Pixel::black());
                }
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use image::GrayImage;
    use test::{Bencher, black_box};

    #[bench]
    fn bench_gaussian_noise_mut(b: &mut Bencher) {
        let mut image = GrayImage::new(100, 100);
        b.iter(|| { gaussian_noise_mut(&mut image, 30.0, 40.0, 1usize); });
        black_box(image);
    }

    #[bench]
    fn bench_salt_and_pepper_noise_mut(b: &mut Bencher) {
        let mut image = GrayImage::new(100, 100);
        b.iter(|| { salt_and_pepper_noise_mut(&mut image, 0.3, 1usize); });
        black_box(image);
    }
}
<|endoftext|>


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

use syntax::ast;

use config::lists::*;
use config::IndentStyle;
use rewrite::{Rewrite, RewriteContext};
use shape::Shape;
use utils::{first_line_width, is_single_line, last_line_width, trimmed_last_line_width, wrap_str};

/// Sigils that decorate a binop pair.
#[derive(new, Clone, Copy)]
pub(crate) struct PairParts<'a> {
    prefix: &'a str,
    infix: &'a str,
    suffix: &'a str,
}

impl<'a> PairParts<'a> {
    pub(crate) fn infix(infix: &'a str) -> PairParts<'a> {
        PairParts {
            prefix: "",
            infix,
            suffix: "",
        }
    }
}

// Flattens a tree of pairs into a list and tries to rewrite them all at once.
// FIXME would be nice to reuse the lists API for this, but because each separator
// can be different, we can't.
pub(crate) fn rewrite_all_pairs(
    expr: &ast::Expr,
    shape: Shape,
    context: &RewriteContext,
) -> Option<String> {
    // First we try formatting on one line.
    if let Some(list) = expr.flatten(context, false) {
        if let Some(r) = rewrite_pairs_one_line(&list, shape, context) {
            return Some(r);
        }
    }

    // We can't format on line, so try many. When we flatten here we make sure
    // to only flatten pairs with the same operator, that way we don't
    // necessarily need one line per sub-expression, but we don't do anything
    // too funny wrt precedence.
    expr.flatten(context, true)
        .and_then(|list| rewrite_pairs_multiline(list, shape, context))
}

// This may return a multi-line result since we allow the last expression to go
// multiline in a 'single line' formatting.
fn rewrite_pairs_one_line<T: Rewrite>(
    list: &PairList<T>,
    shape: Shape,
    context: &RewriteContext,
) -> Option<String> {
    assert!(list.list.len() >= 2, "Not a pair?");

    let mut result = String::new();
    let base_shape = shape.block();

    for (e, s) in list.list.iter().zip(list.separators.iter()) {
        let cur_shape = base_shape.offset_left(last_line_width(&result))?;
        let rewrite = e.rewrite(context, cur_shape)?;

        if !is_single_line(&rewrite) || result.len() > shape.width {
            return None;
        }

        result.push_str(&rewrite);
        result.push(' ');
        result.push_str(s);
        result.push(' ');
    }

    let last = list.list.last().unwrap();
    let cur_shape = base_shape.offset_left(last_line_width(&result))?;
    let rewrite = last.rewrite(context, cur_shape)?;
    result.push_str(&rewrite);

    if first_line_width(&result) > shape.width {
        return None;
    }

    // Check the last expression in the list. We let this expression go over
    // multiple lines, but we check that if this is necessary, then we can't
    // do better using multi-line formatting.
    if !is_single_line(&result) {
        let multiline_shape = shape.offset_left(list.separators.last().unwrap().len() + 1)?;
        let multiline_list: PairList<T> = PairList {
            list: vec![last],
            separators: vec![],
            separator_place: list.separator_place,
        };
        // Format as if we were multi-line.
        if let Some(rewrite) = rewrite_pairs_multiline(multiline_list, multiline_shape, context) {
            // Also, don't let expressions surrounded by parens go multi-line,
            // this looks really bad.
            if rewrite.starts_with('(') || is_single_line(&rewrite) {
                return None;
            }
        }
    }

    wrap_str(result, context.config.max_width(), shape)
}

fn rewrite_pairs_multiline<T: Rewrite>(
    list: PairList<T>,
    shape: Shape,
    context: &RewriteContext,
) -> Option<String> {
    let rhs_offset = shape.rhs_overhead(&context.config);
    let nested_shape = (match context.config.indent_style() {
        IndentStyle::Visual => shape.visual_indent(0),
        IndentStyle::Block => shape.block_indent(context.config.tab_spaces()),
    })
    .with_max_width(&context.config)
    .sub_width(rhs_offset)?;

    let indent_str = nested_shape.indent.to_string_with_newline(context.config);
    let mut result = String::new();

    let rewrite = list.list[0].rewrite(context, shape)?;
    result.push_str(&rewrite);

    for (e, s) in list.list[1..].iter().zip(list.separators.iter()) {
        // The following test checks if we should keep two subexprs on the same
        // line. We do this if not doing so would create an orphan and there is
        // enough space to do so.
        let offset = if result.contains('\n') {
            0
        } else {
            shape.used_width()
        };
        if last_line_width(&result) + offset <= nested_shape.used_width() {
            // We must snuggle the next line onto the previous line to avoid an orphan.
            if let Some(line_shape) =
                shape.offset_left(s.len() + 2 + trimmed_last_line_width(&result))
            {
                if let Some(rewrite) = e.rewrite(context, line_shape) {
                    result.push(' ');
                    result.push_str(s);
                    result.push(' ');
                    result.push_str(&rewrite);
                    continue;
                }
            }
        }

        let nested_overhead = s.len() + 1;
        let line_shape = match context.config.binop_separator() {
            SeparatorPlace::Back => {
                result.push(' ');
                result.push_str(s);
                result.push_str(&indent_str);
                nested_shape.sub_width(nested_overhead)?
            }
            SeparatorPlace::Front => {
                result.push_str(&indent_str);
                result.push_str(s);
                result.push(' ');
                nested_shape.offset_left(nested_overhead)?
            }
        };

        let rewrite = e.rewrite(context, line_shape)?;
        result.push_str(&rewrite);
    }
    Some(result)
}

// Rewrites a single pair.
pub(crate) fn rewrite_pair<LHS, RHS>(
    lhs: &LHS,
    rhs: &RHS,
    pp: PairParts,
    context: &RewriteContext,
    shape: Shape,
    separator_place: SeparatorPlace,
) -> Option<String>
where
    LHS: Rewrite,
    RHS: Rewrite,
{
    let tab_spaces = context.config.tab_spaces();
    let lhs_overhead = match separator_place {
        SeparatorPlace::Back => shape.used_width() + pp.prefix.len() + pp.infix.trim_right().len(),
        SeparatorPlace::Front => shape.used_width(),
    };
    let lhs_shape = Shape {
        width: context.budget(lhs_overhead),
        ..shape
    };
    let lhs_result = lhs
        .rewrite(context, lhs_shape)
        .map(|lhs_str| format!("{}{}", pp.prefix, lhs_str))?;

    // Try to put both lhs and rhs on the same line.
    let rhs_orig_result = shape
        .offset_left(last_line_width(&lhs_result) + pp.infix.len())
        .and_then(|s| s.sub_width(pp.suffix.len()))
        .and_then(|rhs_shape| rhs.rewrite(context, rhs_shape));
    if let Some(ref rhs_result) = rhs_orig_result {
        // If the length of the lhs is equal to or shorter than the tab width or
        // the rhs looks like block expression, we put the rhs on the same
        // line with the lhs even if the rhs is multi-lined.
        let allow_same_line = lhs_result.len() <= tab_spaces || rhs_result
            .lines()
            .next()
            .map(|first_line| first_line.ends_with('{'))
            .unwrap_or(false);
        if !rhs_result.contains('\n') || allow_same_line {
            let one_line_width = last_line_width(&lhs_result)
                + pp.infix.len()
                + first_line_width(rhs_result)
                + pp.suffix.len();
            if one_line_width <= shape.width {
                return Some(format!(
                    "{}{}{}{}",
                    lhs_result, pp.infix, rhs_result, pp.suffix
                ));
            }
        }
    }

    // We have to use multiple lines.
    // Re-evaluate the rhs because we have more space now:
    let mut rhs_shape = match context.config.indent_style() {
        IndentStyle::Visual => shape
            .sub_width(pp.suffix.len() + pp.prefix.len())?
            .visual_indent(pp.prefix.len()),
        IndentStyle::Block => {
            // Try to calculate the initial constraint on the right hand side.
            let rhs_overhead = shape.rhs_overhead(context.config);
            Shape::indented(shape.indent.block_indent(context.config), context.config)
                .sub_width(rhs_overhead)?
        }
    };
    let infix = match separator_place {
        SeparatorPlace::Back => pp.infix.trim_right(),
        SeparatorPlace::Front => pp.infix.trim_left(),
    };
    if separator_place == SeparatorPlace::Front {
        rhs_shape = rhs_shape.offset_left(infix.len())?;
    }
    let rhs_result = rhs.rewrite(context, rhs_shape)?;
    let indent_str = rhs_shape.indent.to_string_with_newline(context.config);
    let infix_with_sep = match separator_place {
        SeparatorPlace::Back => format!("{}{}", infix, indent_str),
        SeparatorPlace::Front => format!("{}{}", indent_str, infix),
    };
    Some(format!(
        "{}{}{}{}",
        lhs_result, infix_with_sep, rhs_result, pp.suffix
    ))
}

// A pair which forms a tree and can be flattened (e.g., binops).
trait FlattenPair: Rewrite + Sized {
    // If `_same_op` is `true`, then we only combine binops with the same
    // operator into the list. E.g,, if the source is `a * b + c`, if `_same_op`
    // is true, we make `[(a * b), c]` if `_same_op` is false, we make
    // `[a, b, c]`
    fn flatten(&self, _context: &RewriteContext, _same_op: bool) -> Option<PairList<Self>> {
        None
    }
}

struct PairList<'a, 'b, T: Rewrite + 'b> {
    list: Vec<&'b T>,
    separators: Vec<&'a str>,
    separator_place: SeparatorPlace,
}

impl FlattenPair for ast::Expr {
    fn flatten(&self, context: &RewriteContext, same_op: bool) -> Option<PairList<ast::Expr>> {
        let top_op = match self.node {
            ast::ExprKind::Binary(op, _, _) => op.node,
            _ => return None,
        };

        // Turn a tree of binop expressions into a list using a depth-first,
        // in-order traversal.
        let mut stack = vec![];
        let mut list = vec![];
        let mut separators = vec![];
        let mut node = self;
        loop {
            match node.node {
                ast::ExprKind::Binary(op, ref lhs, _) if !same_op || op.node == top_op => {
                    stack.push(node);
                    node = lhs;
                }
                _ => {
                    list.push(node);
                    if let Some(pop) = stack.pop() {
                        match pop.node {
                            ast::ExprKind::Binary(op, _, ref rhs) => {
                                separators.push(op.node.to_string());
                                node = rhs;
                            }
                            _ => unreachable!(),
                        }
                    } else {
                        break;
                    }
                }
            }
        }

        assert_eq!(list.len() - 1, separators.len());
        Some(PairList {
            list,
            separators,
            separator_place: context.config.binop_separator(),
        })
    }
}

impl FlattenPair for ast::Ty {}
impl FlattenPair for ast::Pat {}
<commit_msg>Simplify situations in which the last sub-expr in a bin-op can go multiline without making the whole expr multiline<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax::ast;

use config::lists::*;
use config::IndentStyle;
use rewrite::{Rewrite, RewriteContext};
use shape::Shape;
use utils::{first_line_width, is_single_line, last_line_width, trimmed_last_line_width, wrap_str};

/// Sigils that decorate a binop pair.
#[derive(new, Clone, Copy)]
pub(crate) struct PairParts<'a> {
    prefix: &'a str,
    infix: &'a str,
    suffix: &'a str,
}

impl<'a> PairParts<'a> {
    pub(crate) fn infix(infix: &'a str) -> PairParts<'a> {
        PairParts {
            prefix: "",
            infix,
            suffix: "",
        }
    }
}

// Flattens a tree of pairs into a list and tries to rewrite them all at once.
// FIXME would be nice to reuse the lists API for this, but because each separator
// can be different, we can't.
pub(crate) fn rewrite_all_pairs(
    expr: &ast::Expr,
    shape: Shape,
    context: &RewriteContext,
) -> Option<String> {
    // First we try formatting on one line.
    if let Some(list) = expr.flatten(false) {
        if let Some(r) = rewrite_pairs_one_line(&list, shape, context) {
            return Some(r);
        }
    }

    // We can't format on line, so try many. When we flatten here we make sure
    // to only flatten pairs with the same operator, that way we don't
    // necessarily need one line per sub-expression, but we don't do anything
    // too funny wrt precedence.
    expr.flatten(true)
        .and_then(|list| rewrite_pairs_multiline(list, shape, context))
}

// This may return a multi-line result since we allow the last expression to go
// multiline in a 'single line' formatting.
fn rewrite_pairs_one_line<T: Rewrite>(
    list: &PairList<T>,
    shape: Shape,
    context: &RewriteContext,
) -> Option<String> {
    assert!(list.list.len() >= 2, "Not a pair?");

    let mut result = String::new();
    let base_shape = shape.block();

    for (e, s) in list.list.iter().zip(list.separators.iter()) {
        let cur_shape = base_shape.offset_left(last_line_width(&result))?;
        let rewrite = e.rewrite(context, cur_shape)?;

        if !is_single_line(&rewrite) || result.len() > shape.width {
            return None;
        }

        result.push_str(&rewrite);
        result.push(' ');
        result.push_str(s);
        result.push(' ');
    }

    let prefix_len = result.len();
    let last = list.list.last().unwrap();
    let cur_shape = base_shape.offset_left(last_line_width(&result))?;
    let last_rewrite = last.rewrite(context, cur_shape)?;
    result.push_str(&last_rewrite);

    if first_line_width(&result) > shape.width {
        return None;
    }

    // Check the last expression in the list. We sometimes let this expression
    // go over multiple lines, but we check for some ugly conditions.
    if !(is_single_line(&result) || last_rewrite.starts_with('{'))
        && (last_rewrite.starts_with('(') || prefix_len > context.config.tab_spaces())
    {
        return None;
    }

    wrap_str(result, context.config.max_width(), shape)
}

fn rewrite_pairs_multiline<T: Rewrite>(
    list: PairList<T>,
    shape: Shape,
    context: &RewriteContext,
) -> Option<String> {
    let rhs_offset = shape.rhs_overhead(&context.config);
    let nested_shape = (match context.config.indent_style() {
        IndentStyle::Visual => shape.visual_indent(0),
        IndentStyle::Block => shape.block_indent(context.config.tab_spaces()),
    })
    .with_max_width(&context.config)
    .sub_width(rhs_offset)?;

    let indent_str = nested_shape.indent.to_string_with_newline(context.config);
    let mut result = String::new();

    let rewrite = list.list[0].rewrite(context, shape)?;
    result.push_str(&rewrite);

    for (e, s) in list.list[1..].iter().zip(list.separators.iter()) {
        // The following test checks if we should keep two subexprs on the same
        // line. We do this if not doing so would create an orphan and there is
        // enough space to do so.
        let offset = if result.contains('\n') {
            0
        } else {
            shape.used_width()
        };
        if last_line_width(&result) + offset <= nested_shape.used_width() {
            // We must snuggle the next line onto the previous line to avoid an orphan.
            if let Some(line_shape) =
                shape.offset_left(s.len() + 2 + trimmed_last_line_width(&result))
            {
                if let Some(rewrite) = e.rewrite(context, line_shape) {
                    result.push(' ');
                    result.push_str(s);
                    result.push(' ');
                    result.push_str(&rewrite);
                    continue;
                }
            }
        }

        let nested_overhead = s.len() + 1;
        let line_shape = match context.config.binop_separator() {
            SeparatorPlace::Back => {
                result.push(' ');
                result.push_str(s);
                result.push_str(&indent_str);
                nested_shape.sub_width(nested_overhead)?
            }
            SeparatorPlace::Front => {
                result.push_str(&indent_str);
                result.push_str(s);
                result.push(' ');
                nested_shape.offset_left(nested_overhead)?
            }
        };

        let rewrite = e.rewrite(context, line_shape)?;
        result.push_str(&rewrite);
    }
    Some(result)
}

// Rewrites a single pair.
pub(crate) fn rewrite_pair<LHS, RHS>(
    lhs: &LHS,
    rhs: &RHS,
    pp: PairParts,
    context: &RewriteContext,
    shape: Shape,
    separator_place: SeparatorPlace,
) -> Option<String>
where
    LHS: Rewrite,
    RHS: Rewrite,
{
    let tab_spaces = context.config.tab_spaces();
    let lhs_overhead = match separator_place {
        SeparatorPlace::Back => shape.used_width() + pp.prefix.len() + pp.infix.trim_right().len(),
        SeparatorPlace::Front => shape.used_width(),
    };
    let lhs_shape = Shape {
        width: context.budget(lhs_overhead),
        ..shape
    };
    let lhs_result = lhs
        .rewrite(context, lhs_shape)
        .map(|lhs_str| format!("{}{}", pp.prefix, lhs_str))?;

    // Try to put both lhs and rhs on the same line.
    let rhs_orig_result = shape
        .offset_left(last_line_width(&lhs_result) + pp.infix.len())
        .and_then(|s| s.sub_width(pp.suffix.len()))
        .and_then(|rhs_shape| rhs.rewrite(context, rhs_shape));
    if let Some(ref rhs_result) = rhs_orig_result {
        // If the length of the lhs is equal to or shorter than the tab width or
        // the rhs looks like block expression, we put the rhs on the same
        // line with the lhs even if the rhs is multi-lined.
        let allow_same_line = lhs_result.len() <= tab_spaces || rhs_result
            .lines()
            .next()
            .map(|first_line| first_line.ends_with('{'))
            .unwrap_or(false);
        if !rhs_result.contains('\n') || allow_same_line {
            let one_line_width = last_line_width(&lhs_result)
                + pp.infix.len()
                + first_line_width(rhs_result)
                + pp.suffix.len();
            if one_line_width <= shape.width {
                return Some(format!(
                    "{}{}{}{}",
                    lhs_result, pp.infix, rhs_result, pp.suffix
                ));
            }
        }
    }

    // We have to use multiple lines.
    // Re-evaluate the rhs because we have more space now:
    let mut rhs_shape = match context.config.indent_style() {
        IndentStyle::Visual => shape
            .sub_width(pp.suffix.len() + pp.prefix.len())?
            .visual_indent(pp.prefix.len()),
        IndentStyle::Block => {
            // Try to calculate the initial constraint on the right hand side.
            let rhs_overhead = shape.rhs_overhead(context.config);
            Shape::indented(shape.indent.block_indent(context.config), context.config)
                .sub_width(rhs_overhead)?
        }
    };
    let infix = match separator_place {
        SeparatorPlace::Back => pp.infix.trim_right(),
        SeparatorPlace::Front => pp.infix.trim_left(),
    };
    if separator_place == SeparatorPlace::Front {
        rhs_shape = rhs_shape.offset_left(infix.len())?;
    }
    let rhs_result = rhs.rewrite(context, rhs_shape)?;
    let indent_str = rhs_shape.indent.to_string_with_newline(context.config);
    let infix_with_sep = match separator_place {
        SeparatorPlace::Back => format!("{}{}", infix, indent_str),
        SeparatorPlace::Front => format!("{}{}", indent_str, infix),
    };
    Some(format!(
        "{}{}{}{}",
        lhs_result, infix_with_sep, rhs_result, pp.suffix
    ))
}

// A pair which forms a tree and can be flattened (e.g., binops).
trait FlattenPair: Rewrite + Sized {
    // If `_same_op` is `true`, then we only combine binops with the same
    // operator into the list. E.g,, if the source is `a * b + c`, if `_same_op`
    // is true, we make `[(a * b), c]` if `_same_op` is false, we make
    // `[a, b, c]`
    fn flatten(&self, _same_op: bool) -> Option<PairList<Self>> {
        None
    }
}

struct PairList<'a, 'b, T: Rewrite + 'b> {
    list: Vec<&'b T>,
    separators: Vec<&'a str>,
}

impl FlattenPair for ast::Expr {
    fn flatten(&self, same_op: bool) -> Option<PairList<ast::Expr>> {
        let top_op = match self.node {
            ast::ExprKind::Binary(op, _, _) => op.node,
            _ => return None,
        };

        // Turn a tree of binop expressions into a list using a depth-first,
        // in-order traversal.
        let mut stack = vec![];
        let mut list = vec![];
        let mut separators = vec![];
        let mut node = self;
        loop {
            match node.node {
                ast::ExprKind::Binary(op, ref lhs, _) if !same_op || op.node == top_op => {
                    stack.push(node);
                    node = lhs;
                }
                _ => {
                    list.push(node);
                    if let Some(pop) = stack.pop() {
                        match pop.node {
                            ast::ExprKind::Binary(op, _, ref rhs) => {
                                separators.push(op.node.to_string());
                                node = rhs;
                            }
                            _ => unreachable!(),
                        }
                    } else {
                        break;
                    }
                }
            }
        }

        assert_eq!(list.len() - 1, separators.len());
        Some(PairList {
            list,
            separators,
        })
    }
}

impl FlattenPair for ast::Ty {}
impl FlattenPair for ast::Pat {}
<|endoftext|>


<commit_before>use command::Command;

pub fn parse(s: &str) -> Vec<Command> {
    let mut vec = Vec::new();
    for c in s.chars() {
        let command = match c {
            '.' => Some(Command::Output),
            ',' => Some(Command::Input),
            '<' => Some(Command::LeftShift),
            '>' => Some(Command::RightShift),
            '+' => Some(Command::Increment),
            '-' => Some(Command::Decrement),
            '[' => Some(Command::JumpForward),
            ']' => Some(Command::JumpBackward),
            _   => None,
        };
        match command {
            Some(com) => vec.push(com),
            None => {},
        }
    }
    vec
}
<commit_msg>Add unit test for parse::parse(&str)<commit_after>use command::Command;

pub fn parse(s: &str) -> Vec<Command> {
    let mut vec = Vec::new();
    for c in s.chars() {
        let command = match c {
            '.' => Some(Command::Output),
            ',' => Some(Command::Input),
            '<' => Some(Command::LeftShift),
            '>' => Some(Command::RightShift),
            '+' => Some(Command::Increment),
            '-' => Some(Command::Decrement),
            '[' => Some(Command::JumpForward),
            ']' => Some(Command::JumpBackward),
            _   => None,
        };
        match command {
            Some(com) => vec.push(com),
            None => {},
        }
    }
    vec
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_parse() {
        const COMMAND_TOUR: &'static str = ".,><+-[]9";
        let actual = parse(&COMMAND_TOUR);
        let expected = [
            Command::Output,
            Command::Input,
            Command::RightShift,
            Command::LeftShift,
            Command::Increment,
            Command::Decrement,
            Command::JumpForward,
            Command::JumpBackward,
        ];
        assert_eq!(actual, expected);
    }
}
<|endoftext|>


<commit_before>use std;
use std::{mem,u32};
use std::ops::Drop;
use super::{ErrorType, to_error_type};
use native::*;

pub struct Queue {
    handle: *const QueueHandle
}

impl Queue {
    pub fn create(agent: &Agent, size: u32, queue_type: QueueType) -> Result<Queue, ErrorType> {
        let handle: *const QueueHandle = unsafe { mem::zeroed() };
        unsafe {
            match hsa_queue_create(agent.clone(), size, queue_type,
                                   std::ptr::null(), std::ptr::null(),
                                   u32::MAX, u32::MAX, &handle) {
                0 => Ok(Queue {
                    handle: handle
                }),
                e => Err(to_error_type(e))
            }
        }
    }

    pub fn enqueue(&mut self, packet: &KernelDispatchPacket) {
        unsafe {
            let handle = &*(self.handle);
            let index = hsa_queue_load_write_index_relaxed(self.handle);
            let queue_index = (index & (handle.size as u64)) as usize;
            let queue_ptr = (handle.base_address as *mut u8).offset((queue_index * PACKET_SIZE) as isize);
            let queue_body_ptr = queue_ptr.offset(4);
            let packet_ptr = packet as *const _ as *const u8;
            let packet_header = *(packet_ptr as *const u32);
            let packet_body_ptr = packet_ptr.offset(4);
            std::ptr::copy(packet_body_ptr, queue_body_ptr, PACKET_SIZE - 4);
            std::intrinsics::atomic_store_rel(queue_ptr as *mut u32,
                                              packet_header);
            hsa_signal_store_relaxed(handle.doorbell_signal.clone(), index as SignalValue);
        }
    }

    /*
    pub fn load_read_index_acquire(&self) -> u64 {
        unsafe {
            hsa_queue_load_read_index_acquire(self.handle)
        }
    }
    pub fn load_read_index_relaxed(&self) -> u64 {
        unsafe {
            hsa_queue_load_read_index_relaxed(self.handle)
        }
    }
    pub fn load_write_index_acquire(&self) -> u64 {
        unsafe {
            hsa_queue_load_write_index_acquire(self.handle)
        }
    }
    pub fn load_write_index_relaxed(&self) -> u64 {
        unsafe {
            hsa_queue_load_write_index_relaxed(self.handle)
        }
    }
    pub fn store_write_index_relaxed(&mut self, value: u64) {
        unsafe {
            hsa_queue_store_write_index_relaxed(self.handle, value)
        }
    }
    pub fn store_write_index_release(&mut self, value: u64) {
        unsafe {
            hsa_queue_store_write_index_release(self.handle, value)
        }
    }
    pub fn cas_write_index_acq_rel(&mut self, expected: u64, value: u64) -> u64 {
        unsafe {
            hsa_queue_cas_write_index_acq_rel(self.handle, expected, value)
        }
    }
    pub fn cas_write_index_acquire(&mut self, expected: u64, value: u64) -> u64 {
        unsafe {
            hsa_queue_cas_write_index_acquire(self.handle, expected, value)
        }
    }
    pub fn cas_write_index_relaxed(&mut self, expected: u64, value: u64) -> u64 {
        unsafe {
            hsa_queue_cas_write_index_relaxed(self.handle, expected, value)
        }
    }
    pub fn cas_write_index_release(&mut self, expected: u64, value: u64) -> u64 {
        unsafe {
            hsa_queue_cas_write_index_release(self.handle, expected, value)
        }
    }
    pub fn add_write_index_acq_rel(&mut self, value: u64) -> u64 {
        unsafe {
            hsa_queue_add_write_index_acq_rel(self.handle, value)
        }
    }
    pub fn add_write_index_acquire(&mut self, value: u64) -> u64 {
        unsafe {
            hsa_queue_add_write_index_acquire(self.handle, value)
        }
    }
    pub fn add_write_index_relaxed(&mut self, value: u64) -> u64 {
        unsafe {
            hsa_queue_add_write_index_relaxed(self.handle, value)
        }
    }
    pub fn add_write_index_release(&mut self, value: u64) -> u64 {
        unsafe {
            hsa_queue_add_write_index_release(self.handle, value)
        }
    }
    pub fn store_read_index_relaxed(&mut self, value: u64) {
        unsafe {
            hsa_queue_store_read_index_relaxed(self.handle, value)
        }
    }
    pub fn store_read_index_release(&mut self, value: u64) {
        unsafe {
            hsa_queue_store_read_index_release(self.handle, value)
        }
    }*/
}

impl Drop for Queue {
    fn drop(&mut self) {
        if self.handle != std::ptr::null() {
            unsafe {
                hsa_queue_destroy(self.handle);
            }
            self.handle = std::ptr::null();
        }
    }
}
<commit_msg>Queueの不具合を修正．2つ以上のパケットを処理できるようになった．<commit_after>use std;
use std::{mem,u32};
use std::ops::Drop;
use super::{ErrorType, to_error_type};
use native::*;

pub struct Queue {
    handle: *const QueueHandle
}

impl Queue {
    pub fn create(agent: &Agent, size: u32, queue_type: QueueType) -> Result<Queue, ErrorType> {
        let handle: *const QueueHandle = unsafe { mem::zeroed() };
        unsafe {
            match hsa_queue_create(agent.clone(), size, queue_type,
                                   std::ptr::null(), std::ptr::null(),
                                   u32::MAX, u32::MAX, &handle) {
                0 => Ok(Queue {
                    handle: handle
                }),
                e => Err(to_error_type(e))
            }
        }
    }

    pub fn enqueue(&mut self, packet: &KernelDispatchPacket) {
        unsafe {
            let handle = &*(self.handle);
            let index = hsa_queue_add_write_index_relaxed(self.handle, 1);
            let queue_index = (index % (handle.size as u64)) as usize;
            let queue_ptr = (handle.base_address as *mut u8).offset((queue_index * PACKET_SIZE) as isize);
            let queue_body_ptr = queue_ptr.offset(4);
            let packet_ptr = packet as *const _ as *const u8;
            let packet_header = *(packet_ptr as *const u32);
            let packet_body_ptr = packet_ptr.offset(4);
            std::ptr::copy(packet_body_ptr, queue_body_ptr, PACKET_SIZE - 4);
            std::intrinsics::atomic_store_rel(queue_ptr as *mut u32,
                                              packet_header);
            hsa_signal_store_relaxed(handle.doorbell_signal.clone(), index as SignalValue);
        }
    }

    /*
    pub fn load_read_index_acquire(&self) -> u64 {
        unsafe {
            hsa_queue_load_read_index_acquire(self.handle)
        }
    }
    pub fn load_read_index_relaxed(&self) -> u64 {
        unsafe {
            hsa_queue_load_read_index_relaxed(self.handle)
        }
    }
    pub fn load_write_index_acquire(&self) -> u64 {
        unsafe {
            hsa_queue_load_write_index_acquire(self.handle)
        }
    }
    pub fn load_write_index_relaxed(&self) -> u64 {
        unsafe {
            hsa_queue_load_write_index_relaxed(self.handle)
        }
    }
    pub fn store_write_index_relaxed(&mut self, value: u64) {
        unsafe {
            hsa_queue_store_write_index_relaxed(self.handle, value)
        }
    }
    pub fn store_write_index_release(&mut self, value: u64) {
        unsafe {
            hsa_queue_store_write_index_release(self.handle, value)
        }
    }
    pub fn cas_write_index_acq_rel(&mut self, expected: u64, value: u64) -> u64 {
        unsafe {
            hsa_queue_cas_write_index_acq_rel(self.handle, expected, value)
        }
    }
    pub fn cas_write_index_acquire(&mut self, expected: u64, value: u64) -> u64 {
        unsafe {
            hsa_queue_cas_write_index_acquire(self.handle, expected, value)
        }
    }
    pub fn cas_write_index_relaxed(&mut self, expected: u64, value: u64) -> u64 {
        unsafe {
            hsa_queue_cas_write_index_relaxed(self.handle, expected, value)
        }
    }
    pub fn cas_write_index_release(&mut self, expected: u64, value: u64) -> u64 {
        unsafe {
            hsa_queue_cas_write_index_release(self.handle, expected, value)
        }
    }
    pub fn add_write_index_acq_rel(&mut self, value: u64) -> u64 {
        unsafe {
            hsa_queue_add_write_index_acq_rel(self.handle, value)
        }
    }
    pub fn add_write_index_acquire(&mut self, value: u64) -> u64 {
        unsafe {
            hsa_queue_add_write_index_acquire(self.handle, value)
        }
    }
    pub fn add_write_index_relaxed(&mut self, value: u64) -> u64 {
        unsafe {
            hsa_queue_add_write_index_relaxed(self.handle, value)
        }
    }
    pub fn add_write_index_release(&mut self, value: u64) -> u64 {
        unsafe {
            hsa_queue_add_write_index_release(self.handle, value)
        }
    }
    pub fn store_read_index_relaxed(&mut self, value: u64) {
        unsafe {
            hsa_queue_store_read_index_relaxed(self.handle, value)
        }
    }
    pub fn store_read_index_release(&mut self, value: u64) {
        unsafe {
            hsa_queue_store_read_index_release(self.handle, value)
        }
    }*/
}

impl Drop for Queue {
    fn drop(&mut self) {
        if self.handle != std::ptr::null() {
            unsafe {
                hsa_queue_destroy(self.handle);
            }
            self.handle = std::ptr::null();
        }
    }
}
<|endoftext|>