<commit_before>#[link(name = "grid", vers = "1.0", author = "jbaldwin")];
#[crate_type = "lib"];

extern mod std;
extern mod extra;

use std::path;
use std::io;
use std::int;

pub enum CellState {
	Alive,
	Dead
}

pub struct Cell {
	pub state: CellState
}

impl Cell {
	pub fn alive(&self, neighbours_alive: int) -> CellState {

		match self.state {
			Alive => match neighbours_alive {
				2 | 3 => Alive,	// Rule #2
				_ => Dead		// Rules #1, #3
			},
			Dead => match neighbours_alive {
				3 => Alive,		// Rule #4
				_ => Dead
			}
		}
	}
}

pub struct Grid {
	curr: ~[~[Cell]],
	next: ~[~[Cell]]
}

impl Grid {

	pub fn width(&self) -> int { self.curr.len() as int }
	pub fn height(&self) -> int { self.curr[0].len() as int }

	pub fn step(&mut self) {
		/*
		* Rules
		* 1) Any live cell with fewer than two live neighbours dies.
		* 2) Any live cell with two or three live neighbours lives.
		* 3) Any live cell with more than three live neighbours dies.
		* 4) Any dead cell with exactly three live neighbours becomes a live cell.
		*/

		let neighbours = [
			[-1, -1],
			[ 0, -1],
			[ 1, -1],
			[-1,  0],
			[ 1,  0],
			[-1,  1],
			[ 0,  1],
			[ 1,  1]
		];

		for int::range(0, self.width()) |row| {
			for int::range(0, self.height()) |col| {
				let mut count = 0;

				for int::range(0, neighbours.len() as int) |n| {
					let x = neighbours[n][0] + row;
					let y = neighbours[n][1] + col;

					if self.in_bounds(x, y) {
						count +=  match self.curr[x][y].state {
							Dead => 0,
							Alive => 1,

						};
					}

					// stop counting, the cell is dead
					if count >= 4 { break; }
				}
				self.next[row][col].state = self.curr[row][col].alive(count);
			}
		}

		self.copy_back();
	}

	/**
	* Loads the input grid file.
	* File format is line delmited '0's and '1's.
	* 1 = The square is true|on in the game of life.
	* 0 = The square is false|off in the game of life.
	**/
	pub fn load(file: &path::Path) -> ~Grid {

		let read_result = io::file_reader(file);

		let lines = match read_result {
			Ok(file) => file.read_lines(),
			Err(e) => {
				fail!(fmt!("Error reading input grid file: %?", e))
			}
		};

		let mut g: ~Grid = ~Grid { curr: ~[], next: ~[] };

		for lines.iter().advance() |line: &~str| {
			let mut row1: ~[Cell] = ~[];
			let mut row2: ~[Cell] = ~[];
			for line.iter().advance() |c| {
				let cell: Cell = match c {
					'0' => Cell { state: Dead },
					'1' => Cell { state: Alive },
					_ => fail!(fmt!("Error parsing input grid file: %c is not valid, 0 or 1 only.", c))
				};
				row1.push(cell);
				row2.push(cell);
			}
			g.curr.push(row1);
			g.next.push(row2);
		}

		return g;
	}

	pub fn print(&self) {
		for self.curr.iter().advance() |row| {
			for row.iter().advance() |cell| {
				print(fmt!("%c", match cell.state {
					Dead => '-',
					Alive => '*'
				}));
			}
			println("");
		}
	}

	fn in_bounds(&self, x: int, y: int) -> bool {
		if x >= 0 && x < self.width() &&
		   y >= 0 && y < self.height()
		   { true } else { false }
	}

	fn copy_back(&mut self) {
		for int::range(0, self.width()) |i| {
			for int::range(0, self.height()) |j| {
				self.curr[i][j].state = self.next[i][j].state;
			}
		}
	}
}<commit_msg>quick buffer swap (unsafe)<commit_after>#[link(name = "grid", vers = "1.0", author = "jbaldwin")];
#[crate_type = "lib"];

extern mod std;
extern mod extra;

use std::path;
use std::io;
use std::int;

pub enum CellState {
	Alive,
	Dead
}

pub struct Cell {
	pub state: CellState
}

impl Cell {
	pub fn alive(&self, neighbours_alive: int) -> CellState {

		match self.state {
			Alive => match neighbours_alive {
				2 | 3 => Alive,	// Rule #2
				_ => Dead		// Rules #1, #3
			},
			Dead => match neighbours_alive {
				3 => Alive,		// Rule #4
				_ => Dead
			}
		}
	}
}

pub struct Grid {
	curr: ~[~[Cell]],
	next: ~[~[Cell]]
}

impl Grid {

	pub fn width(&self) -> int { self.curr.len() as int }
	pub fn height(&self) -> int { self.curr[0].len() as int }

	pub fn step(&mut self) {
		/*
		* Rules
		* 1) Any live cell with fewer than two live neighbours dies.
		* 2) Any live cell with two or three live neighbours lives.
		* 3) Any live cell with more than three live neighbours dies.
		* 4) Any dead cell with exactly three live neighbours becomes a live cell.
		*/

		let neighbours = [
			[-1, -1],
			[ 0, -1],
			[ 1, -1],
			[-1,  0],
			[ 1,  0],
			[-1,  1],
			[ 0,  1],
			[ 1,  1]
		];

		for int::range(0, self.width()) |row| {
			for int::range(0, self.height()) |col| {
				let mut count = 0;

				for int::range(0, neighbours.len() as int) |n| {
					let x = neighbours[n][0] + row;
					let y = neighbours[n][1] + col;

					if self.in_bounds(x, y) {
						count +=  match self.curr[x][y].state {
							Dead => 0,
							Alive => 1,

						};
					}

					// stop counting, the cell is dead
					if count >= 4 { break; }
				}
				self.next[row][col].state = self.curr[row][col].alive(count);
			}
		}

		// set curr to next and next to curr for quick buffer swapping
		self.swap_buffers();
	}

	/**
	* Loads the input grid file.
	* File format is line delmited '0's and '1's.
	* 1 = The square is true|on in the game of life.
	* 0 = The square is false|off in the game of life.
	**/
	pub fn load(file: &path::Path) -> ~Grid {

		let read_result = io::file_reader(file);

		let lines = match read_result {
			Ok(file) => file.read_lines(),
			Err(e) => {
				fail!(fmt!("Error reading input grid file: %?", e))
			}
		};

		let mut g: ~Grid = ~Grid { curr: ~[], next: ~[] };

		for lines.iter().advance() |line: &~str| {
			let mut row1: ~[Cell] = ~[];
			let mut row2: ~[Cell] = ~[];
			for line.iter().advance() |c| {
				let cell: Cell = match c {
					'0' => Cell { state: Dead },
					'1' => Cell { state: Alive },
					_ => fail!(fmt!("Error parsing input grid file: %c is not valid, 0 or 1 only.", c))
				};
				row1.push(cell);
				row2.push(cell);
			}
			g.curr.push(row1);
			g.next.push(row2);
		}

		return g;
	}

	pub fn print(&self) {
		for self.curr.iter().advance() |row| {
			for row.iter().advance() |cell| {
				print(fmt!("%c", match cell.state {
					Dead => '-',
					Alive => '*'
				}));
			}
			println("");
		}
	}

	fn in_bounds(&self, x: int, y: int) -> bool {
		if x >= 0 && x < self.width() &&
		   y >= 0 && y < self.height()
		   { true } else { false }
	}

	fn swap_buffers(&mut self) {
		unsafe {
			std::ptr::swap_ptr(
				std::ptr::to_mut_unsafe_ptr(&mut self.curr),
				std::ptr::to_mut_unsafe_ptr(&mut self.next));
		}
	}
}<|endoftext|>


<commit_before>use crate::clean;
use crate::core::DocContext;
use crate::fold::{self, DocFolder};
use crate::passes::Pass;

use syntax::attr;

pub const CALCULATE_DOC_COVERAGE: Pass = Pass {
    name: "calculate-doc-coverage",
    pass: calculate_doc_coverage,
    description: "counts the number of items with and without documentation",
};

fn calculate_doc_coverage(krate: clean::Crate, _: &DocContext<'_, '_, '_>) -> clean::Crate {
    let mut calc = CoverageCalculator::default();
    let krate = calc.fold_crate(krate);

    let total_minus_traits = calc.total - calc.total_trait_impls;
    let docs_minus_traits = calc.with_docs - calc.trait_impls_with_docs;

    print!("Rustdoc found {}/{} items with documentation", calc.with_docs, calc.total);
    println!(" ({}/{} not counting trait impls)", docs_minus_traits, total_minus_traits);

    if calc.total > 0 {
        let percentage = (calc.with_docs as f64 * 100.0) / calc.total as f64;
        let percentage_minus_traits =
            (docs_minus_traits as f64 * 100.0) / total_minus_traits as f64;
        println!("    Score: {:.1}% ({:.1}% not counting trait impls)",
                 percentage, percentage_minus_traits);
    }

    krate
}

#[derive(Default)]
struct CoverageCalculator {
    total: usize,
    with_docs: usize,
    total_trait_impls: usize,
    trait_impls_with_docs: usize,
}

impl fold::DocFolder for CoverageCalculator {
    fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> {
        match i.inner {
            clean::StrippedItem(..) => {}
            clean::ImplItem(ref impl_)
                if attr::contains_name(&i.attrs.other_attrs, "automatically_derived")
                    || impl_.synthetic || impl_.blanket_impl.is_some() =>
            {
                // skip counting anything inside these impl blocks
                // FIXME(misdreavus): need to also find items that came out of a derive macro
                return Some(i);
            }
            // non-local items are skipped because they can be out of the users control, especially
            // in the case of trait impls, which rustdoc eagerly inlines
            _ => if i.def_id.is_local() {
                let has_docs = !i.attrs.doc_strings.is_empty();

                if let clean::ImplItem(ref i) = i.inner {
                    if let Some(ref tr) = i.trait_ {
                        debug!("counting impl {:#} for {:#}", tr, i.for_);

                        self.total += 1;
                        if has_docs {
                            self.with_docs += 1;
                        }

                        // trait impls inherit their docs from the trait definition, so documenting
                        // them can be considered optional

                        self.total_trait_impls += 1;
                        if has_docs {
                            self.trait_impls_with_docs += 1;
                        }

                        for it in &i.items {
                            self.total_trait_impls += 1;
                            if !it.attrs.doc_strings.is_empty() {
                                self.trait_impls_with_docs += 1;
                            }
                        }
                    } else {
                        // inherent impls *can* be documented, and those docs show up, but in most
                        // cases it doesn't make sense, as all methods on a type are in one single
                        // impl block
                        debug!("not counting impl {:#}", i.for_);
                    }
                } else {
                    debug!("counting {} {:?}", i.type_(), i.name);
                    self.total += 1;
                    if has_docs {
                        self.with_docs += 1;
                    }
                }
            }
        }

        self.fold_item_recur(i)
    }
}
<commit_msg>count fewer items in calculate-doc-coverage<commit_after>use crate::clean;
use crate::core::DocContext;
use crate::fold::{self, DocFolder};
use crate::passes::Pass;

use syntax::attr;

pub const CALCULATE_DOC_COVERAGE: Pass = Pass {
    name: "calculate-doc-coverage",
    pass: calculate_doc_coverage,
    description: "counts the number of items with and without documentation",
};

fn calculate_doc_coverage(krate: clean::Crate, _: &DocContext<'_, '_, '_>) -> clean::Crate {
    let mut calc = CoverageCalculator::default();
    let krate = calc.fold_crate(krate);

    let total_minus_traits = calc.total - calc.total_trait_impls;
    let docs_minus_traits = calc.with_docs - calc.trait_impls_with_docs;

    print!("Rustdoc found {}/{} items with documentation", calc.with_docs, calc.total);
    println!(" ({}/{} not counting trait impls)", docs_minus_traits, total_minus_traits);

    if calc.total > 0 {
        let percentage = (calc.with_docs as f64 * 100.0) / calc.total as f64;
        let percentage_minus_traits =
            (docs_minus_traits as f64 * 100.0) / total_minus_traits as f64;
        println!("    Score: {:.1}% ({:.1}% not counting trait impls)",
                 percentage, percentage_minus_traits);
    }

    krate
}

#[derive(Default)]
struct CoverageCalculator {
    total: usize,
    with_docs: usize,
    total_trait_impls: usize,
    trait_impls_with_docs: usize,
}

impl fold::DocFolder for CoverageCalculator {
    fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> {
        match i.inner {
            clean::StrippedItem(..) => {
                // don't count items in stripped modules
                return Some(i);
            }
            clean::ImportItem(..) | clean::ExternCrateItem(..) => {}
            clean::ImplItem(ref impl_)
                if attr::contains_name(&i.attrs.other_attrs, "automatically_derived")
                    || impl_.synthetic || impl_.blanket_impl.is_some() =>
            {
                // skip counting anything inside these impl blocks
                // FIXME(misdreavus): need to also find items that came out of a derive macro
                return Some(i);
            }
            // non-local items are skipped because they can be out of the users control, especially
            // in the case of trait impls, which rustdoc eagerly inlines
            _ => if i.def_id.is_local() {
                let has_docs = !i.attrs.doc_strings.is_empty();

                if let clean::ImplItem(ref i) = i.inner {
                    if let Some(ref tr) = i.trait_ {
                        debug!("counting impl {:#} for {:#}", tr, i.for_);

                        self.total += 1;
                        if has_docs {
                            self.with_docs += 1;
                        }

                        // trait impls inherit their docs from the trait definition, so documenting
                        // them can be considered optional

                        self.total_trait_impls += 1;
                        if has_docs {
                            self.trait_impls_with_docs += 1;
                        }

                        for it in &i.items {
                            self.total_trait_impls += 1;
                            if !it.attrs.doc_strings.is_empty() {
                                self.trait_impls_with_docs += 1;
                            }
                        }
                    } else {
                        // inherent impls *can* be documented, and those docs show up, but in most
                        // cases it doesn't make sense, as all methods on a type are in one single
                        // impl block
                        debug!("not counting impl {:#}", i.for_);
                    }
                } else {
                    debug!("counting {} {:?}", i.type_(), i.name);
                    self.total += 1;
                    if has_docs {
                        self.with_docs += 1;
                    }
                }
            }
        }

        self.fold_item_recur(i)
    }
}
<|endoftext|>


<commit_before>use crate::utils::{
    is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then,
    visitors::find_all_ret_expressions,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::*;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for private functions that only return `Ok` or `Some`.
    ///
    /// **Why is this bad?** It is not meaningful to wrap values when no `None` or `Err` is returned.
    ///
    /// **Known problems:** Since this lint changes function type signature, you may need to
    /// adjust some code at callee side.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> Option<i32> {
    ///     if a && b {
    ///         return Some(50);
    ///     }
    ///     if a {
    ///         Some(0)
    ///     } else {
    ///         Some(10)
    ///     }
    /// }
    /// ```
    /// Use instead:
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> i32 {
    ///     if a && b {
    ///         return 50;
    ///     }
    ///     if a {
    ///         0
    ///     } else {
    ///         10
    ///     }
    /// }
    /// ```
    pub UNNECESSARY_WRAP,
    complexity,
    "functions that only return `Ok` or `Some`"
}

declare_lint_pass!(UnnecessaryWrap => [UNNECESSARY_WRAP]);

impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap {
    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        fn_kind: FnKind<'tcx>,
        fn_decl: &FnDecl<'tcx>,
        body: &Body<'tcx>,
        span: Span,
        hir_id: HirId,
    ) {
        if_chain! {
            if let FnKind::ItemFn(.., visibility, _) = fn_kind;
            if visibility.node.is_pub();
            then {
                return;
            }
        }

        let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) {
            ("Option", &paths::OPTION_SOME)
        } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) {
            ("Result", &paths::RESULT_OK)
        } else {
            return;
        };

        let mut suggs = Vec::new();
        let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
            if_chain! {
                if let ExprKind::Call(ref func, ref args) = ret_expr.kind;
                if let ExprKind::Path(ref qpath) = func.kind;
                if match_qpath(qpath, path);
                if args.len() == 1;
                then {
                    suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string()));
                    true
                } else {
                    false
                }
            }
        });

        if can_sugg {
            span_lint_and_then(
                cx,
                UNNECESSARY_WRAP,
                span,
                format!("this function's return value is unnecessarily wrapped by `{}`", return_type).as_str(),
                |diag| {
                    let inner_ty = return_ty(cx, hir_id)
                        .walk()
                        .skip(1) // skip `std::option::Option` or `std::result::Result`
                        .take(1) // take the first outermost inner type
                        .filter_map(|inner| match inner.unpack() {
                            GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()),
                            _ => None,
                        });
                    inner_ty.for_each(|inner_ty| {
                        diag.span_suggestion(
                            fn_decl.output.span(),
                            format!("remove `{}` from the return type...", return_type).as_str(),
                            inner_ty,
                            Applicability::MachineApplicable,
                        );
                    });
                    diag.multipart_suggestion(
                        "...and change the returning expressions",
                        suggs,
                        Applicability::MachineApplicable,
                    );
                },
            );
        }
    }
}
<commit_msg>Run `cargo dev fmt`<commit_after>use crate::utils::{
    is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then,
    visitors::find_all_ret_expressions,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::*;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for private functions that only return `Ok` or `Some`.
    ///
    /// **Why is this bad?** It is not meaningful to wrap values when no `None` or `Err` is returned.
    ///
    /// **Known problems:** Since this lint changes function type signature, you may need to
    /// adjust some code at callee side.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> Option<i32> {
    ///     if a && b {
    ///         return Some(50);
    ///     }
    ///     if a {
    ///         Some(0)
    ///     } else {
    ///         Some(10)
    ///     }
    /// }
    /// ```
    /// Use instead:
    /// ```rust
    /// fn get_cool_number(a: bool, b: bool) -> i32 {
    ///     if a && b {
    ///         return 50;
    ///     }
    ///     if a {
    ///         0
    ///     } else {
    ///         10
    ///     }
    /// }
    /// ```
    pub UNNECESSARY_WRAP,
    complexity,
    "functions that only return `Ok` or `Some`"
}

declare_lint_pass!(UnnecessaryWrap => [UNNECESSARY_WRAP]);

impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap {
    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        fn_kind: FnKind<'tcx>,
        fn_decl: &FnDecl<'tcx>,
        body: &Body<'tcx>,
        span: Span,
        hir_id: HirId,
    ) {
        if_chain! {
            if let FnKind::ItemFn(.., visibility, _) = fn_kind;
            if visibility.node.is_pub();
            then {
                return;
            }
        }

        let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) {
            ("Option", &paths::OPTION_SOME)
        } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) {
            ("Result", &paths::RESULT_OK)
        } else {
            return;
        };

        let mut suggs = Vec::new();
        let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
            if_chain! {
                if let ExprKind::Call(ref func, ref args) = ret_expr.kind;
                if let ExprKind::Path(ref qpath) = func.kind;
                if match_qpath(qpath, path);
                if args.len() == 1;
                then {
                    suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string()));
                    true
                } else {
                    false
                }
            }
        });

        if can_sugg {
            span_lint_and_then(
                cx,
                UNNECESSARY_WRAP,
                span,
                format!(
                    "this function's return value is unnecessarily wrapped by `{}`",
                    return_type
                )
                .as_str(),
                |diag| {
                    let inner_ty = return_ty(cx, hir_id)
                        .walk()
                        .skip(1) // skip `std::option::Option` or `std::result::Result`
                        .take(1) // take the first outermost inner type
                        .filter_map(|inner| match inner.unpack() {
                            GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()),
                            _ => None,
                        });
                    inner_ty.for_each(|inner_ty| {
                        diag.span_suggestion(
                            fn_decl.output.span(),
                            format!("remove `{}` from the return type...", return_type).as_str(),
                            inner_ty,
                            Applicability::MachineApplicable,
                        );
                    });
                    diag.multipart_suggestion(
                        "...and change the returning expressions",
                        suggs,
                        Applicability::MachineApplicable,
                    );
                },
            );
        }
    }
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use std::default::Default;

use LoadAvg;
use ProcessorExt;

/// Dummy struct that represents a processor.
pub struct Processor {}

impl ProcessorExt for Processor {
    fn get_cpu_usage(&self) -> f32 {
        0.0
    }

    fn get_name(&self) -> &str {
        ""
    }

    fn get_frequency(&self) -> u64 {
        0
    }

    fn get_vendor_id(&self) -> &str {
        ""
    }
}
<commit_msg>Add get_brand for unknown<commit_after>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use std::default::Default;

use LoadAvg;
use ProcessorExt;

/// Dummy struct that represents a processor.
pub struct Processor {}

impl ProcessorExt for Processor {
    fn get_cpu_usage(&self) -> f32 {
        0.0
    }

    fn get_name(&self) -> &str {
        ""
    }

    fn get_frequency(&self) -> u64 {
        0
    }

    fn get_vendor_id(&self) -> &str {
        ""
    }

    fn get_brand(&self) -> &str {
        ""
    }
}
<|endoftext|>


<commit_before>extern crate eom;
extern crate ndarray;
extern crate ndarray_linalg;
extern crate num_traits;

use ndarray::*;
use ndarray_linalg::*;
use std::fs::*;
use std::io::Write;

use eom::traits::*;
use eom::*;

fn check_accuracy<A, D, Sc>(teo: Sc, init: Array<A, D>, fname: &str)
where
    A: Scalar<Real = f64>,
    D: Dimension,
    Sc: Scheme<Scalar = A, Dim = D, Time = f64>,
{
    let acc = adaptor::accuracy(teo, init, 0.01, 1000, 12);
    let mut f = File::create(fname).unwrap();
    write!(&mut f, "dt,dev\n").unwrap();
    for &(dt, dev) in acc.iter() {
        write!(&mut f, "{:.08e},{:.08e}\n", dt, dev).unwrap();
    }
}

fn main() {
    let l63 = ode::Lorenz63::default();
    check_accuracy(
        explicit::Euler::new(l63.clone(), 1.0),
        arr1(&[1.0, 0.0, 0.0]),
        "euler.csv",
    );
    check_accuracy(
        explicit::Heun::new(l63.clone(), 1.0),
        arr1(&[1.0, 0.0, 0.0]),
        "heun.csv",
    );
    check_accuracy(
        explicit::RK4::new(l63.clone(), 1.0),
        arr1(&[1.0, 0.0, 0.0]),
        "rk4.csv",
    );
    check_accuracy(
        semi_implicit::DiagRK4::new(l63.clone(), 1.0),
        arr1(&[1.0, 0.0, 0.0]),
        "diag_rk4.csv",
    );
}
<commit_msg>Update example code<commit_after>extern crate eom;
extern crate ndarray;
extern crate ndarray_linalg;
extern crate num_traits;

use ndarray::*;
use std::fs::*;
use std::io::Write;

use eom::traits::*;
use eom::*;

fn check_accuracy<Sc>(teo: Sc, init: Array1<f64>, fname: &str)
where
    Sc: Scheme<Scalar = f64, Dim = Ix1, Time = f64>,
{
    let acc = adaptor::accuracy(teo, init, 0.01, 1000, 12);
    let mut f = File::create(fname).unwrap();
    write!(&mut f, "dt,dev\n").unwrap();
    for &(dt, dev) in acc.iter() {
        write!(&mut f, "{:.08e},{:.08e}\n", dt, dev).unwrap();
    }
}

fn main() {
    let l63 = ode::Lorenz63::default();
    check_accuracy(
        explicit::Euler::new(l63.clone(), 1.0),
        arr1(&[1.0, 0.0, 0.0]),
        "euler.csv",
    );
    check_accuracy(
        explicit::Heun::new(l63.clone(), 1.0),
        arr1(&[1.0, 0.0, 0.0]),
        "heun.csv",
    );
    check_accuracy(
        explicit::RK4::new(l63.clone(), 1.0),
        arr1(&[1.0, 0.0, 0.0]),
        "rk4.csv",
    );
    check_accuracy(
        semi_implicit::DiagRK4::new(l63.clone(), 1.0),
        arr1(&[1.0, 0.0, 0.0]),
        "diag_rk4.csv",
    );
}
<|endoftext|>


<commit_before>//! A demonstration of constructing and using a non-blocking stream.
//!
//! Audio from the default input device is passed directly to the default output device in a duplex
//! stream, so beware of feedback!

extern crate portaudio;

use portaudio as pa;

const SAMPLE_RATE: f64 = 44_100.0;
const FRAMES: u32 = 256;
const CHANNELS: i32 = 2;
const INTERLEAVED: bool = true;

fn main() {
    run().unwrap()
}

fn run() -> Result<(), pa::Error> {

    let pa = try!(pa::PortAudio::new());

    println!("PortAudio:");
    println!("version: {}", pa.version());
    println!("version text: {:?}", pa.version_text());
    println!("host count: {}", try!(pa.host_api_count()));

    let default_host = try!(pa.default_host_api());
    println!("default host: {:#?}", pa.host_api_info(default_host));

    let def_input = try!(pa.default_input_device());
    let input_info = try!(pa.device_info(def_input));
    println!("Default input device info: {:#?}", &input_info);

    // Construct the input stream parameters.
    let latency = input_info.default_low_input_latency;
    let input_params = pa::StreamParameters::<f32>::new(def_input, CHANNELS, INTERLEAVED, latency);

    let def_output = try!(pa.default_output_device());
    let output_info = try!(pa.device_info(def_output));
    println!("Default output device info: {:#?}", &output_info);

    // Construct the output stream parameters.
    let latency = output_info.default_low_output_latency;
    let output_params = pa::StreamParameters::new(def_output, CHANNELS, INTERLEAVED, latency);

    // Check that the stream format is supported.
    try!(pa.is_duplex_format_supported(input_params, output_params, SAMPLE_RATE));

    // Construct the settings with which we'll open our duplex stream.
    let settings = pa::DuplexStreamSettings {
        in_params: input_params,
        out_params: output_params,
        sample_rate: SAMPLE_RATE,
        frames_per_buffer: FRAMES,
        flags: pa::StreamFlags::empty(),
    };

    // Once the countdown reaches 0 we'll close the stream.
    let mut count_down = 3.0;

    // Keep track of the last `current_time` so we can calculate the delta time.
    let mut maybe_last_time = None;

    // We'll use this channel to send the count_down to the main thread for fun.
    let (sender, receiver) = ::std::sync::mpsc::channel();

    // A callback to pass to the non-blocking stream.
    let callback = move |args: pa::DuplexStreamCallbackArgs<f32, f32>| {
        let pa::DuplexStreamCallbackArgs { in_buffer, out_buffer, frames, time, .. } = args;

        let current_time = time.current;
        let prev_time = maybe_last_time.unwrap_or(current_time);
        let dt = current_time - prev_time;
        count_down -= dt;
        maybe_last_time = Some(current_time);

        assert!(frames == FRAMES as usize);
        sender.send(count_down).ok();

        // Pass the input straight to the output - BEWARE OF FEEDBACK!
        for (output_sample, input_sample) in out_buffer.iter_mut().zip(in_buffer.iter()) {
            *output_sample = *input_sample;
        }

        if count_down > 0.0 { pa::Continue } else { pa::Complete }
    };

    // Construct a stream with input and output sample types of f32.
    let mut stream = try!(pa.open_non_blocking_stream(settings, callback));

    try!(stream.start());

    // Loop while the non-blocking stream is active.
    while let true = try!(stream.is_active()) {

        // Do some stuff!
        while let Ok(count_down) = receiver.try_recv() {
            println!("count_down: {:?}", count_down);
        }

    }

    try!(stream.stop());

    Ok(())
}
<commit_msg>Destructure callback args in arg position for less code<commit_after>//! A demonstration of constructing and using a non-blocking stream.
//!
//! Audio from the default input device is passed directly to the default output device in a duplex
//! stream, so beware of feedback!

extern crate portaudio;

use portaudio as pa;

const SAMPLE_RATE: f64 = 44_100.0;
const FRAMES: u32 = 256;
const CHANNELS: i32 = 2;
const INTERLEAVED: bool = true;

fn main() {
    run().unwrap()
}

fn run() -> Result<(), pa::Error> {

    let pa = try!(pa::PortAudio::new());

    println!("PortAudio:");
    println!("version: {}", pa.version());
    println!("version text: {:?}", pa.version_text());
    println!("host count: {}", try!(pa.host_api_count()));

    let default_host = try!(pa.default_host_api());
    println!("default host: {:#?}", pa.host_api_info(default_host));

    let def_input = try!(pa.default_input_device());
    let input_info = try!(pa.device_info(def_input));
    println!("Default input device info: {:#?}", &input_info);

    // Construct the input stream parameters.
    let latency = input_info.default_low_input_latency;
    let input_params = pa::StreamParameters::<f32>::new(def_input, CHANNELS, INTERLEAVED, latency);

    let def_output = try!(pa.default_output_device());
    let output_info = try!(pa.device_info(def_output));
    println!("Default output device info: {:#?}", &output_info);

    // Construct the output stream parameters.
    let latency = output_info.default_low_output_latency;
    let output_params = pa::StreamParameters::new(def_output, CHANNELS, INTERLEAVED, latency);

    // Check that the stream format is supported.
    try!(pa.is_duplex_format_supported(input_params, output_params, SAMPLE_RATE));

    // Construct the settings with which we'll open our duplex stream.
    let settings = pa::DuplexStreamSettings {
        in_params: input_params,
        out_params: output_params,
        sample_rate: SAMPLE_RATE,
        frames_per_buffer: FRAMES,
        flags: pa::StreamFlags::empty(),
    };

    // Once the countdown reaches 0 we'll close the stream.
    let mut count_down = 3.0;

    // Keep track of the last `current_time` so we can calculate the delta time.
    let mut maybe_last_time = None;

    // We'll use this channel to send the count_down to the main thread for fun.
    let (sender, receiver) = ::std::sync::mpsc::channel();

    // A callback to pass to the non-blocking stream.
    let callback = move |pa::DuplexStreamCallbackArgs { in_buffer, out_buffer, frames, time, .. }| {
        let current_time = time.current;
        let prev_time = maybe_last_time.unwrap_or(current_time);
        let dt = current_time - prev_time;
        count_down -= dt;
        maybe_last_time = Some(current_time);

        assert!(frames == FRAMES as usize);
        sender.send(count_down).ok();

        // Pass the input straight to the output - BEWARE OF FEEDBACK!
        for (output_sample, input_sample) in out_buffer.iter_mut().zip(in_buffer.iter()) {
            *output_sample = *input_sample;
        }

        if count_down > 0.0 { pa::Continue } else { pa::Complete }
    };

    // Construct a stream with input and output sample types of f32.
    let mut stream = try!(pa.open_non_blocking_stream(settings, callback));

    try!(stream.start());

    // Loop while the non-blocking stream is active.
    while let true = try!(stream.is_active()) {

        // Do some stuff!
        while let Ok(count_down) = receiver.try_recv() {
            println!("count_down: {:?}", count_down);
        }

    }

    try!(stream.stop());

    Ok(())
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (strings) anychar combinator

use nom::{
    branch::alt,
    bytes::complete::tag,
    character::complete::{anychar, one_of},
    combinator::{map_opt, recognize},
    multi::{many0, many_m_n},
    sequence::preceded,
    IResult,
};

fn parse_octal(input: &str) -> IResult<&str, char> {
    map_opt(
        preceded(tag("\\"), recognize(many_m_n(1, 3, one_of("01234567")))),
        |out: &str| {
            u32::from_str_radix(out, 8)
                .map(std::char::from_u32)
                .ok()
                .flatten()
        },
    )(input)
}

pub fn reduce_octal_to_char(input: &str) -> String {
    let result = many0(alt((parse_octal, anychar)))(input)
        .map(|(_, r)| r)
        .unwrap()
        .into_iter()
        .collect();
    result
}
<commit_msg>remove 'let and return'<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (strings) anychar combinator

use nom::{
    branch::alt,
    bytes::complete::tag,
    character::complete::{anychar, one_of},
    combinator::{map_opt, recognize},
    multi::{many0, many_m_n},
    sequence::preceded,
    IResult,
};

fn parse_octal(input: &str) -> IResult<&str, char> {
    map_opt(
        preceded(tag("\\"), recognize(many_m_n(1, 3, one_of("01234567")))),
        |out: &str| {
            u32::from_str_radix(out, 8)
                .map(std::char::from_u32)
                .ok()
                .flatten()
        },
    )(input)
}

pub fn reduce_octal_to_char(input: &str) -> String {
    many0(alt((parse_octal, anychar)))(input)
        .map(|(_, r)| r)
        .unwrap()
        .into_iter()
        .collect()
}
<|endoftext|>


<commit_before>use nom::{
    branch::alt,
    bytes::complete::tag,
    character::complete::{anychar, one_of},
    combinator::{map_opt, recognize},
    multi::{many0, many_m_n},
    sequence::preceded,
    IResult,
};

fn parse_octal(input: &str) -> IResult<&str, char> {
    map_opt(
        preceded(tag("\\"), recognize(many_m_n(1, 3, one_of("01234567")))),
        |out: &str| {
            u32::from_str_radix(out, 8)
                .map(|u| char::from_u32(u))
                .ok()
                .flatten()
        },
    )(input)
}

pub fn reduce_octal_to_char(input: String) -> String {
    let result = many0(alt((parse_octal, anychar)))(input.as_str())
        .map(|(_, r)| r)
        .unwrap()
        .into_iter()
        .collect();
    result
}
<commit_msg>Fixed clippy issues<commit_after>use nom::{
    branch::alt,
    bytes::complete::tag,
    character::complete::{anychar, one_of},
    combinator::{map_opt, recognize},
    multi::{many0, many_m_n},
    sequence::preceded,
    IResult,
};

fn parse_octal(input: &str) -> IResult<&str, char> {
    map_opt(
        preceded(tag("\\"), recognize(many_m_n(1, 3, one_of("01234567")))),
        |out: &str| {
            u32::from_str_radix(out, 8)
                .map(char::from_u32)
                .ok()
                .flatten()
        },
    )(input)
}

pub fn reduce_octal_to_char(input: String) -> String {
    let result = many0(alt((parse_octal, anychar)))(input.as_str())
        .map(|(_, r)| r)
        .unwrap()
        .into_iter()
        .collect();
    result
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct};
use itertools::Itertools;
use ra_ide_db::RootDatabase;
use ra_syntax::{
    algo,
    ast::{self, Path, RecordLit, RecordPat},
    match_ast, AstNode, SyntaxKind,
    SyntaxKind::*,
    SyntaxNode,
};

use crate::{
    assist_ctx::{Assist, AssistCtx},
    AssistId,
};

// Assist: reorder_fields
//
// Reorder the fields of record literals and record patterns in the same order as in
// the definition.
//
// ```
// struct Foo {foo: i32, bar: i32};
// const test: Foo = <|>Foo {bar: 0, foo: 1}
// ```
// ->
// ```
// struct Foo {foo: i32, bar: i32};
// const test: Foo = Foo {foo: 1, bar: 0}
// ```
//
pub(crate) fn reorder_fields(ctx: AssistCtx) -> Option<Assist> {
    reorder::<RecordLit>(ctx.clone()).or_else(|| reorder::<RecordPat>(ctx))
}

fn reorder<R: AstNode>(ctx: AssistCtx) -> Option<Assist> {
    let record = ctx.find_node_at_offset::<R>()?;
    let path = record.syntax().children().find_map(Path::cast)?;

    let ranks = compute_fields_ranks(&path, &ctx)?;

    let fields = get_fields(&record.syntax());
    let sorted_fields = sorted_by_rank(&fields, |node| {
        *ranks.get(&get_field_name(node)).unwrap_or(&usize::max_value())
    });

    if sorted_fields == fields {
        return None;
    }

    ctx.add_assist(AssistId("reorder_fields"), "Reorder record fields", |edit| {
        for (old, new) in fields.iter().zip(&sorted_fields) {
            algo::diff(old, new).into_text_edit(edit.text_edit_builder());
        }
        edit.target(record.syntax().text_range())
    })
}

fn get_fields_kind(node: &SyntaxNode) -> Vec<SyntaxKind> {
    match node.kind() {
        RECORD_LIT => vec![RECORD_FIELD],
        RECORD_PAT => vec![RECORD_FIELD_PAT, BIND_PAT],
        _ => vec![],
    }
}

fn get_field_name(node: &SyntaxNode) -> String {
    let res = match_ast! {
        match node {
            ast::RecordField(field) => { field.field_name().map(|it| it.to_string()) },
            ast::RecordFieldPat(field) => { field.field_name().map(|it| it.to_string()) },
            _ => None,
        }
    };
    res.unwrap_or_default()
}

fn get_fields(record: &SyntaxNode) -> Vec<SyntaxNode> {
    let kinds = get_fields_kind(record);
    record.children().flat_map(|n| n.children()).filter(|n| kinds.contains(&n.kind())).collect()
}

fn sorted_by_rank(
    fields: &[SyntaxNode],
    get_rank: impl Fn(&SyntaxNode) -> usize,
) -> Vec<SyntaxNode> {
    fields.iter().cloned().sorted_by_key(get_rank).collect()
}

fn struct_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option<Struct> {
    match sema.resolve_path(path) {
        Some(PathResolution::Def(ModuleDef::Adt(Adt::Struct(s)))) => Some(s),
        _ => None,
    }
}

fn compute_fields_ranks(path: &Path, ctx: &AssistCtx) -> Option<HashMap<String, usize>> {
    Some(
        struct_definition(path, ctx.sema)?
            .fields(ctx.db)
            .iter()
            .enumerate()
            .map(|(idx, field)| (field.name(ctx.db).to_string(), idx))
            .collect(),
    )
}

#[cfg(test)]
mod tests {
    use crate::helpers::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn not_applicable_if_sorted() {
        check_assist_not_applicable(
            reorder_fields,
            r#"
        struct Foo {
            foo: i32,
            bar: i32,
        }

        const test: Foo = <|>Foo { foo: 0, bar: 0 };
        "#,
        )
    }

    #[test]
    fn trivial_empty_fields() {
        check_assist_not_applicable(
            reorder_fields,
            r#"
        struct Foo {};
        const test: Foo = <|>Foo {}
        "#,
        )
    }

    #[test]
    fn reorder_struct_fields() {
        check_assist(
            reorder_fields,
            r#"
        struct Foo {foo: i32, bar: i32};
        const test: Foo = <|>Foo {bar: 0, foo: 1}
        "#,
            r#"
        struct Foo {foo: i32, bar: i32};
        const test: Foo = <|>Foo {foo: 1, bar: 0}
        "#,
        )
    }

    #[test]
    fn reorder_struct_pattern() {
        check_assist(
            reorder_fields,
            r#"
        struct Foo { foo: i64, bar: i64, baz: i64 }

        fn f(f: Foo) -> {
            match f {
                <|>Foo { baz: 0, ref mut bar, .. } => (),
                _ => ()
            }
        }
        "#,
            r#"
        struct Foo { foo: i64, bar: i64, baz: i64 }

        fn f(f: Foo) -> {
            match f {
                <|>Foo { ref mut bar, baz: 0, .. } => (),
                _ => ()
            }
        }
        "#,
        )
    }

    #[test]
    fn reorder_with_extra_field() {
        check_assist(
            reorder_fields,
            r#"
            struct Foo {
                foo: String,
                bar: String,
            }

            impl Foo {
                fn new() -> Foo {
                    let foo = String::new();
                    <|>Foo {
                        bar: foo.clone(),
                        extra: "Extra field",
                        foo,
                    }
                }
            }
            "#,
            r#"
            struct Foo {
                foo: String,
                bar: String,
            }

            impl Foo {
                fn new() -> Foo {
                    let foo = String::new();
                    <|>Foo {
                        foo,
                        bar: foo.clone(),
                        extra: "Extra field",
                    }
                }
            }
            "#,
        )
    }
}
<commit_msg>Remove more unnecessary braces<commit_after>use std::collections::HashMap;

use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct};
use itertools::Itertools;
use ra_ide_db::RootDatabase;
use ra_syntax::{
    algo,
    ast::{self, Path, RecordLit, RecordPat},
    match_ast, AstNode, SyntaxKind,
    SyntaxKind::*,
    SyntaxNode,
};

use crate::{
    assist_ctx::{Assist, AssistCtx},
    AssistId,
};

// Assist: reorder_fields
//
// Reorder the fields of record literals and record patterns in the same order as in
// the definition.
//
// ```
// struct Foo {foo: i32, bar: i32};
// const test: Foo = <|>Foo {bar: 0, foo: 1}
// ```
// ->
// ```
// struct Foo {foo: i32, bar: i32};
// const test: Foo = Foo {foo: 1, bar: 0}
// ```
//
pub(crate) fn reorder_fields(ctx: AssistCtx) -> Option<Assist> {
    reorder::<RecordLit>(ctx.clone()).or_else(|| reorder::<RecordPat>(ctx))
}

fn reorder<R: AstNode>(ctx: AssistCtx) -> Option<Assist> {
    let record = ctx.find_node_at_offset::<R>()?;
    let path = record.syntax().children().find_map(Path::cast)?;

    let ranks = compute_fields_ranks(&path, &ctx)?;

    let fields = get_fields(&record.syntax());
    let sorted_fields = sorted_by_rank(&fields, |node| {
        *ranks.get(&get_field_name(node)).unwrap_or(&usize::max_value())
    });

    if sorted_fields == fields {
        return None;
    }

    ctx.add_assist(AssistId("reorder_fields"), "Reorder record fields", |edit| {
        for (old, new) in fields.iter().zip(&sorted_fields) {
            algo::diff(old, new).into_text_edit(edit.text_edit_builder());
        }
        edit.target(record.syntax().text_range())
    })
}

fn get_fields_kind(node: &SyntaxNode) -> Vec<SyntaxKind> {
    match node.kind() {
        RECORD_LIT => vec![RECORD_FIELD],
        RECORD_PAT => vec![RECORD_FIELD_PAT, BIND_PAT],
        _ => vec![],
    }
}

fn get_field_name(node: &SyntaxNode) -> String {
    let res = match_ast! {
        match node {
            ast::RecordField(field) => field.field_name().map(|it| it.to_string()),
            ast::RecordFieldPat(field) => field.field_name().map(|it| it.to_string()),
            _ => None,
        }
    };
    res.unwrap_or_default()
}

fn get_fields(record: &SyntaxNode) -> Vec<SyntaxNode> {
    let kinds = get_fields_kind(record);
    record.children().flat_map(|n| n.children()).filter(|n| kinds.contains(&n.kind())).collect()
}

fn sorted_by_rank(
    fields: &[SyntaxNode],
    get_rank: impl Fn(&SyntaxNode) -> usize,
) -> Vec<SyntaxNode> {
    fields.iter().cloned().sorted_by_key(get_rank).collect()
}

fn struct_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option<Struct> {
    match sema.resolve_path(path) {
        Some(PathResolution::Def(ModuleDef::Adt(Adt::Struct(s)))) => Some(s),
        _ => None,
    }
}

fn compute_fields_ranks(path: &Path, ctx: &AssistCtx) -> Option<HashMap<String, usize>> {
    Some(
        struct_definition(path, ctx.sema)?
            .fields(ctx.db)
            .iter()
            .enumerate()
            .map(|(idx, field)| (field.name(ctx.db).to_string(), idx))
            .collect(),
    )
}

#[cfg(test)]
mod tests {
    use crate::helpers::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn not_applicable_if_sorted() {
        check_assist_not_applicable(
            reorder_fields,
            r#"
        struct Foo {
            foo: i32,
            bar: i32,
        }

        const test: Foo = <|>Foo { foo: 0, bar: 0 };
        "#,
        )
    }

    #[test]
    fn trivial_empty_fields() {
        check_assist_not_applicable(
            reorder_fields,
            r#"
        struct Foo {};
        const test: Foo = <|>Foo {}
        "#,
        )
    }

    #[test]
    fn reorder_struct_fields() {
        check_assist(
            reorder_fields,
            r#"
        struct Foo {foo: i32, bar: i32};
        const test: Foo = <|>Foo {bar: 0, foo: 1}
        "#,
            r#"
        struct Foo {foo: i32, bar: i32};
        const test: Foo = <|>Foo {foo: 1, bar: 0}
        "#,
        )
    }

    #[test]
    fn reorder_struct_pattern() {
        check_assist(
            reorder_fields,
            r#"
        struct Foo { foo: i64, bar: i64, baz: i64 }

        fn f(f: Foo) -> {
            match f {
                <|>Foo { baz: 0, ref mut bar, .. } => (),
                _ => ()
            }
        }
        "#,
            r#"
        struct Foo { foo: i64, bar: i64, baz: i64 }

        fn f(f: Foo) -> {
            match f {
                <|>Foo { ref mut bar, baz: 0, .. } => (),
                _ => ()
            }
        }
        "#,
        )
    }

    #[test]
    fn reorder_with_extra_field() {
        check_assist(
            reorder_fields,
            r#"
            struct Foo {
                foo: String,
                bar: String,
            }

            impl Foo {
                fn new() -> Foo {
                    let foo = String::new();
                    <|>Foo {
                        bar: foo.clone(),
                        extra: "Extra field",
                        foo,
                    }
                }
            }
            "#,
            r#"
            struct Foo {
                foo: String,
                bar: String,
            }

            impl Foo {
                fn new() -> Foo {
                    let foo = String::new();
                    <|>Foo {
                        foo,
                        bar: foo.clone(),
                        extra: "Extra field",
                    }
                }
            }
            "#,
        )
    }
}
<|endoftext|>


<commit_before>extern crate crossbeam;
extern crate walkdir;

pub mod single_threaded;

use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
use std::fs;
use self::crossbeam::sync::chase_lev;
use self::walkdir::WalkDir;
use regex::{RegexSet, Regex};
use std::path::PathBuf;
use colored::*;
use std::process::exit;
use utils::size;
use std::thread;
use error::*;
use types::FileSize;
use std::path::Path;

pub use walk_parallel::single_threaded::*;

/// Enum for messaging between workers/stealers
pub enum Status<T> {
    Done,
    Data(T),
}

/// The 'Walk' struct contains all the information we need to traverse a directory.
#[derive(Debug)]
pub struct Walk {
    pub path: PathBuf,
    gitignore: Option<RegexSet>,
    hgignore: Option<RegexSet>,
    darcs_boring: Option<RegexSet>,
    excludes: Option<Regex>,
    max_depth: Option<u8>,
    threshold: Option<u64>,
    start_depth: usize,
    nproc: usize,
    show_files: bool,
    get_blocks: bool,
    follow_symlinks: bool,
    artifacts_only: bool,
}

impl Walk {
    /// function to make output from a 'Walk', using one thread. It also takes an 'Arc<AtomicU64>'
    /// and will add the relevant directory sizes to it.
    pub fn print_dir(w: Walk, total: Arc<AtomicU64>) -> () {

        let excludes = match w.excludes {
            Some(ref x) => Some(x),
            _ => None,
        };

        let v = if excludes.is_some() || w.artifacts_only {
            read_all(
                &w.path,
                (w.start_depth as u8),
                w.max_depth,
                excludes,
                &w.gitignore,
                false,
                w.artifacts_only,
            )
        } else {
            read_all_fast(&w.path, (w.start_depth as u8), w.max_depth)
        };

        let subdir_size = v.file_size.get();

        total.fetch_add(subdir_size, Ordering::Relaxed);

        let mut to_print = if let Some(m) = w.threshold {
            subdir_size > m
        } else {
            true
        };

        if let Some(0) = w.max_depth {
            to_print = false;
        }

        if to_print {
            // filter by depth
            let mut v_filtered = v.filtered(w.threshold, !w.show_files, w.max_depth);

            v_filtered.display_tree(w.path);
        }
    }

    /// set the maximum depth to display
    pub fn set_depth(&mut self, d: u8) -> () {
        self.max_depth = Some(d);
    }

    /// set the regex for excludes
    pub fn set_regex(&mut self, r: Regex) -> () {
        self.excludes = Some(r);
    }

    /// set the minumum file size
    pub fn set_threshold(&mut self, n: u64) -> () {
        self.threshold = Some(n);
    }

    /// include files when printing
    pub fn with_files(&mut self) -> () {
        self.show_files = true;
    }

    /// include files when printing
    pub fn blocks(&mut self) -> () {
        self.get_blocks = true;
    }

    /// include files when printing
    pub fn artifacts_only(&mut self) -> () {
        self.artifacts_only = true;
    }

    fn get_proc(&self) -> usize {
        self.nproc
    }

    /// Create a new 'Walk' from a 'PathBuf' and the number
    /// of processor cores to be used.
    pub fn new(p: PathBuf, n: usize) -> Walk {
        Walk {
            path: p,
            gitignore: None,
            hgignore: None,
            darcs_boring: None,
            excludes: None,
            max_depth: None,
            threshold: None,
            start_depth: 0,
            nproc: n,
            show_files: false,
            get_blocks: false,
            follow_symlinks: false,
            artifacts_only: false,
        }
    }

    fn bump_depth(&mut self) -> () {
        self.start_depth += 1;
    }

    /// This takes a 'Walk' and a 'Worker<Status<Walk>>' and executes the walk *in parallel*,
    /// creating new work for each subdirectory. It's not the most efficient concurrency
    /// imaginable, but it's fast and easy-ish to use. It *also* takes in an 'Arc<AtomicU64>',
    /// which it updates with any file sizes in the directory.
    pub fn push_subdir(
        w: &Walk,
        worker: &mut chase_lev::Worker<Status<Walk>>,
        total: Arc<AtomicU64>,
    ) {

        let in_paths = &w.path;

        // fill up queue + print out files
        if let Ok(paths) = fs::read_dir(in_paths) {

            // iterate over all the entries in the directory
            for p in paths {
                let val = match p {
                    Ok(x) => x,
                    _ => {
                        eprintln!("{}: path error at {:?}.", "Error".red(), p);
                        exit(0x0001)
                    }
                };

                let exclude_check = if let Some(ref x) = w.excludes {
                    if let Some(r) = val.path().into_os_string().to_str() {
                        !x.is_match(r)
                    } else {
                        eprintln!(
                            "{}: ignoring invalid unicode at: {:?}",
                            "Warning".yellow(),
                            val.path().display()
                        );
                        true
                    }
                } else {
                    true
                };

                if exclude_check {
                    match val.file_type() {
                        Ok(t) => {
                            if t.is_dir() {
                                let mut new_path = w.path.to_owned();
                                new_path.push(val.file_name());
                                let mut new_walk = Walk::new(new_path, w.get_proc());
                                if w.excludes.is_some() {
                                    new_walk.set_regex(w.excludes.clone().unwrap());
                                }
                                if w.show_files {
                                    new_walk.with_files();
                                }
                                new_walk.bump_depth();
                                if let Some(d) = w.max_depth {
                                    new_walk.set_depth(d);
                                }
                                if let Some(b) = w.threshold {
                                    new_walk.set_threshold(b);
                                }
                                worker.push(Status::Data(new_walk)); // pass a vector of Arc's to do 2-level traversals?
                            } else if t.is_file() {
                                if let Ok(l) = val.metadata() {
                                    let size = size(&l, w.get_blocks); // l.len();
                                    total.fetch_add(size, Ordering::Relaxed);
                                    if w.show_files && size != 0 {
                                        let to_formatted = format!("{}", FileSize::new(size));
                                        println!(
                                            "{}\t {}",
                                            &to_formatted.green(),
                                            val.path().display()
                                        );
                                    }
                                } else {
                                    eprintln!(
                                        "{}: could not find filesize for file at {}.",
                                        "Warning".yellow(),
                                        val.path().display()
                                    );
                                }
                            }
                        }
                        _ => {
                            eprintln!(
                                "{}: could not determine file type for: {}",
                                "Warning".yellow(),
                                val.path().display()
                            )
                        }
                    }
                }
            }

            // send "done" messages to all the workers
            let iter = 0..(w.get_proc());
            iter.map(|_| worker.push(Status::Done)).count();

        }
        // if we can't read the directory contents, figure out why
        // 1: check the path exists
        else if !in_paths.exists() {
            eprintln!(
                "{}: path '{}' does not exist, or you do not have permission to enter.",
                "Error".red(),
                &in_paths.display()
            );
        }
        // 2: check the path is actually a directory
        else if !in_paths.is_dir() {
            if w.artifacts_only {
                eprintln!(
                    "{}: {} is not a directory; not searching for artifacts",
                    "Warning".yellow(),
                    &in_paths.display()
                );
            }

            if let Ok(l) = in_paths.metadata() {
                let size = size(&l, w.get_blocks); // l.len();
                let to_formatted = format!("{}", FileSize::new(size));
                println!("{}\t {}", &to_formatted.green(), in_paths.display());
            } else {
                panic!("{}", Internal::IoError);
            }
        }
        // 3: otherwise, give a warning about permissions
        else {
            eprintln!(
                "{}: permission denied for directory: {}",
                "Warning".yellow(),
                &in_paths.display()
            );
        }

    }
}

fn latex_log<P: AsRef<Path>>(p: P) -> bool {

    lazy_static! {
        static ref LOG: Regex =
            Regex::new(r"\.log$")
            .unwrap();
    }

    if LOG.is_match(&p.as_ref().to_string_lossy().to_string()) {
        let mut parent = (&p.as_ref())
            .parent()
            .unwrap()
            .to_string_lossy()
            .to_string();
        parent.push_str("/*.tex");
        glob_exists(&parent)
    } else {
        false
    }

}

// TODO figure out why the unwrap_or is failing?
// FIXME take optional reference to a regex
pub fn clean_project_dirs<P: AsRef<Path>>(p: P, exclude: Option<Regex>, vimtags: bool) -> () {

    lazy_static! {
        static ref REGEX: Regex =
            Regex::new(r"(\.(a|la|lo|o|ll|keter|bc|dyn_o|d|rlib|crate|hi|hc|dyn_hi|S|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|hspec-failures|pyc|mod|go\.(v|teak|xmldef)|p_hi|p_o|prof|hide-cache|ghc\.environment\..*-\d.\d.\d|tix|synctex\.gz|hl))$")
            .unwrap();
    }

    for dir in WalkDir::new(p)
        .into_iter()
        .filter_map(|e| e.ok())
        .filter(|p| {
            exclude.clone().map(|e| {
                e.is_match(&p.path().to_string_lossy().to_string())
            }) != Some(false)
        })
        .filter(|p| {
            REGEX.is_match(&p.path().to_string_lossy().to_string()) ||
                is_project_dir(
                    &p.path().to_string_lossy().to_string(),
                    &p.path()
                        .file_name()
                        .map(|x| x.to_string_lossy().to_string())
                        .unwrap_or("".to_string()),
                ) || latex_log(&p.path()) ||
                ({
                     let x = &p.path().to_string_lossy().to_string();
                     x.ends_with("/flxg_stats.txt")
                 })
        })
    {
        if dir.file_type().is_file() {
            fs::remove_file(dir.path()).unwrap_or(());
        } else if dir.file_type().is_dir() {
            fs::remove_dir_all(dir.path()).unwrap_or(());
        }
    }
}

/// Given a 'Walk' struct, traverse it concurrently and print out any relevant outputs.
/// Currently, this only works for a depth of two, which is probably bad.
pub fn print_parallel(w: Walk) -> () {

    // initialize the total at 0 and create a reference to it
    let val = AtomicU64::new(0);
    let arc = Arc::new(val);
    let arc_producer = arc.clone();
    let arc_child = arc.clone();
    let path_display = w.path.clone();

    // set up worker & stealer
    let (mut worker, stealer): (chase_lev::Worker<Status<Walk>>,
                                chase_lev::Stealer<Status<Walk>>) = chase_lev::deque();

    // set up our iterator for the workers
    let iter = 0..(&w.get_proc() - 1);

    let spawn_workers = (&w.path).is_file();

    // create the producer in another thread
    let child_producer = thread::spawn(move || {

        let arc_local = arc_producer.clone();

        // assign work to everyone
        Walk::push_subdir(&w, &mut worker, arc_local.clone());

        // start popping off values in the worker's thread
        loop {
            if let Some(p) = worker.try_pop() {
                match p {
                    Status::Data(d) => Walk::print_dir(d, arc_local.clone()),
                    _ => break,
                };
            }
        }

    });

    // create a vector of thread handles so that it doesn't execute
    // everything sequentially.
    let mut threads = Vec::new();

    // set up as many workers as we have threads
    for _ in iter {

        // create a new stealer
        let stealer_clone = stealer.clone();

        let arc_local = arc_child.clone();

        // run the stealer in a new thread
        let child_consumer = thread::spawn(move || loop {

            if let chase_lev::Steal::Data(p) = stealer_clone.steal() {
                match p {
                    Status::Data(d) => Walk::print_dir(d, arc_local.clone()),
                    _ => break,
                };
            }
        });

        threads.push(child_consumer);

    }

    // join the child producer to the main thread
    let _ = child_producer.join();

    // join the workers to the main thread
    let _ = threads
        .into_iter()
        .map(|v| {
            let result = v.join();
            if let Ok(exit) = result {
                exit
            } else if let Err(e) = result {
                panic!("{:?}", e)
            }
        })
        .count();

    // get the total size
    let m = arc.load(Ordering::SeqCst); // TODO - check if this works with Relaxed?
    let size = FileSize::new(m);

    // print directory total.
    if size != FileSize::new(0) {
        let to_formatted = format!("{}", size);
        println!("{}\t {}", &to_formatted.green(), path_display.display());
    }

}
<commit_msg>minor adjustments<commit_after>extern crate crossbeam;
extern crate walkdir;

pub mod single_threaded;

use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
use std::fs;
use self::crossbeam::sync::chase_lev;
use self::walkdir::WalkDir;
use regex::{RegexSet, Regex};
use std::path::PathBuf;
use colored::*;
use std::process::exit;
use utils::size;
use std::thread;
use error::*;
use types::FileSize;
use std::path::Path;

pub use walk_parallel::single_threaded::*;

/// Enum for messaging between workers/stealers
pub enum Status<T> {
    Done,
    Data(T),
}

/// The 'Walk' struct contains all the information we need to traverse a directory.
#[derive(Debug)]
pub struct Walk {
    pub path: PathBuf,
    gitignore: Option<RegexSet>,
    hgignore: Option<RegexSet>,
    darcs_boring: Option<RegexSet>,
    excludes: Option<Regex>,
    max_depth: Option<u8>,
    threshold: Option<u64>,
    start_depth: usize,
    nproc: usize,
    show_files: bool,
    get_blocks: bool,
    follow_symlinks: bool,
    artifacts_only: bool,
}

impl Walk {
    /// function to make output from a 'Walk', using one thread. It also takes an 'Arc<AtomicU64>'
    /// and will add the relevant directory sizes to it.
    pub fn print_dir(w: Walk, total: Arc<AtomicU64>) -> () {

        let excludes = match w.excludes {
            Some(ref x) => Some(x),
            _ => None,
        };

        let v = if excludes.is_some() || w.artifacts_only {
            read_all(
                &w.path,
                (w.start_depth as u8),
                w.max_depth,
                excludes,
                &w.gitignore,
                false,
                w.artifacts_only,
            )
        } else {
            read_all_fast(&w.path, (w.start_depth as u8), w.max_depth)
        };

        let subdir_size = v.file_size.get();

        total.fetch_add(subdir_size, Ordering::Relaxed);

        let mut to_print = if let Some(m) = w.threshold {
            subdir_size > m
        } else {
            true
        };

        if let Some(0) = w.max_depth {
            to_print = false;
        }

        if to_print {
            // filter by depth
            let mut v_filtered = v.filtered(w.threshold, !w.show_files, w.max_depth);

            v_filtered.display_tree(w.path);
        }
    }

    /// set the maximum depth to display
    pub fn set_depth(&mut self, d: u8) -> () {
        self.max_depth = Some(d);
    }

    /// set the regex for excludes
    pub fn set_regex(&mut self, r: Regex) -> () {
        self.excludes = Some(r);
    }

    /// set the minumum file size
    pub fn set_threshold(&mut self, n: u64) -> () {
        self.threshold = Some(n);
    }

    /// include files when printing
    pub fn with_files(&mut self) -> () {
        self.show_files = true;
    }

    /// include files when printing
    pub fn blocks(&mut self) -> () {
        self.get_blocks = true;
    }

    /// include files when printing
    pub fn artifacts_only(&mut self) -> () {
        self.artifacts_only = true;
    }

    fn get_proc(&self) -> usize {
        self.nproc
    }

    /// Create a new 'Walk' from a 'PathBuf' and the number
    /// of processor cores to be used.
    pub fn new(p: PathBuf, n: usize) -> Walk {
        Walk {
            path: p,
            gitignore: None,
            hgignore: None,
            darcs_boring: None,
            excludes: None,
            max_depth: None,
            threshold: None,
            start_depth: 0,
            nproc: n,
            show_files: false,
            get_blocks: false,
            follow_symlinks: false,
            artifacts_only: false,
        }
    }

    fn bump_depth(&mut self) -> () {
        self.start_depth += 1;
    }

    /// This takes a 'Walk' and a 'Worker<Status<Walk>>' and executes the walk *in parallel*,
    /// creating new work for each subdirectory. It's not the most efficient concurrency
    /// imaginable, but it's fast and easy-ish to use. It *also* takes in an 'Arc<AtomicU64>',
    /// which it updates with any file sizes in the directory.
    pub fn push_subdir(
        w: &Walk,
        worker: &mut chase_lev::Worker<Status<Walk>>,
        total: Arc<AtomicU64>,
    ) {

        let in_paths = &w.path;

        // fill up queue + print out files
        if let Ok(paths) = fs::read_dir(in_paths) {

            // iterate over all the entries in the directory
            for p in paths {
                let val = match p {
                    Ok(x) => x,
                    _ => {
                        eprintln!("{}: path error at {:?}.", "Error".red(), p);
                        exit(0x0001)
                    }
                };

                let exclude_check = if let Some(ref x) = w.excludes {
                    if let Some(r) = val.path().into_os_string().to_str() {
                        !x.is_match(r)
                    } else {
                        eprintln!(
                            "{}: ignoring invalid unicode at: {:?}",
                            "Warning".yellow(),
                            val.path().display()
                        );
                        true
                    }
                } else {
                    true
                };

                if exclude_check {
                    match val.file_type() {
                        Ok(t) => {
                            if t.is_dir() {
                                let mut new_path = w.path.to_owned();
                                new_path.push(val.file_name());
                                let mut new_walk = Walk::new(new_path, w.get_proc());
                                if w.excludes.is_some() {
                                    new_walk.set_regex(w.excludes.clone().unwrap());
                                }
                                if w.show_files {
                                    new_walk.with_files();
                                }
                                new_walk.bump_depth();
                                if let Some(d) = w.max_depth {
                                    new_walk.set_depth(d);
                                }
                                if let Some(b) = w.threshold {
                                    new_walk.set_threshold(b);
                                }
                                worker.push(Status::Data(new_walk)); // pass a vector of Arc's to do 2-level traversals?
                            } else if t.is_file() {
                                if let Ok(l) = val.metadata() {
                                    let size = size(&l, w.get_blocks); // l.len();
                                    total.fetch_add(size, Ordering::Relaxed);
                                    if w.show_files && size != 0 {
                                        let to_formatted = format!("{}", FileSize::new(size));
                                        println!(
                                            "{}\t {}",
                                            &to_formatted.green(),
                                            val.path().display()
                                        );
                                    }
                                } else {
                                    eprintln!(
                                        "{}: could not find filesize for file at {}.",
                                        "Warning".yellow(),
                                        val.path().display()
                                    );
                                }
                            }
                        }
                        _ => {
                            eprintln!(
                                "{}: could not determine file type for: {}",
                                "Warning".yellow(),
                                val.path().display()
                            )
                        }
                    }
                }
            }

            // send "done" messages to all the workers
            let iter = 0..(w.get_proc());
            iter.map(|_| worker.push(Status::Done)).count();

        }
        // if we can't read the directory contents, figure out why
        // 1: check the path exists
        else if !in_paths.exists() {
            eprintln!(
                "{}: path '{}' does not exist, or you do not have permission to enter.",
                "Error".red(),
                &in_paths.display()
            );
        }
        // 2: check the path is actually a directory
        else if !in_paths.is_dir() {
            if w.artifacts_only {
                eprintln!(
                    "{}: {} is not a directory; not searching for artifacts",
                    "Warning".yellow(),
                    &in_paths.display()
                );
            }

            if let Ok(l) = in_paths.metadata() {
                let size = size(&l, w.get_blocks); // l.len();
                let to_formatted = format!("{}", FileSize::new(size));
                println!("{}\t {}", &to_formatted.green(), in_paths.display());
            } else {
                panic!("{}", Internal::IoError);
            }
        }
        // 3: otherwise, give a warning about permissions
        else {
            eprintln!(
                "{}: permission denied for directory: {}",
                "Warning".yellow(),
                &in_paths.display()
            );
        }

    }
}

fn latex_log<P: AsRef<Path>>(p: P) -> bool {

    lazy_static! {
        static ref LOG: Regex =
            Regex::new(r"\.log$")
            .unwrap();
    }

    if LOG.is_match(&p.as_ref().to_string_lossy().to_string()) {
        let mut parent = (&p.as_ref())
            .parent()
            .unwrap()
            .to_string_lossy()
            .to_string();
        parent.push_str("/*.tex");
        glob_exists(&parent)
    } else {
        false
    }

}

// TODO figure out why the unwrap_or is failing?
// FIXME take optional reference to a regex
pub fn clean_project_dirs<P: AsRef<Path>>(p: P, exclude: Option<Regex>, vimtags: bool) -> () {

    lazy_static! {
        static ref REGEX: Regex =
            Regex::new(r"\.(a|la|lo|o|ll|keter|bc|dyn_o|d|rlib|crate|hi|hc|dyn_hi|S|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|hspec-failures|pyc|mod|go\.(v|teak|xmldef)|p_hi|p_o|prof|hide-cache|ghc\.environment\..*-\d.\d.\d|tix|synctex\.gz|hl)$")
            .unwrap();
    }

    for dir in WalkDir::new(p)
        .into_iter()
        .filter_map(|e| e.ok())
        .filter(|p| {
            exclude.clone().map(|e| {
                e.is_match(&p.path().to_string_lossy().to_string())
            }) != Some(false)
        })
        .filter(|p| {
            REGEX.is_match(&p.path().to_string_lossy().to_string()) ||
                is_project_dir(
                    &p.path().to_string_lossy().to_string(),
                    &p.path()
                        .file_name()
                        .map(|x| x.to_string_lossy().to_string())
                        .unwrap_or("".to_string()),
                ) || latex_log(&p.path()) ||
                ({
                     let x = &p.path().to_string_lossy().to_string();
                     x.ends_with("/flxg_stats.txt")
                 })
        })
    {
        if dir.file_type().is_file() {
            fs::remove_file(dir.path()).unwrap_or(());
        } else if dir.file_type().is_dir() {
            fs::remove_dir_all(dir.path()).unwrap_or(());
        }
    }
}

/// Given a 'Walk' struct, traverse it concurrently and print out any relevant outputs.
/// Currently, this only works for a depth of two, which is probably bad.
pub fn print_parallel(w: Walk) -> () {

    // initialize the total at 0 and create a reference to it
    let val = AtomicU64::new(0);
    let arc = Arc::new(val);
    let arc_producer = arc.clone();
    let arc_child = arc.clone();
    let path_display = w.path.clone();

    // set up worker & stealer
    let (mut worker, stealer): (chase_lev::Worker<Status<Walk>>,
                                chase_lev::Stealer<Status<Walk>>) = chase_lev::deque();

    // set up our iterator for the workers
    let iter = 0..(&w.get_proc() - 1);

    let spawn_workers = (&w.path).is_file();

    // create the producer in another thread
    let child_producer = thread::spawn(move || {

        let arc_local = arc_producer.clone();

        // assign work to everyone
        Walk::push_subdir(&w, &mut worker, arc_local.clone());

        // start popping off values in the worker's thread
        loop {
            if let Some(p) = worker.try_pop() {
                match p {
                    Status::Data(d) => Walk::print_dir(d, arc_local.clone()),
                    _ => break,
                };
            }
        }

    });

    // create a vector of thread handles so that it doesn't execute
    // everything sequentially.
    let mut threads = Vec::new();

    // set up as many workers as we have threads
    for _ in iter {

        // create a new stealer
        let stealer_clone = stealer.clone();

        let arc_local = arc_child.clone();

        // run the stealer in a new thread
        let child_consumer = thread::spawn(move || loop {

            if let chase_lev::Steal::Data(p) = stealer_clone.steal() {
                match p {
                    Status::Data(d) => Walk::print_dir(d, arc_local.clone()),
                    _ => break,
                };
            }
        });

        threads.push(child_consumer);

    }

    // join the child producer to the main thread
    let _ = child_producer.join();

    // join the workers to the main thread
    let _ = threads
        .into_iter()
        .map(|v| {
            let result = v.join();
            if let Ok(exit) = result {
                exit
            } else if let Err(e) = result {
                panic!("{:?}", e)
            }
        })
        .count();

    // get the total size
    let m = arc.load(Ordering::SeqCst); // TODO - check if this works with Relaxed?
    let size = FileSize::new(m);

    // print directory total.
    if size != FileSize::new(0) {
        let to_formatted = format!("{}", size);
        println!("{}\t {}", &to_formatted.green(), path_display.display());
    }

}
<|endoftext|>


<commit_before>//! Functions for finding and labelling connected components of an image.

use image::{GenericImage, GenericImageView, ImageBuffer, Luma};

use definitions::Image;
use union_find::DisjointSetForest;
use std::cmp;

/// Determines which neighbors of a pixel we consider
/// to be connected to it.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Connectivity {
    /// A pixel is connected to its N, S, E and W neighbors.
    Four,
    /// A pixel is connected to all of its neighbors.
    Eight,
}

/// Returns an image of the same size as the input, where each pixel
/// is labelled by the connected foreground component it belongs to,
/// or 0 if it's in the background. Input pixels are treated as belonging
/// to the background if and only if they are equal to the provided background pixel.
///
/// # Examples
///
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Luma;
/// use imageproc::region_labelling::{connected_components, Connectivity};
///
/// let background_color = Luma([0u8]);
///
/// let image = gray_image!(
///     1, 0, 1, 1;
///     0, 1, 1, 0;
///     0, 0, 0, 0;
///     0, 0, 0, 1);
///
/// // With four-way connectivity the foreground regions which
/// // are only connected across diagonals belong to different
/// // connected components.
/// let components_four = gray_image!(type: u32,
///     1, 0, 2, 2;
///     0, 2, 2, 0;
///     0, 0, 0, 0;
///     0, 0, 0, 3);
///
/// assert_pixels_eq!(
///     connected_components(&image, Connectivity::Four, background_color),
///     components_four);
///
/// // With eight-way connectivity all foreground pixels in the top two rows
/// // belong to the same connected component.
/// let components_eight = gray_image!(type: u32,
///     1, 0, 1, 1;
///     0, 1, 1, 0;
///     0, 0, 0, 0;
///     0, 0, 0, 2);
///
/// assert_pixels_eq!(
///     connected_components(&image, Connectivity::Eight, background_color),
///     components_eight);
/// # }
/// ```
///
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// // This example is like the first, except that not all of the input foreground
/// // pixels are the same color. Pixels of different color are never counted
/// // as belonging to the same connected component.
///
/// use image::Luma;
/// use imageproc::region_labelling::{connected_components, Connectivity};
///
/// let background_color = Luma([0u8]);
///
/// let image = gray_image!(
///     1, 0, 1, 1;
///     0, 1, 2, 0;
///     0, 0, 0, 0;
///     0, 0, 0, 1);
///
/// let components_four = gray_image!(type: u32,
///     1, 0, 2, 2;
///     0, 3, 4, 0;
///     0, 0, 0, 0;
///     0, 0, 0, 5);
///
/// assert_pixels_eq!(
///     connected_components(&image, Connectivity::Four, background_color),
///     components_four);
///
/// // If this behaviour is not what you want then you can first
/// // threshold the input image.
/// use imageproc::contrast::threshold;
///
/// // Pixels equal to the threshold are treated as background.
/// let thresholded = threshold(&image, 0);
///
/// let thresholded_components_four = gray_image!(type: u32,
///     1, 0, 2, 2;
///     0, 2, 2, 0;
///     0, 0, 0, 0;
///     0, 0, 0, 3);
///
/// assert_pixels_eq!(
///     connected_components(&thresholded, Connectivity::Four, background_color),
///     thresholded_components_four);
/// # }
/// ```
pub fn connected_components(
    image: &I,
    conn: Connectivity,
    background: I::Pixel,
) -> Image<Luma<u32>>
where
    I: GenericImage,
    I::Pixel: Eq,
{
    let (width, height) = image.dimensions();
    let mut out = ImageBuffer::new(width, height);

    // TODO: add macro to abandon early if either dimension is zero
    if width == 0 || height == 0 {
        return out;
    }

    let image_size = (width * height) as usize;
    let mut forest = DisjointSetForest::new(image_size);
    let mut adj_labels = [0u32; 4];
    let mut next_label = 1;

    for y in 0..height {
        for x in 0..width {
            let current = unsafe { image.unsafe_get_pixel(x, y) };
            if current == background {
                continue;
            }

            let mut num_adj = 0;

            if x > 0 {
                // West
                let pixel = unsafe { image.unsafe_get_pixel(x - 1, y) };
                if pixel == current {
                    let label = unsafe { out.unsafe_get_pixel(x - 1, y)[0] };
                    adj_labels[num_adj] = label;
                    num_adj += 1;
                }
            }

            if y > 0 {
                // North
                let pixel = unsafe { image.unsafe_get_pixel(x, y - 1) };
                if pixel == current {
                    let label = unsafe { out.unsafe_get_pixel(x, y - 1)[0] };
                    adj_labels[num_adj] = label;
                    num_adj += 1;
                }

                if conn == Connectivity::Eight {
                    if x > 0 {
                        // North West
                        let pixel = unsafe { image.unsafe_get_pixel(x - 1, y - 1) };
                        if pixel == current {
                            let label = unsafe { out.unsafe_get_pixel(x - 1, y - 1)[0] };
                            adj_labels[num_adj] = label;
                            num_adj += 1;
                        }
                    }
                    if x < width - 1 {
                        // North East
                        let pixel = unsafe { image.unsafe_get_pixel(x + 1, y - 1) };
                        if pixel == current {
                            let label = unsafe { out.unsafe_get_pixel(x + 1, y - 1)[0] };
                            adj_labels[num_adj] = label;
                            num_adj += 1;
                        }
                    }
                }
            }

            if num_adj == 0 {
                unsafe {
                    out.unsafe_put_pixel(x, y, Luma([next_label]));
                }
                next_label += 1;
            } else {
                let mut min_label = u32::max_value();
                for n in 0..num_adj {
                    min_label = cmp::min(min_label, adj_labels[n]);
                }
                unsafe {
                    out.unsafe_put_pixel(x, y, Luma([min_label]));
                }
                for n in 0..num_adj {
                    forest.union(min_label as usize, adj_labels[n] as usize);
                }
            }
        }
    }

    // Make components start at 1
    let mut output_labels = vec![0u32; image_size];
    let mut count = 1;

    unsafe {
        for y in 0..height {
            for x in 0..width {
                let label = {
                    if image.unsafe_get_pixel(x, y) == background {
                        continue;
                    }
                    out.unsafe_get_pixel(x, y)[0]
                };
                let root = forest.root(label as usize);
                let mut output_label = *output_labels.get_unchecked(root);
                if output_label < 1 {
                    output_label = count;
                    count += 1;
                }
                *output_labels.get_unchecked_mut(root) = output_label;
                out.unsafe_put_pixel(x, y, Luma([output_label]));
            }
        }
    }

    out
}

#[cfg(test)]
mod test {
    use super::connected_components;
    use super::Connectivity::{Four, Eight};
    use definitions::{HasBlack, HasWhite};
    use image::{GrayImage, ImageBuffer, Luma};
    use test;

    #[test]
    fn test_connected_components_eight_white_background() {
        let image = gray_image!(
              1, 255,   2,   1;
            255,   1,   1, 255;
            255, 255, 255, 255;
            255, 255, 255,   1);

        let expected = gray_image!(type: u32,
            1, 0, 2, 1;
            0, 1, 1, 0;
            0, 0, 0, 0;
            0, 0, 0, 3);

        let labelled = connected_components(&image, Eight, Luma::white());
        assert_pixels_eq!(labelled, expected);
    }

    // One huge component with eight-way connectivity, loads of
    // isolated components with four-way conectivity.
    fn chessboard(width: u32, height: u32) -> GrayImage {
        ImageBuffer::from_fn(width, height, |x, y| if (x + y) % 2 == 0 {
            return Luma([255u8]);
        } else {
            return Luma([0u8]);
        })
    }

    #[test]
    fn test_connected_components_eight_chessboard() {
        let image = chessboard(30, 30);
        let components = connected_components(&image, Eight, Luma::black());
        let max_component = components.pixels().map(|p| p[0]).max();
        assert_eq!(max_component, Some(1u32));
    }

    #[test]
    fn test_connected_components_four_chessboard() {
        let image = chessboard(30, 30);
        let components = connected_components(&image, Four, Luma::black());
        let max_component = components.pixels().map(|p| p[0]).max();
        assert_eq!(max_component, Some(450u32));
    }

    #[bench]
    fn bench_connected_components_eight_chessboard(b: &mut test::Bencher) {
        let image = chessboard(300, 300);
        b.iter(|| {
            let components = connected_components(&image, Eight, Luma::black());
            test::black_box(components);
        });
    }

    #[bench]
    fn bench_connected_components_four_chessboard(b: &mut test::Bencher) {
        let image = chessboard(300, 300);
        b.iter(|| {
            let components = connected_components(&image, Four, Luma::black());
            test::black_box(components);
        });
    }
}
<commit_msg>Document limitation of connected_components and panic early (#289)<commit_after>//! Functions for finding and labelling connected components of an image.

use image::{GenericImage, GenericImageView, ImageBuffer, Luma};

use definitions::Image;
use union_find::DisjointSetForest;
use std::cmp;

/// Determines which neighbors of a pixel we consider
/// to be connected to it.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Connectivity {
    /// A pixel is connected to its N, S, E and W neighbors.
    Four,
    /// A pixel is connected to all of its neighbors.
    Eight,
}

/// Returns an image of the same size as the input, where each pixel
/// is labelled by the connected foreground component it belongs to,
/// or 0 if it's in the background. Input pixels are treated as belonging
/// to the background if and only if they are equal to the provided background pixel.
///
/// # Panics
/// Panics if the image contains 232 or more pixels. If this limitation causes you
/// problems then open an issue and we can rewrite this function to support larger images.
///
/// # Examples
///
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use image::Luma;
/// use imageproc::region_labelling::{connected_components, Connectivity};
///
/// let background_color = Luma([0u8]);
///
/// let image = gray_image!(
///     1, 0, 1, 1;
///     0, 1, 1, 0;
///     0, 0, 0, 0;
///     0, 0, 0, 1);
///
/// // With four-way connectivity the foreground regions which
/// // are only connected across diagonals belong to different
/// // connected components.
/// let components_four = gray_image!(type: u32,
///     1, 0, 2, 2;
///     0, 2, 2, 0;
///     0, 0, 0, 0;
///     0, 0, 0, 3);
///
/// assert_pixels_eq!(
///     connected_components(&image, Connectivity::Four, background_color),
///     components_four);
///
/// // With eight-way connectivity all foreground pixels in the top two rows
/// // belong to the same connected component.
/// let components_eight = gray_image!(type: u32,
///     1, 0, 1, 1;
///     0, 1, 1, 0;
///     0, 0, 0, 0;
///     0, 0, 0, 2);
///
/// assert_pixels_eq!(
///     connected_components(&image, Connectivity::Eight, background_color),
///     components_eight);
/// # }
/// ```
///
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// // This example is like the first, except that not all of the input foreground
/// // pixels are the same color. Pixels of different color are never counted
/// // as belonging to the same connected component.
///
/// use image::Luma;
/// use imageproc::region_labelling::{connected_components, Connectivity};
///
/// let background_color = Luma([0u8]);
///
/// let image = gray_image!(
///     1, 0, 1, 1;
///     0, 1, 2, 0;
///     0, 0, 0, 0;
///     0, 0, 0, 1);
///
/// let components_four = gray_image!(type: u32,
///     1, 0, 2, 2;
///     0, 3, 4, 0;
///     0, 0, 0, 0;
///     0, 0, 0, 5);
///
/// assert_pixels_eq!(
///     connected_components(&image, Connectivity::Four, background_color),
///     components_four);
///
/// // If this behaviour is not what you want then you can first
/// // threshold the input image.
/// use imageproc::contrast::threshold;
///
/// // Pixels equal to the threshold are treated as background.
/// let thresholded = threshold(&image, 0);
///
/// let thresholded_components_four = gray_image!(type: u32,
///     1, 0, 2, 2;
///     0, 2, 2, 0;
///     0, 0, 0, 0;
///     0, 0, 0, 3);
///
/// assert_pixels_eq!(
///     connected_components(&thresholded, Connectivity::Four, background_color),
///     thresholded_components_four);
/// # }
/// ```
pub fn connected_components(
    image: &I,
    conn: Connectivity,
    background: I::Pixel,
) -> Image<Luma<u32>>
where
    I: GenericImage,
    I::Pixel: Eq,
{
    let (width, height) = image.dimensions();
    let image_size = width as usize * height as usize;
    if image_size >= 2usize.pow(32) {
        panic!("Images with 2^32 or more pixels are not supported");
    }

    let mut out = ImageBuffer::new(width, height);

    // TODO: add macro to abandon early if either dimension is zero
    if width == 0 || height == 0 {
        return out;
    }

    let mut forest = DisjointSetForest::new(image_size);
    let mut adj_labels = [0u32; 4];
    let mut next_label = 1;

    for y in 0..height {
        for x in 0..width {
            let current = unsafe { image.unsafe_get_pixel(x, y) };
            if current == background {
                continue;
            }

            let mut num_adj = 0;

            if x > 0 {
                // West
                let pixel = unsafe { image.unsafe_get_pixel(x - 1, y) };
                if pixel == current {
                    let label = unsafe { out.unsafe_get_pixel(x - 1, y)[0] };
                    adj_labels[num_adj] = label;
                    num_adj += 1;
                }
            }

            if y > 0 {
                // North
                let pixel = unsafe { image.unsafe_get_pixel(x, y - 1) };
                if pixel == current {
                    let label = unsafe { out.unsafe_get_pixel(x, y - 1)[0] };
                    adj_labels[num_adj] = label;
                    num_adj += 1;
                }

                if conn == Connectivity::Eight {
                    if x > 0 {
                        // North West
                        let pixel = unsafe { image.unsafe_get_pixel(x - 1, y - 1) };
                        if pixel == current {
                            let label = unsafe { out.unsafe_get_pixel(x - 1, y - 1)[0] };
                            adj_labels[num_adj] = label;
                            num_adj += 1;
                        }
                    }
                    if x < width - 1 {
                        // North East
                        let pixel = unsafe { image.unsafe_get_pixel(x + 1, y - 1) };
                        if pixel == current {
                            let label = unsafe { out.unsafe_get_pixel(x + 1, y - 1)[0] };
                            adj_labels[num_adj] = label;
                            num_adj += 1;
                        }
                    }
                }
            }

            if num_adj == 0 {
                unsafe {
                    out.unsafe_put_pixel(x, y, Luma([next_label]));
                }
                next_label += 1;
            } else {
                let mut min_label = u32::max_value();
                for n in 0..num_adj {
                    min_label = cmp::min(min_label, adj_labels[n]);
                }
                unsafe {
                    out.unsafe_put_pixel(x, y, Luma([min_label]));
                }
                for n in 0..num_adj {
                    forest.union(min_label as usize, adj_labels[n] as usize);
                }
            }
        }
    }

    // Make components start at 1
    let mut output_labels = vec![0u32; image_size];
    let mut count = 1;

    unsafe {
        for y in 0..height {
            for x in 0..width {
                let label = {
                    if image.unsafe_get_pixel(x, y) == background {
                        continue;
                    }
                    out.unsafe_get_pixel(x, y)[0]
                };
                let root = forest.root(label as usize);
                let mut output_label = *output_labels.get_unchecked(root);
                if output_label < 1 {
                    output_label = count;
                    count += 1;
                }
                *output_labels.get_unchecked_mut(root) = output_label;
                out.unsafe_put_pixel(x, y, Luma([output_label]));
            }
        }
    }

    out
}

#[cfg(test)]
mod test {
    use super::connected_components;
    use super::Connectivity::{Four, Eight};
    use definitions::{HasBlack, HasWhite};
    use image::{GrayImage, ImageBuffer, Luma};
    use test;

    #[test]
    fn test_connected_components_eight_white_background() {
        let image = gray_image!(
              1, 255,   2,   1;
            255,   1,   1, 255;
            255, 255, 255, 255;
            255, 255, 255,   1);

        let expected = gray_image!(type: u32,
            1, 0, 2, 1;
            0, 1, 1, 0;
            0, 0, 0, 0;
            0, 0, 0, 3);

        let labelled = connected_components(&image, Eight, Luma::white());
        assert_pixels_eq!(labelled, expected);
    }

    // One huge component with eight-way connectivity, loads of
    // isolated components with four-way conectivity.
    fn chessboard(width: u32, height: u32) -> GrayImage {
        ImageBuffer::from_fn(width, height, |x, y| if (x + y) % 2 == 0 {
            return Luma([255u8]);
        } else {
            return Luma([0u8]);
        })
    }

    #[test]
    fn test_connected_components_eight_chessboard() {
        let image = chessboard(30, 30);
        let components = connected_components(&image, Eight, Luma::black());
        let max_component = components.pixels().map(|p| p[0]).max();
        assert_eq!(max_component, Some(1u32));
    }

    #[test]
    fn test_connected_components_four_chessboard() {
        let image = chessboard(30, 30);
        let components = connected_components(&image, Four, Luma::black());
        let max_component = components.pixels().map(|p| p[0]).max();
        assert_eq!(max_component, Some(450u32));
    }

    #[bench]
    fn bench_connected_components_eight_chessboard(b: &mut test::Bencher) {
        let image = chessboard(300, 300);
        b.iter(|| {
            let components = connected_components(&image, Eight, Luma::black());
            test::black_box(components);
        });
    }

    #[bench]
    fn bench_connected_components_four_chessboard(b: &mut test::Bencher) {
        let image = chessboard(300, 300);
        b.iter(|| {
            let components = connected_components(&image, Four, Luma::black());
            test::black_box(components);
        });
    }
}
<|endoftext|>