<commit_before>extern crate rand;

pub mod mep;
pub use mep::*;

///SISO is an algorithm that takes a static amount of inputs and produces a static number of outputs.
pub trait SISO<'a, In, Out> {
    ///The iterator type returned from compute. Its lifetime is tied to self.
    type Iter: Iterator<Item=Out> + 'a;
    ///Compute is provided an input slice that must be the correct number of inputs and produces an
    ///iterator that provides the static number of outputs.
    fn compute(&'a self, inputs: &'a [In]) -> Self::Iter;
}

///SIVO is an algorithm that takes a static amount of inputs and produces a variable number of outputs.
pub trait SIVO<'a, In, Out> {
    ///The iterator type returned from compute. Its lifetime is tied to self.
    type Iter: Iterator<Item=Out> + 'a;
    ///Compute is provided an input slice that must be the correct number of inputs along with the number of outputs.
    ///It returns an iterator that provides the required number of outputs.
    fn compute(&'a self, inputs: &'a [In], n_outputs: usize) -> Self::Iter;
}

///VISO is an algorithm that takes a variable amount of inputs and produces a static number of outputs.
pub trait VISO<'a, In, Out> {
    ///The iterator type returned from compute. Its lifetime is tied to self.
    type Iter: Iterator<Item=Out> + 'a;
    ///Compute is provided an input slice that can be any number of inputs and produces an
    ///iterator that provides the static number of outputs.
    fn compute(&'a self, inputs: &'a [In]) -> Self::Iter;
}

///VIVO is an algorithm that takes a variable amount of inputs and produces a variable number of outputs.
pub trait VIVO<'a, In, Out> {
    ///The iterator type returned from compute. Its lifetime is tied to self.
    type Iter: Iterator<Item=Out> + 'a;
    ///Compute is provided an input slice that can be any number of inputs along with the number of outputs.
    ///It returns an iterator that provides the required number of outputs.
    fn compute(&'a self, inputs: &'a [In], n_outputs: usize) -> Self::Iter;
}

///A learning algorithm is one that can be trained and performs computations.
pub trait Learning<R, In, Out>
    where R: rand::Rng
{
    ///Train requires inputs and outputs required by the system and an Rng to introduce randomness.
    ///Level should scale linearly with the amount of time spent training and level 1 should represent the smallest
    ///amount of training possible.
    fn train(&mut self, level: u32, inputs: &[In], outputs: &[Out], rng: &mut R);
}

///Genetic is a trait that allows genetic manipulation. Genetic algorithms require duplication, which is why
///there is a requirement for Clone. It is parameterized with an Rng (R) type so that the algorithms can extract random
///data when mating so that mating can happen randomly. In and Out are parameters specifying the inputs and outputs of
///the learning algorithm component of the genetic algorithm.
///
///Note: This API is highly likely to change before version 1.0.
pub trait Genetic<R> : Clone
    where R: rand::Rng
{
    ///The mate function takes a tuple of two parent references and an Rng, then returns a new child.
    fn mate(parents: (&Self, &Self), rng: &mut R) -> Self;
    ///The mutate function performs a unit mutation. A single, several, or no actual mutations may occour.
    fn mutate(&mut self, rng: &mut R);
}
<commit_msg>removed trait bounds from public traits<commit_after>extern crate rand;

pub mod mep;
pub use mep::*;

///SISO is an algorithm that takes a static amount of inputs and produces a static number of outputs.
pub trait SISO<'a, In, Out> {
    ///The iterator type returned from compute. Its lifetime is tied to self.
    type Iter: Iterator<Item=Out> + 'a;
    ///Compute is provided an input slice that must be the correct number of inputs and produces an
    ///iterator that provides the static number of outputs.
    fn compute(&'a self, inputs: &'a [In]) -> Self::Iter;
}

///SIVO is an algorithm that takes a static amount of inputs and produces a variable number of outputs.
pub trait SIVO<'a, In, Out> {
    ///The iterator type returned from compute. Its lifetime is tied to self.
    type Iter: Iterator<Item=Out> + 'a;
    ///Compute is provided an input slice that must be the correct number of inputs along with the number of outputs.
    ///It returns an iterator that provides the required number of outputs.
    fn compute(&'a self, inputs: &'a [In], n_outputs: usize) -> Self::Iter;
}

///VISO is an algorithm that takes a variable amount of inputs and produces a static number of outputs.
pub trait VISO<'a, In, Out> {
    ///The iterator type returned from compute. Its lifetime is tied to self.
    type Iter: Iterator<Item=Out> + 'a;
    ///Compute is provided an input slice that can be any number of inputs and produces an
    ///iterator that provides the static number of outputs.
    fn compute(&'a self, inputs: &'a [In]) -> Self::Iter;
}

///VIVO is an algorithm that takes a variable amount of inputs and produces a variable number of outputs.
pub trait VIVO<'a, In, Out> {
    ///The iterator type returned from compute. Its lifetime is tied to self.
    type Iter: Iterator<Item=Out> + 'a;
    ///Compute is provided an input slice that can be any number of inputs along with the number of outputs.
    ///It returns an iterator that provides the required number of outputs.
    fn compute(&'a self, inputs: &'a [In], n_outputs: usize) -> Self::Iter;
}

///A learning algorithm is one that can be trained and performs computations.
pub trait Learning<R, In, Out> {
    ///Train requires inputs and outputs required by the system and an Rng to introduce randomness.
    ///Level should scale linearly with the amount of time spent training and level 1 should represent the smallest
    ///amount of training possible.
    fn train(&mut self, level: u32, inputs: &[In], outputs: &[Out], rng: &mut R);
}

///Genetic is a trait that allows genetic manipulation. Genetic algorithms require duplication, which is why
///there is a requirement for Clone. It is parameterized with an Rng (R) type so that the algorithms can extract random
///data when mating so that mating can happen randomly. In and Out are parameters specifying the inputs and outputs of
///the learning algorithm component of the genetic algorithm.
///
///Note: This API is highly likely to change before version 1.0.
pub trait Genetic<R> : Clone {
    ///The mate function takes a tuple of two parent references and an Rng, then returns a new child.
    fn mate(parents: (&Self, &Self), rng: &mut R) -> Self;
    ///The mutate function performs a unit mutation. A single, several, or no actual mutations may occour.
    fn mutate(&mut self, rng: &mut R);
}
<|endoftext|>


<commit_before>
use std::vec;
use std::collections::HashMap;
use std::collections::hash_set::HashSet;

extern crate ocl;
use ocl::{ProQue, Buffer};

static KERNEL_SOURCE: &'static str = include_str!("kernel_source.cl");

type Dimension = (usize, usize);
type NodeId = usize;

#[derive(Hash, Eq, PartialEq, Debug)]
enum Operation {
	Input,
	MatrixMul(NodeId, NodeId),
	Sigmoid(NodeId),
}

struct Node {
	id : NodeId,
	input_nodes : Vec<NodeId>,
	input_shape : Option<Dimension>,
	output_shape : Option<Dimension>,
	operation : Operation,
	buffer : Buffer<f32>,
}

struct Graph {
	proque : ProQue,
	nodes : Vec<Node>,
}

impl Graph {
	fn new() -> Graph {
		Graph {
			proque : ProQue::builder().src(KERNEL_SOURCE).dims([3]).build().unwrap(),
			nodes : vec![],
		}
	}

	fn get_output(&self, node_id : NodeId, input_map : HashMap<NodeId, Vec<f32>>) -> Vec<f32> {
		//(node.operation)(&self, input_map)
		vec![]
	}

	fn new_input(&mut self, shape : Dimension) -> NodeId {
		let mut n = Node {
			id : 0,
			input_shape : Some(shape),
			output_shape : Some(shape),
			input_nodes : vec![],
			operation : Operation::Input,
			buffer : self.proque.create_buffer::<f32>().unwrap()
		};
		self.nodes.push(n);
		let id = self.nodes.len()-1;
		n.id = id;
		id
	}
}

#[cfg(test)]
mod tests {
	use super::{Graph, Dimension, Node, NodeId};
	use std::collections::HashMap;

	#[test]
	fn test_identity() {
		let mut input = HashMap::new();
		let mut g = Graph::new();
		let n : NodeId = g.new_input((10, 11));
		input.insert(n, vec![0.0, 1.0, 2.0]);
		g.get_output(n, input);
	}

    #[test]
    fn integration_full_test() {
		let g = Graph::new();
    }
}
<commit_msg>Remove the OpenCL pieces.  Implement matrix multiplication.  Add unary and binary matrix operators.<commit_after>
use std::f32;
use std::vec;
use std::collections::HashMap;
use std::collections::hash_set::HashSet;

extern crate ocl;
use ocl::{ProQue, Buffer};

static KERNEL_SOURCE: &'static str = include_str!("kernel_source.cl");

type Dimension = (usize, usize);
type NodeId = usize;

//		ActivationFunction::Sigmoid => 1.0f32/(1.0 + (-value).exp()),

#[derive(Hash, Eq, PartialEq, Debug, Copy, Clone)]
enum Operation<F> {
	Input,
	MatrixMultiply(NodeId, NodeId),
	MatrixBinaryOp(NodeId, NodeId, F),
	MatrixUnaryOp(NodeId, F),
//	Transpose(NodeId),
}

struct Node<F> {
	id : NodeId,
	shape : Dimension,
	operation : Operation<F>,
	buffer : Vec<f32>,
}

impl<F> Node<F> {
	fn get_value(&self, x : usize, y : usize) -> f32 {
		self.buffer[x + y*self.shape.1]
	}

	fn set_value(&mut self, x : usize, y : usize, value : f32) {
		self.buffer[x + y*self.shape.1] = value;
	}

	fn get_rows(&self) -> usize {
		self.shape.0
	}

	fn get_columns(&self) -> usize {
		self.shape.1
	}

	fn get_width(&self) -> usize {
		self.shape.1
	}

	fn get_height(&self) -> usize {
		self.shape.0
	}
}

struct Graph<F> {
//	proque : ProQue,
	nodes : Vec<Node<F>>,
}

impl<F> Graph<F> where F: Fn(f32, f32)->f32 {
	fn new() -> Graph<F> {
		Graph {
//			proque : ProQue::builder().src(KERNEL_SOURCE).dims([3]).build().unwrap(),
			nodes : vec![],
		}
	}

	// Graph methods
	fn get_output(&mut self, node_id : NodeId, input_map : &HashMap<NodeId, Vec<f32>>) -> Vec<f32> {
		//(node.operation)(&self, input_map)
		match self.nodes[node_id].operation {
			Operation::Input => input_map.get(&node_id).unwrap().clone(),
			Operation::MatrixMultiply(n1, n2) => {
				// Verify shapes
				let a_width = self.nodes[n1].shape.1; // Columns (j)
				let a_height = self.nodes[n1].shape.0; // Rows (i)
				let b_width = self.nodes[n2].shape.1; // Columns (k)
				let b_height = self.nodes[n2].shape.0; // Rows (j)
				let c_width = b_width;
				let c_height = a_height;
				assert_eq!(a_width, b_height);
				assert_eq!(a_height*b_width, self.nodes[node_id].buffer.len());

				// Set up the buffer for this node.
				let a : Vec<f32> = self.get_output(n1, &input_map);
				let b : Vec<f32> = self.get_output(n2, &input_map);

				// Multiply
				for i in 0..a_height { // Column [Iterating over row]
					for k in 0..b_width { // Row/Width [Iterating over column]
						let mut accumulator = 0.0;
						for j in 0..a_width { // Column
							accumulator += a[j + i*a_width]*b[k + j*b_width];
						}
						self.nodes[node_id].buffer[k + i*c_width] = accumulator;
					}
				}

				self.nodes[node_id].buffer.clone()
			},
			Operation::MatrixBinaryOp(n1, n2, f) => {
				let a : Vec<f32> = self.get_output(n1, &input_map);
				let b : Vec<f32> = self.get_output(n2, &input_map);

				let vec_len = self.nodes[node_id].buffer.len();

				for i in 0..vec_len {
					self.nodes[node_id].buffer[i] = f(a[i], b[i]);
				}

				self.nodes[node_id].buffer.clone()
			},
			Operation::MatrixUnaryOp(n1, f) => {
				let a : Vec<f32> = self.get_output(n1, &input_map);
				let vec_len = self.nodes[node_id].buffer.len();

				for i in 0..vec_len {
					self.nodes[node_id].buffer[i] = f(a[i], i as f32);
				}

				self.nodes[node_id].buffer.clone()
			}
		}
	}

	// Node creation
	fn new_input(&mut self, shape : Dimension) -> NodeId {
		let mut n = Node {
			id : 0,
			shape : shape,
			operation : Operation::Input,
			buffer : vec![0.0; shape.0*shape.1], //self.proque.create_buffer::<f32>().unwrap()
		};
		self.nodes.push(n);
		let id = self.nodes.len()-1;
		n.id = id;
		id
	}

	fn new_matmul(&mut self, node_a_id : NodeId, node_b_id : NodeId) -> NodeId {
		let mut n = Node {
			id : 0,
			shape : (self.nodes[node_a_id].shape.0, self.nodes[node_b_id].shape.1),
			operation : Operation::MatrixMultiply(node_a_id, node_b_id),
			buffer : vec![0.0; self.nodes[node_a_id].shape.0*self.nodes[node_b_id].shape.1],
		};
		self.nodes.push(n);
		let id = self.nodes.len()-1;
		n.id = id;
		id
	}
}

#[cfg(test)]
mod tests {
	use super::{Graph, Dimension, Node, NodeId};
	use std::collections::HashMap;

	#[test]
	fn test_identity() {
		// Build graph
		let mut input = HashMap::new();
		let mut g = Graph::new();
		let m : NodeId = g.new_input((3, 3));
		let n : NodeId = g.new_input((1, 3));
		let o = g.new_matmul(n, m);
		let j : NodeId = g.new_input((3, 5));
		let k = g.new_matmul(m, j);

		// Shape check
		assert_eq!(g.nodes[m].shape, (3, 3));
		assert_eq!(g.nodes[n].shape, (1, 3));
		assert_eq!(g.nodes[o].shape, (1, 3));

		// Configure data
		input.insert(m, vec![
			1.0, 0.0, 0.0,
			0.0, 1.0, 0.0,
			0.0, 0.0, 1.0
		]);
		input.insert(n, vec![
			0.0, 1.0, 2.0
		]);
		input.insert(j, vec![
			1.0, 2.0, 3.0,
			4.0, 5.0, 6.0,
			7.0, 8.0, 9.0,
			10.0, 11.0, 12.0,
			13.0, 14.0, 15.0
		]);

		// Verify outputs
		let res = g.get_output(o, &input);
		assert_eq!(res[0], 0.0);
		assert_eq!(res[1], 1.0);
		assert_eq!(res[2], 2.0);
		let res2 = g.get_output(k, &input);
		for i in 0..15 {
			assert_eq!(res2[i], (i as f32+1.0));
		}
	}

    #[test]
    fn integration_full_test() {
		let g = Graph::new();
    }
}
<|endoftext|>


<commit_before>
extern crate rand;

use rand::Rng;

/// Return a random sample of a known maximum size from an iterator of unknown length.
///
/// Implements Jeffrey Vitter's Algorithm R (see https://en.wikipedia.org/wiki/Reservoir_sampling)
///
/// # Examples
///
/// ```
/// # extern crate rand;
/// # extern crate reservoir;
/// # use rand::thread_rng;
/// # use reservoir::sample;
/// # fn main() {
/// let iter = 0..10;
///
/// let samples = sample(&mut thread_rng(), 4, iter);
///
/// assert_eq!(4, samples.len());
/// assert!(samples.iter().all(|e| *e >= 0 && *e < 10));
/// # }
/// ```
///
/// If the sampled iterator contains fewer items than the sample_size, all items are returned.
///
/// ```
/// # extern crate rand;
/// # extern crate reservoir;
/// # use rand::thread_rng;
/// # use reservoir::sample;
/// # fn main() {
/// let iter = 0..10;
///
/// let samples : Vec<i32> = sample(&mut thread_rng(), 20, iter);
/// let expected_samples : Vec<i32> = (0..10).collect();
///
/// assert_eq!(expected_samples, samples);
/// # }
/// ```

pub fn sample<I, RNG>(rng : &mut RNG, sample_size : usize, iter : I) -> Vec<I::Item>
    where I : Iterator,
          RNG : Rng
{
    let mut samples = Vec::<I::Item>::with_capacity(sample_size);

    let mut count : usize = 0;

    for element in iter {
        count += 1;

        if count <= sample_size {
            samples.push(element);
        } else {
            let index = rng.gen_range(0, count);
            if index < samples.len() {
                samples[index] = element;
            }
        }
    }

    samples
}
<commit_msg>can sample onto the end of an existing vec<commit_after>//! Reservoir sampling: collect a random sample of a known maximum
//! size from an iterator of unknown length.
//!
//! Implements Jeffrey Vitter's Algorithm R (see
//! https://en.wikipedia.org/wiki/Reservoir_sampling)

extern crate rand;

use rand::Rng;

/// Return a random sample of a known maximum size from an iterator of
/// unknown length.
///
/// # Examples
///
/// ```
/// # extern crate rand;
/// # extern crate reservoir;
/// # use rand::thread_rng;
/// # use reservoir::sample;
/// # fn main() {
/// let iter = 0..10;
///
/// let samples = sample(&mut thread_rng(), 4, iter);
///
/// assert_eq!(4, samples.len());
/// assert!(samples.iter().all(|e| *e >= 0 && *e < 10));
/// # }
/// ```
///
/// If the sampled iterator contains fewer items than the sample_size,
/// all items are returned.
///
/// ```
/// # extern crate rand;
/// # extern crate reservoir;
/// # use rand::thread_rng;
/// # use reservoir::sample;
/// # fn main() {
/// let iter = 0..10;
///
/// let samples : Vec<i32> = sample(&mut thread_rng(), 20, iter);
/// let expected_samples : Vec<i32> = (0..10).collect();
///
/// assert_eq!(expected_samples, samples);
/// # }
/// ```

pub fn sample<I, RNG>(rng : &mut RNG, sample_size : usize, iter : I) -> Vec<I::Item>
    where I : Iterator,
          RNG : Rng
{
    let mut samples = Vec::<I::Item>::with_capacity(sample_size);
    sample_into(&mut samples, rng, sample_size, iter);
    samples
}

/// Collect a random sample of a known maximum size from an iterator
/// of unknown length into an existing Vec.
///
/// # Examples
///
/// For example:
///
/// ```
/// # extern crate rand;
/// # extern crate reservoir;
/// # use rand::thread_rng;
/// # use reservoir::sample_into;
/// # fn main() {
/// let iter = 0..10;
/// let mut samples : Vec<i32> = Vec::new();
///
/// sample_into(&mut samples, &mut thread_rng(), 4, iter);
///
/// assert_eq!(4, samples.len());
/// assert!(samples.iter().all(|e| *e >= 0 && *e < 10));
/// # }
/// ```
///
/// Preserves any elements already in the vector:
///
/// ```
/// # extern crate rand;
/// # extern crate reservoir;
/// # use rand::thread_rng;
/// # use reservoir::sample_into;
/// # fn main() {
/// let iter = 0..10;
/// let mut samples : Vec<i32> = vec![99,100];
///
/// sample_into(&mut samples, &mut thread_rng(), 4, iter);
///
/// assert_eq!(6, samples.len());
/// assert_eq!(99, samples[0]);
/// assert_eq!(100, samples[1]);
/// assert!(samples[2..].iter().all(|e| *e >= 0 && *e < 10));
/// # }
/// ```

pub fn sample_into<I, RNG>(samples : &mut Vec<I::Item>, rng : &mut RNG, sample_size : usize, iter : I)
    where I : Iterator,
          RNG : Rng
{
    let original_length = samples.len();
    let mut count : usize = 0;

    for element in iter {
        count += 1;

        if count <= sample_size {
            samples.push(element);
        } else {
            let index = rng.gen_range(0, count);
            if index < sample_size {
                samples[original_length+index] = element;
            }
        }
    }
}

<|endoftext|>


<commit_before>#![feature(plugin_registrar, macro_rules)]
#![crate_type = "dylib"]

extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::codemap::{Span};
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, DummyResult};
use rustc::plugin::Registry;

enum Severity {
    Note,
    Warning,
    Error,
    Fatal,
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    macro_rules! register_specifics {
        ($($name: expr => $sev: ident),*) => {
            {
                $(
                    reg.register_macro($name, {
                        fn f(cx: &mut ExtCtxt, sp: Span,
                             args: &[ast::TokenTree]) -> Box<base::MacResult+'static> {
                            expand_msg($sev, cx, sp, args)
                        }
                        f
                    });
                    )*
            }
        }
    }

    register_specifics! {
        "compile_note" => Note,
        "compile_warning" => Warning,
        "compile_error" => Error,
        "compile_fatal" => Fatal
    }
}

fn expand_msg(sev: Severity,
              cx: &mut ExtCtxt, sp: Span, args: &[ast::TokenTree]) -> Box<base::MacResult+'static> {
    // copied from syntax::ext::concat.
    let es = match base::get_exprs_from_tts(cx, sp, args) {
        Some(e) => e,
        None => return base::DummyResult::expr(sp)
    };
    let mut accumulator = String::new();
    for e in es.into_iter() {
        match e.node {
            ast::ExprLit(ref lit) => {
                match lit.node {
                    ast::LitStr(ref s, _) |
                    ast::LitFloat(ref s, _) |
                    ast::LitFloatUnsuffixed(ref s) => {
                        accumulator.push_str(s.get());
                    }
                    ast::LitChar(c) => {
                        accumulator.push(c);
                    }
                    ast::LitInt(i, ast::UnsignedIntLit(_)) |
                    ast::LitInt(i, ast::SignedIntLit(_, ast::Plus)) |
                    ast::LitInt(i, ast::UnsuffixedIntLit(ast::Plus)) => {
                        accumulator.push_str(format!("{}", i).as_slice());
                    }
                    ast::LitInt(i, ast::SignedIntLit(_, ast::Minus)) |
                    ast::LitInt(i, ast::UnsuffixedIntLit(ast::Minus)) => {
                        accumulator.push_str(format!("-{}", i).as_slice());
                    }
                    ast::LitBool(b) => {
                        accumulator.push_str(format!("{}", b).as_slice());
                    }
                    ast::LitByte(..) |
                    ast::LitBinary(..) => {
                        cx.span_err(e.span, "cannot concatenate a binary literal");
                    }
                }
            }
            _ => {
                cx.span_err(e.span, "expected a literal");
            }
        }
    }

    macro_rules! emit {
        ($($sev: ident => $method: ident),*) => {
            match sev {
                $($sev => cx.$method(sp, accumulator.as_slice()),)*
            }
        }
    }
    emit! {
        Note => span_note,
        Warning => span_warn,
        Error => span_err,
        Fatal => span_fatal
    }

    DummyResult::any(sp)
}
<commit_msg>Update for rustc 336349c93 2014-11-17 20:37:19 +0000<commit_after>#![feature(plugin_registrar, macro_rules)]
#![crate_type = "dylib"]

extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::codemap::{Span};
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, DummyResult};
use rustc::plugin::Registry;

use Severity::{Note, Warning, Error, Fatal};

enum Severity {
    Note,
    Warning,
    Error,
    Fatal,
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    macro_rules! register_specifics {
        ($($name: expr => $sev: ident),*) => {
            {
                $(
                    reg.register_macro($name, {
                        fn f(cx: &mut ExtCtxt, sp: Span,
                             args: &[ast::TokenTree]) -> Box<base::MacResult+'static> {
                            expand_msg($sev, cx, sp, args)
                        }
                        f
                    });
                    )*
            }
        }
    }

    register_specifics! {
        "compile_note" => Note,
        "compile_warning" => Warning,
        "compile_error" => Error,
        "compile_fatal" => Fatal
    }
}

fn expand_msg(sev: Severity,
              cx: &mut ExtCtxt, sp: Span, args: &[ast::TokenTree]) -> Box<base::MacResult+'static> {
    // copied from syntax::ext::concat.
    let es = match base::get_exprs_from_tts(cx, sp, args) {
        Some(e) => e,
        None => return base::DummyResult::expr(sp)
    };
    let mut accumulator = String::new();
    for e in es.into_iter() {
        match e.node {
            ast::ExprLit(ref lit) => {
                match lit.node {
                    ast::LitStr(ref s, _) |
                    ast::LitFloat(ref s, _) |
                    ast::LitFloatUnsuffixed(ref s) => {
                        accumulator.push_str(s.get());
                    }
                    ast::LitChar(c) => {
                        accumulator.push(c);
                    }
                    ast::LitInt(i, ast::UnsignedIntLit(_)) |
                    ast::LitInt(i, ast::SignedIntLit(_, ast::Plus)) |
                    ast::LitInt(i, ast::UnsuffixedIntLit(ast::Plus)) => {
                        accumulator.push_str(format!("{}", i).as_slice());
                    }
                    ast::LitInt(i, ast::SignedIntLit(_, ast::Minus)) |
                    ast::LitInt(i, ast::UnsuffixedIntLit(ast::Minus)) => {
                        accumulator.push_str(format!("-{}", i).as_slice());
                    }
                    ast::LitBool(b) => {
                        accumulator.push_str(format!("{}", b).as_slice());
                    }
                    ast::LitByte(..) |
                    ast::LitBinary(..) => {
                        cx.span_err(e.span, "cannot concatenate a binary literal");
                    }
                }
            }
            _ => {
                cx.span_err(e.span, "expected a literal");
            }
        }
    }

    macro_rules! emit {
        ($($sev: ident => $method: ident),*) => {
            match sev {
                $($sev => cx.$method(sp, accumulator.as_slice()),)*
            }
        }
    }
    emit! {
        Note => span_note,
        Warning => span_warn,
        Error => span_err,
        Fatal => span_fatal
    }

    DummyResult::any(sp)
}
<|endoftext|>


<commit_before>//! This crate is a reimplementation
//! of GNU gettext translation framework in Rust.
//! It allows your Rust programs to parse out GNU MO files
//! containing translations and use them in your user interface.
//!
//! It contains several differences from the official C implementation.
//! Notably, this crate does not in any way depend on a global locale
//! ([2.2](https://www.gnu.org/software/gettext/manual/gettext.html#Setting-the-GUI-Locale))
//! and does not enforce a directory structure
//! for storing your translation catalogs
//! ([11.2.3](https://www.gnu.org/software/gettext/manual/gettext.html#Locating-Catalogs)).
//! Instead, the choice of translation catalog to use is explicitly made by the user.
//!
//! This crate is still in-progress
//! and may not be on par with the original implementation feature-wise.
//!
//! For the exact feature parity see the roadmap in the
//! [README](https://github.com/justinas/gettext#readme).
//!
//! # Example
//!
//! ```ignore
//! extern crate gettext;
//!
//! use std::fs::File;
//! use gettext::Catalog;
//!
//! fn main() {
//!     let f = File::open("french.mo").expect("could not open the catalog");
//!     let catalog = Catalog::parse(f).expect("could not parse the catalog");
//!
//!     // Will print out the French translation
//!     // if it is found in the parsed file
//!     // or "Name" otherwise.
//!     println!("{}", catalog.gettext("Name"));
//! }
//! ```

// https://pascalhertleif.de/artikel/good-practices-for-writing-rust-libraries/
#![deny(
    missing_docs,
    missing_debug_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unused_import_braces
)]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

mod metadata;
mod parser;
mod plurals;

use std::collections::HashMap;
use std::io::Read;
use std::ops::Deref;

use parser::default_resolver;
pub use parser::{Error, ParseOptions};
use plurals::*;

fn key_with_context(context: &str, key: &str) -> String {
    let mut result = context.to_owned();
    result.push('\x04');
    result.push_str(key);
    result
}

/// Catalog represents a set of translation strings
/// parsed out of one MO file.
#[derive(Clone, Debug)]
pub struct Catalog {
    strings: HashMap<String, Message>,
    resolver: Resolver,
}

impl Catalog {
    /// Creates a new, empty gettext catalog.
    fn new() -> Self {
        Catalog {
            strings: HashMap::new(),
            resolver: Resolver::Function(default_resolver),
        }
    }

    /// Parses a gettext catalog from the given binary MO file.
    /// Returns the `Err` variant upon encountering an invalid file format
    /// or invalid byte sequence in strings.
    ///
    /// Calling this method is equivalent to calling
    /// `ParseOptions::new().parse(reader)`.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use gettext::Catalog;
    /// use std::fs::File;
    ///
    /// let file = File::open("french.mo").unwrap();
    /// let catalog = Catalog::parse(file).unwrap();
    /// ```
    pub fn parse<R: Read>(reader: R) -> Result<Self, parser::Error> {
        ParseOptions::new().parse(reader)
    }

    fn insert(&mut self, msg: Message) {
        let key = match msg.context {
            Some(ref ctxt) => key_with_context(ctxt, &msg.id),
            None => msg.id.clone(),
        };
        self.strings.insert(key, msg);
    }

    /// Returns the singular translation of `msg_id` from the given catalog
    /// or `msg_id` itself if a translation does not exist.
    pub fn gettext<'a>(&'a self, msg_id: &'a str) -> &'a str {
        self.strings
            .get(msg_id)
            .and_then(|msg| msg.get_translated(0))
            .unwrap_or(msg_id)
    }

    /// Returns the plural translation of `msg_id` from the given catalog
    /// with the correct plural form for the number `n` of objects.
    /// Returns msg_id if a translation does not exist and `n == 1`,
    /// msg_id_plural otherwise.
    ///
    /// Currently, the only supported plural formula is `n != 1`.
    pub fn ngettext<'a>(&'a self, msg_id: &'a str, msg_id_plural: &'a str, n: u64) -> &'a str {
        let form_no = self.resolver.resolve(n);
        let message = self.strings.get(msg_id);
        match message.and_then(|m| m.get_translated(form_no)) {
            Some(msg) => msg,
            None if n == 1 => msg_id,
            None if n != 1 => msg_id_plural,
            _ => unreachable!(),
        }
    }

    /// Returns the singular translation of `msg_id`
    /// in the context `msg_context`
    /// or `msg_id` itself if a translation does not exist.
    // TODO: DRY gettext/pgettext
    pub fn pgettext<'a>(&'a self, msg_context: &'a str, msg_id: &'a str) -> &'a str {
        let key = key_with_context(msg_context, &msg_id);
        self.strings
            .get(&key)
            .and_then(|msg| msg.get_translated(0))
            .unwrap_or(msg_id)
    }

    /// Returns the plural translation of `msg_id`
    /// in the context `msg_context`
    /// with the correct plural form for the number `n` of objects.
    /// Returns msg_id if a translation does not exist and `n == 1`,
    /// msg_id_plural otherwise.
    ///
    /// Currently, the only supported plural formula is `n != 1`.
    // TODO: DRY ngettext/npgettext
    pub fn npgettext<'a>(
        &'a self,
        msg_context: &'a str,
        msg_id: &'a str,
        msg_id_plural: &'a str,
        n: u64,
    ) -> &'a str {
        let key = key_with_context(msg_context, &msg_id);
        let form_no = self.resolver.resolve(n);
        let message = self.strings.get(&key);
        match message.and_then(|m| m.get_translated(form_no)) {
            Some(msg) => msg,
            None if n == 1 => msg_id,
            None if n != 1 => msg_id_plural,
            _ => unreachable!(),
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
struct Message {
    id: String,
    context: Option<String>,
    translated: Vec<String>,
}

impl Message {
    fn new<T: Into<String>>(id: T, context: Option<T>, translated: Vec<T>) -> Self {
        Message {
            id: id.into(),
            context: context.map(Into::into),
            translated: translated.into_iter().map(Into::into).collect(),
        }
    }

    fn get_translated(&self, form_no: usize) -> Option<&str> {
        self.translated.get(form_no).map(|s| s.deref())
    }
}

#[test]
fn catalog_impls_send_sync() {
    fn check<T: Send + Sync>(_: T) {};
    check(Catalog::new());
}

#[test]
fn catalog_insert() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("thisisid", None, vec![]));
    cat.insert(Message::new("anotherid", Some("context"), vec![]));
    let mut keys = cat.strings.keys().collect::<Vec<_>>();
    keys.sort();
    assert_eq!(keys, &["context\x04anotherid", "thisisid"])
}

#[test]
fn catalog_gettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", None, vec!["Tekstas"]));
    cat.insert(Message::new("Image", Some("context"), vec!["Paveikslelis"]));
    assert_eq!(cat.gettext("Text"), "Tekstas");
    assert_eq!(cat.gettext("Image"), "Image");
}

#[test]
fn catalog_ngettext() {
    let mut cat = Catalog::new();
    {
        // n == 1, no translation
        assert_eq!(cat.ngettext("Text", "Texts", 1), "Text");
        // n != 1, no translation
        assert_eq!(cat.ngettext("Text", "Texts", 0), "Texts");
        assert_eq!(cat.ngettext("Text", "Texts", 2), "Texts");
    }
    {
        cat.insert(Message::new("Text", None, vec!["Tekstas", "Tekstai"]));
        // n == 1, translation available
        assert_eq!(cat.ngettext("Text", "Texts", 1), "Tekstas");
        // n != 1, translation available
        assert_eq!(cat.ngettext("Text", "Texts", 0), "Tekstai");
        assert_eq!(cat.ngettext("Text", "Texts", 2), "Tekstai");
    }
}

#[test]
fn catalog_ngettext_not_enough_forms_in_message() {
    fn resolver(count: u64) -> usize {
        count as usize
    }

    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", None, vec!["Tekstas", "Tekstai"]));
    cat.resolver = Resolver::Function(resolver);
    assert_eq!(cat.ngettext("Text", "Texts", 0), "Tekstas");
    assert_eq!(cat.ngettext("Text", "Texts", 1), "Tekstai");
    assert_eq!(cat.ngettext("Text", "Texts", 2), "Texts");
}

#[test]
fn catalog_npgettext_not_enough_forms_in_message() {
    fn resolver(count: u64) -> usize {
        count as usize
    }

    let mut cat = Catalog::new();
    cat.insert(Message::new(
        "Text",
        Some("ctx"),
        vec!["Tekstas", "Tekstai"],
    ));
    cat.resolver = Resolver::Function(resolver);
    assert_eq!(cat.npgettext("ctx", "Text", "Texts", 0), "Tekstas");
    assert_eq!(cat.npgettext("ctx", "Text", "Texts", 1), "Tekstai");
    assert_eq!(cat.npgettext("ctx", "Text", "Texts", 2), "Texts");
}

#[test]
fn catalog_pgettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", Some("unit test"), vec!["Tekstas"]));
    assert_eq!(cat.pgettext("unit test", "Text"), "Tekstas");
    assert_eq!(cat.pgettext("integration test", "Text"), "Text");
}

#[test]
fn catalog_npgettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new(
        "Text",
        Some("unit test"),
        vec!["Tekstas", "Tekstai"],
    ));

    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 1), "Tekstas");
    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 0), "Tekstai");
    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 2), "Tekstai");

    assert_eq!(
        cat.npgettext("integration test", "Text", "Texts", 1),
        "Text"
    );
    assert_eq!(
        cat.npgettext("integration test", "Text", "Texts", 0),
        "Texts"
    );
    assert_eq!(
        cat.npgettext("integration test", "Text", "Texts", 2),
        "Texts"
    );
}
<commit_msg>Remove outdated information<commit_after>//! This crate is a reimplementation
//! of GNU gettext translation framework in Rust.
//! It allows your Rust programs to parse out GNU MO files
//! containing translations and use them in your user interface.
//!
//! It contains several differences from the official C implementation.
//! Notably, this crate does not in any way depend on a global locale
//! ([2.2](https://www.gnu.org/software/gettext/manual/gettext.html#Setting-the-GUI-Locale))
//! and does not enforce a directory structure
//! for storing your translation catalogs
//! ([11.2.3](https://www.gnu.org/software/gettext/manual/gettext.html#Locating-Catalogs)).
//! Instead, the choice of translation catalog to use is explicitly made by the user.
//!
//! This crate is still in-progress
//! and may not be on par with the original implementation feature-wise.
//!
//! For the exact feature parity see the roadmap in the
//! [README](https://github.com/justinas/gettext#readme).
//!
//! # Example
//!
//! ```ignore
//! extern crate gettext;
//!
//! use std::fs::File;
//! use gettext::Catalog;
//!
//! fn main() {
//!     let f = File::open("french.mo").expect("could not open the catalog");
//!     let catalog = Catalog::parse(f).expect("could not parse the catalog");
//!
//!     // Will print out the French translation
//!     // if it is found in the parsed file
//!     // or "Name" otherwise.
//!     println!("{}", catalog.gettext("Name"));
//! }
//! ```

// https://pascalhertleif.de/artikel/good-practices-for-writing-rust-libraries/
#![deny(
    missing_docs,
    missing_debug_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unused_import_braces
)]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

mod metadata;
mod parser;
mod plurals;

use std::collections::HashMap;
use std::io::Read;
use std::ops::Deref;

use parser::default_resolver;
pub use parser::{Error, ParseOptions};
use plurals::*;

fn key_with_context(context: &str, key: &str) -> String {
    let mut result = context.to_owned();
    result.push('\x04');
    result.push_str(key);
    result
}

/// Catalog represents a set of translation strings
/// parsed out of one MO file.
#[derive(Clone, Debug)]
pub struct Catalog {
    strings: HashMap<String, Message>,
    resolver: Resolver,
}

impl Catalog {
    /// Creates a new, empty gettext catalog.
    fn new() -> Self {
        Catalog {
            strings: HashMap::new(),
            resolver: Resolver::Function(default_resolver),
        }
    }

    /// Parses a gettext catalog from the given binary MO file.
    /// Returns the `Err` variant upon encountering an invalid file format
    /// or invalid byte sequence in strings.
    ///
    /// Calling this method is equivalent to calling
    /// `ParseOptions::new().parse(reader)`.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use gettext::Catalog;
    /// use std::fs::File;
    ///
    /// let file = File::open("french.mo").unwrap();
    /// let catalog = Catalog::parse(file).unwrap();
    /// ```
    pub fn parse<R: Read>(reader: R) -> Result<Self, parser::Error> {
        ParseOptions::new().parse(reader)
    }

    fn insert(&mut self, msg: Message) {
        let key = match msg.context {
            Some(ref ctxt) => key_with_context(ctxt, &msg.id),
            None => msg.id.clone(),
        };
        self.strings.insert(key, msg);
    }

    /// Returns the singular translation of `msg_id` from the given catalog
    /// or `msg_id` itself if a translation does not exist.
    pub fn gettext<'a>(&'a self, msg_id: &'a str) -> &'a str {
        self.strings
            .get(msg_id)
            .and_then(|msg| msg.get_translated(0))
            .unwrap_or(msg_id)
    }

    /// Returns the plural translation of `msg_id` from the given catalog
    /// with the correct plural form for the number `n` of objects.
    /// Returns msg_id if a translation does not exist and `n == 1`,
    /// msg_id_plural otherwise.
    pub fn ngettext<'a>(&'a self, msg_id: &'a str, msg_id_plural: &'a str, n: u64) -> &'a str {
        let form_no = self.resolver.resolve(n);
        let message = self.strings.get(msg_id);
        match message.and_then(|m| m.get_translated(form_no)) {
            Some(msg) => msg,
            None if n == 1 => msg_id,
            None if n != 1 => msg_id_plural,
            _ => unreachable!(),
        }
    }

    /// Returns the singular translation of `msg_id`
    /// in the context `msg_context`
    /// or `msg_id` itself if a translation does not exist.
    // TODO: DRY gettext/pgettext
    pub fn pgettext<'a>(&'a self, msg_context: &'a str, msg_id: &'a str) -> &'a str {
        let key = key_with_context(msg_context, &msg_id);
        self.strings
            .get(&key)
            .and_then(|msg| msg.get_translated(0))
            .unwrap_or(msg_id)
    }

    /// Returns the plural translation of `msg_id`
    /// in the context `msg_context`
    /// with the correct plural form for the number `n` of objects.
    /// Returns msg_id if a translation does not exist and `n == 1`,
    /// msg_id_plural otherwise.
    // TODO: DRY ngettext/npgettext
    pub fn npgettext<'a>(
        &'a self,
        msg_context: &'a str,
        msg_id: &'a str,
        msg_id_plural: &'a str,
        n: u64,
    ) -> &'a str {
        let key = key_with_context(msg_context, &msg_id);
        let form_no = self.resolver.resolve(n);
        let message = self.strings.get(&key);
        match message.and_then(|m| m.get_translated(form_no)) {
            Some(msg) => msg,
            None if n == 1 => msg_id,
            None if n != 1 => msg_id_plural,
            _ => unreachable!(),
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
struct Message {
    id: String,
    context: Option<String>,
    translated: Vec<String>,
}

impl Message {
    fn new<T: Into<String>>(id: T, context: Option<T>, translated: Vec<T>) -> Self {
        Message {
            id: id.into(),
            context: context.map(Into::into),
            translated: translated.into_iter().map(Into::into).collect(),
        }
    }

    fn get_translated(&self, form_no: usize) -> Option<&str> {
        self.translated.get(form_no).map(|s| s.deref())
    }
}

#[test]
fn catalog_impls_send_sync() {
    fn check<T: Send + Sync>(_: T) {};
    check(Catalog::new());
}

#[test]
fn catalog_insert() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("thisisid", None, vec![]));
    cat.insert(Message::new("anotherid", Some("context"), vec![]));
    let mut keys = cat.strings.keys().collect::<Vec<_>>();
    keys.sort();
    assert_eq!(keys, &["context\x04anotherid", "thisisid"])
}

#[test]
fn catalog_gettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", None, vec!["Tekstas"]));
    cat.insert(Message::new("Image", Some("context"), vec!["Paveikslelis"]));
    assert_eq!(cat.gettext("Text"), "Tekstas");
    assert_eq!(cat.gettext("Image"), "Image");
}

#[test]
fn catalog_ngettext() {
    let mut cat = Catalog::new();
    {
        // n == 1, no translation
        assert_eq!(cat.ngettext("Text", "Texts", 1), "Text");
        // n != 1, no translation
        assert_eq!(cat.ngettext("Text", "Texts", 0), "Texts");
        assert_eq!(cat.ngettext("Text", "Texts", 2), "Texts");
    }
    {
        cat.insert(Message::new("Text", None, vec!["Tekstas", "Tekstai"]));
        // n == 1, translation available
        assert_eq!(cat.ngettext("Text", "Texts", 1), "Tekstas");
        // n != 1, translation available
        assert_eq!(cat.ngettext("Text", "Texts", 0), "Tekstai");
        assert_eq!(cat.ngettext("Text", "Texts", 2), "Tekstai");
    }
}

#[test]
fn catalog_ngettext_not_enough_forms_in_message() {
    fn resolver(count: u64) -> usize {
        count as usize
    }

    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", None, vec!["Tekstas", "Tekstai"]));
    cat.resolver = Resolver::Function(resolver);
    assert_eq!(cat.ngettext("Text", "Texts", 0), "Tekstas");
    assert_eq!(cat.ngettext("Text", "Texts", 1), "Tekstai");
    assert_eq!(cat.ngettext("Text", "Texts", 2), "Texts");
}

#[test]
fn catalog_npgettext_not_enough_forms_in_message() {
    fn resolver(count: u64) -> usize {
        count as usize
    }

    let mut cat = Catalog::new();
    cat.insert(Message::new(
        "Text",
        Some("ctx"),
        vec!["Tekstas", "Tekstai"],
    ));
    cat.resolver = Resolver::Function(resolver);
    assert_eq!(cat.npgettext("ctx", "Text", "Texts", 0), "Tekstas");
    assert_eq!(cat.npgettext("ctx", "Text", "Texts", 1), "Tekstai");
    assert_eq!(cat.npgettext("ctx", "Text", "Texts", 2), "Texts");
}

#[test]
fn catalog_pgettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", Some("unit test"), vec!["Tekstas"]));
    assert_eq!(cat.pgettext("unit test", "Text"), "Tekstas");
    assert_eq!(cat.pgettext("integration test", "Text"), "Text");
}

#[test]
fn catalog_npgettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new(
        "Text",
        Some("unit test"),
        vec!["Tekstas", "Tekstai"],
    ));

    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 1), "Tekstas");
    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 0), "Tekstai");
    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 2), "Tekstai");

    assert_eq!(
        cat.npgettext("integration test", "Text", "Texts", 1),
        "Text"
    );
    assert_eq!(
        cat.npgettext("integration test", "Text", "Texts", 0),
        "Texts"
    );
    assert_eq!(
        cat.npgettext("integration test", "Text", "Texts", 2),
        "Texts"
    );
}
<|endoftext|>


<commit_before>//! Find discrete returns in full waveform LiDAR data.
//!
//! # Why is this library called `peakbag`?
//!
//! [Peak bagging](https://en.wikipedia.org/wiki/Peak_bagging) is when you try to summit a bunch of
//! mountains, just to say you summited a bunch of mountains. While the practice of peak bagging
//! can correlate with actual appreciation for the out-of-doors and an adventuresome spirit, a peak
//! bagging attitude is neither necessary nor sufficient for a good time outside.
//!
//! Some use "peak bagger" as a derisive term for someone who likes taking a selfie on top of a
//! mountain more than just spending time outside.
//!
//! This library finds peaks in waveforms, so `peakbag` seemed as good of a name as any.

#![deny(box_pointers, fat_ptr_transmutes, missing_copy_implementations, missing_debug_implementations, missing_docs, trivial_casts, unsafe_code, unused_extern_crates, unused_import_braces, unused_qualifications, variant_size_differences)]

#[macro_use]
extern crate log;
extern crate num;

use std::f64;
use std::fmt;

use num::traits::{ToPrimitive, Unsigned};

/// Detects peaks in full waveform data.
///
/// This is a convenience method that wraps calls to `PeakDetector::new` and
/// `PeakDetector::detect_peaks`.
///
/// # Examples
///
/// ```
/// let ref data = [1u32, 2, 3, 4, 3, 2, 1];
/// let peaks = peakbag::detect_peaks(data, 3, 0, 5);
/// assert_eq!(1, peaks.len());
/// assert_eq!(4, peaks[0].amplitude);
/// assert_eq!(3, peaks[0].index);
/// ```
pub fn detect_peaks<T>(data: &[T], width: usize, floor: T, ceiling: T) -> Vec<Peak<T>>
    where T: Copy + fmt::Display + PartialOrd + ToPrimitive + Unsigned
{
    let detector = PeakDetector::new(width, floor, ceiling);
    detector.detect_peaks(data)
}

/// Configurable struct for detecting peaks.
///
/// This structure allow for fine-grained adjustment of the peak detection procedures.
#[derive(Clone, Copy, Debug)]
pub struct PeakDetector<T: Copy> {
    width: usize,
    floor: T,
    ceiling: T,
    saturation: Option<T>,
    max_kurtosis: f64,
    min_height_above_background: f64,
}

impl<T: Copy> PeakDetector<T> {
    /// Creates a new peak detector.
    ///
    /// # Examples
    ///
    /// ```
    /// use peakbag::PeakDetector;
    /// let detector = PeakDetector::new(1, 2, 3);
    /// ```
    pub fn new(width: usize, floor: T, ceiling: T) -> PeakDetector<T> {
        PeakDetector {
            width: width,
            floor: floor,
            ceiling: ceiling,
            saturation: None,
            max_kurtosis: f64::MAX,
            min_height_above_background: f64::MIN,
        }
    }

    /// Sets the saturation level for this peak detector.
    ///
    /// # Examples
    ///
    /// ```
    /// use peakbag::PeakDetector;
    /// let mut detector = PeakDetector::new(1, 2, 3).saturation(3);
    /// ```
    pub fn saturation(mut self, saturation: T) -> PeakDetector<T> {
        self.saturation = Some(saturation);
        self
    }

    /// Sets the minimum allowable height above background for a peak.
    ///
    /// # Examples
    ///
    /// ```
    /// use peakbag::PeakDetector;
    /// let mut detector = PeakDetector::new(1, 2, 3).min_height_above_background(4.0);
    /// ```
    pub fn min_height_above_background(mut self,
                                       min_height_above_background: f64)
                                       -> PeakDetector<T> {
        self.min_height_above_background = min_height_above_background;
        self
    }

    /// Sets the maximum allowable kurtosis for a peak.
    ///
    /// # Examples
    ///
    /// ```
    /// use peakbag::PeakDetector;
    /// let detector = PeakDetector::new(1, 2, 3).max_kurtosis(4.0);
    /// ```
    pub fn max_kurtosis(mut self, max_kurtosis: f64) -> PeakDetector<T> {
        self.max_kurtosis = max_kurtosis;
        self
    }
}

impl<T> PeakDetector<T> where T: Copy + fmt::Display + PartialOrd + ToPrimitive + Unsigned {
    /// Detects peaks in full waveform data.
    ///
    /// # Panics
    ///
    /// Panics if a sample value cannot be converted to an `i64` and `f64`.
    ///
    /// # Examples
    ///
    /// ```
    /// use peakbag::PeakDetector;
    /// let detector = PeakDetector::new(0, 8, 2);
    /// let peaks = detector.detect_peaks(&[1u32, 2, 3, 2, 1]);
    /// ```
    pub fn detect_peaks(&self, data: &[T]) -> Vec<Peak<T>> {
        let mut state = State::Ascending(0);
        let mut peaks = Vec::new();
        for (i, &sample) in data.iter().enumerate() {
            if i == 0 {
                // We assume the first sample has a slope of zero, which means it can start a leading
                // edge.
                state = State::Ascending(1);
                continue;
            }
            let slope = sample.to_i64().unwrap() - data[i - 1].to_i64().unwrap();
            if let Some(s) = self.saturation {
                if sample == s {
                    state = State::Saturated;
                }
            }
            match state {
                State::Ascending(n) => {
                    if slope < 0 {
                        state = State::Ascending(0);
                    } else if n == self.width {
                        state = State::Descending(0, i);
                    } else {
                        state = State::Ascending(n + 1);
                    }
                }
                State::Descending(n, index) => {
                    if slope > 0 {
                        if n == 0 {
                            state = State::Descending(0, i);
                        } else {
                            state = State::Ascending(1);
                        }
                    } else if n + 1 == self.width {
                        let amplitude = data[index];
                        if amplitude > self.floor && amplitude <= self.ceiling {
                            let (mean, rms, kurtosis) = self.peak_stats(&data, index);
                            let height_above_background = self.height_above_background(&data,
                                                                                index);
                            if height_above_background >= self.min_height_above_background &&
                               kurtosis < self.max_kurtosis {
                                peaks.push(Peak {
                                    index: index,
                                    amplitude: amplitude,
                                    mean: mean,
                                    rms: rms,
                                    kurtosis: kurtosis,
                                    height_above_background: height_above_background,
                                });
                            }
                        }
                        state = State::Ascending(0);
                    } else {
                        state = State::Descending(n + 1, index);
                    }
                }
                State::Saturated => {
                    // We know if we're below the floor, we have a negative slope, since we must
                    // have just gone below the floor.
                    if sample <= self.floor {
                        state = State::Ascending(0);
                    }
                }
            };
            debug!("({}) sample={}, slope={}, state={:?}",
                   i,
                   sample,
                   slope,
                   state);
        }
        peaks
    }

    fn peak_stats(&self, data: &[T], index: usize) -> (f64, f64, f64) {
        let mut values = 0u64;
        let mut values2 = 0u64;
        let mut nvalues = 0usize;
        for &sample in data.iter().skip(index - self.width).take(self.width * 2 + 1) {
            let sample = sample.to_u64().unwrap();
            values += sample;
            values2 += sample * sample;
            nvalues += 1;
        }
        let mean = values as f64 / nvalues as f64;
        let rms = (values2 as f64 / nvalues as f64 - (values as f64 / nvalues as f64).powi(2))
                      .sqrt();
        let mut kurtosis = 0f64;
        for &sample in data.iter().skip(index - self.width).take(self.width * 2 + 1) {
            let sample = sample.to_u64().unwrap();
            let temp = (sample as f64 - mean) / rms;
            kurtosis += temp.powi(4);
        }
        kurtosis = kurtosis / nvalues as f64 - 3.0;
        (mean, rms, kurtosis)
    }

    fn height_above_background(&self, data: &[T], index: usize) -> f64 {
        let slope: f64 = (data[index + self.width] - data[index - self.width]).to_f64().unwrap() /
                         (2.0 * self.width as f64);
        let intercept = data[index + self.width].to_f64().unwrap() -
                        slope * (index - self.width) as f64;
        data[index].to_f64().unwrap() - (slope * index as f64 + intercept)
    }
}

#[derive(Debug)]
enum State {
    Ascending(usize),
    Descending(usize, usize),
    Saturated,
}

/// A peak in the waveform data.
#[derive(Clone, Copy, Debug)]
pub struct Peak<T: Copy> {
    /// The raw intensity of the peak.
    pub amplitude: T,
    /// The index of the peak in the sample data.
    pub index: usize,
    /// The mean intensity value of the peak.
    pub mean: f64,
    /// The rms error of the peak from that mean.
    pub rms: f64,
    /// The kurtosis of the peak.
    pub kurtosis: f64,
    /// The height of the peak above a background level, as defined by the first and last points in
    /// the peak.
    pub height_above_background: f64,
}

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

    #[test]
    fn level_peak() {
        let peaks = detect_peaks(&[1u32, 2, 3, 4, 4, 4, 4], 3, 0, 5);
        assert_eq!(1, peaks.len());
        assert_eq!(3, peaks[0].index);
    }

    #[test]
    fn floor() {
        // Must be above floor, below or equal to ceil
        let peaks = detect_peaks(&[1u32, 2, 3, 4, 3, 2, 1], 3, 4, 5);
        assert_eq!(0, peaks.len());
    }

    #[test]
    fn ceiling() {
        // Must be above floor, below or equal to ceil
        let peaks = detect_peaks(&[1u32, 2, 3, 4, 3, 2, 1], 3, 0, 3);
        assert_eq!(0, peaks.len());
    }

    #[test]
    fn saturation() {
        let detector = PeakDetector::new(3, 1, 8).saturation(8);
        let peaks = detector.detect_peaks(&[5u32, 6, 7, 8, 7, 6, 5]);
        assert_eq!(0, peaks.len());
    }

    #[test]
    fn stats() {
        let peaks = detect_peaks(&[1u32, 2, 3, 4, 3, 2, 1], 3, 0, 5);
        let ref peak = peaks[0];
        assert_eq!(2.2857142857142856, peak.mean);
        assert_eq!(1.0301575072754257, peak.rms);
        assert_eq!(-1.143491124260356, peak.kurtosis);
        assert_eq!(3.0, peak.height_above_background);
    }

    #[test]
    fn min_height_above_background() {
        let detector = PeakDetector::new(3, 1, 8).min_height_above_background(4.0);
        let peaks = detector.detect_peaks(&[1u32, 2, 3, 4, 3, 2, 1]);
        assert_eq!(0, peaks.len());
    }

    #[test]
    fn peak_kurtosis() {
        let detector = PeakDetector::new(3, 1, 8).max_kurtosis(-2.0);
        let peaks = detector.detect_peaks(&[1u32, 2, 3, 4, 3, 2, 1]);
        assert_eq!(0, peaks.len());
    }

    #[test]
    fn should_be_one_peak() {
        let ref data = [2u16, 2, 1, 2, 5, 18, 51, 107, 166, 195, 176, 125, 70, 34, 14, 7, 5, 4, 5,
                        4, 3, 1, 0, 0];
        let peaks = detect_peaks(data, 2, 15, 255);
        assert_eq!(1, peaks.len());
    }
}
<commit_msg>Add check for reference peak amplitude<commit_after>//! Find discrete returns in full waveform LiDAR data.
//!
//! # Why is this library called `peakbag`?
//!
//! [Peak bagging](https://en.wikipedia.org/wiki/Peak_bagging) is when you try to summit a bunch of
//! mountains, just to say you summited a bunch of mountains. While the practice of peak bagging
//! can correlate with actual appreciation for the out-of-doors and an adventuresome spirit, a peak
//! bagging attitude is neither necessary nor sufficient for a good time outside.
//!
//! Some use "peak bagger" as a derisive term for someone who likes taking a selfie on top of a
//! mountain more than just spending time outside.
//!
//! This library finds peaks in waveforms, so `peakbag` seemed as good of a name as any.

#![deny(box_pointers, fat_ptr_transmutes, missing_copy_implementations, missing_debug_implementations, missing_docs, trivial_casts, unsafe_code, unused_extern_crates, unused_import_braces, unused_qualifications, variant_size_differences)]

#[macro_use]
extern crate log;
extern crate num;

use std::f64;
use std::fmt;

use num::traits::{ToPrimitive, Unsigned};

/// Detects peaks in full waveform data.
///
/// This is a convenience method that wraps calls to `PeakDetector::new` and
/// `PeakDetector::detect_peaks`.
///
/// # Examples
///
/// ```
/// let ref data = [1u32, 2, 3, 4, 3, 2, 1];
/// let peaks = peakbag::detect_peaks(data, 3, 0, 5);
/// assert_eq!(1, peaks.len());
/// assert_eq!(4, peaks[0].amplitude);
/// assert_eq!(3, peaks[0].index);
/// ```
pub fn detect_peaks<T>(data: &[T], width: usize, floor: T, ceiling: T) -> Vec<Peak<T>>
    where T: Copy + fmt::Display + PartialOrd + ToPrimitive + Unsigned
{
    let detector = PeakDetector::new(width, floor, ceiling);
    detector.detect_peaks(data)
}

/// Configurable struct for detecting peaks.
///
/// This structure allow for fine-grained adjustment of the peak detection procedures.
#[derive(Clone, Copy, Debug)]
pub struct PeakDetector<T: Copy> {
    width: usize,
    floor: T,
    ceiling: T,
    saturation: Option<T>,
    max_kurtosis: f64,
    min_height_above_background: f64,
}

impl<T: Copy> PeakDetector<T> {
    /// Creates a new peak detector.
    ///
    /// # Examples
    ///
    /// ```
    /// use peakbag::PeakDetector;
    /// let detector = PeakDetector::new(1, 2, 3);
    /// ```
    pub fn new(width: usize, floor: T, ceiling: T) -> PeakDetector<T> {
        PeakDetector {
            width: width,
            floor: floor,
            ceiling: ceiling,
            saturation: None,
            max_kurtosis: f64::MAX,
            min_height_above_background: f64::MIN,
        }
    }

    /// Sets the saturation level for this peak detector.
    ///
    /// # Examples
    ///
    /// ```
    /// use peakbag::PeakDetector;
    /// let mut detector = PeakDetector::new(1, 2, 3).saturation(3);
    /// ```
    pub fn saturation(mut self, saturation: T) -> PeakDetector<T> {
        self.saturation = Some(saturation);
        self
    }

    /// Sets the minimum allowable height above background for a peak.
    ///
    /// # Examples
    ///
    /// ```
    /// use peakbag::PeakDetector;
    /// let mut detector = PeakDetector::new(1, 2, 3).min_height_above_background(4.0);
    /// ```
    pub fn min_height_above_background(mut self,
                                       min_height_above_background: f64)
                                       -> PeakDetector<T> {
        self.min_height_above_background = min_height_above_background;
        self
    }

    /// Sets the maximum allowable kurtosis for a peak.
    ///
    /// # Examples
    ///
    /// ```
    /// use peakbag::PeakDetector;
    /// let detector = PeakDetector::new(1, 2, 3).max_kurtosis(4.0);
    /// ```
    pub fn max_kurtosis(mut self, max_kurtosis: f64) -> PeakDetector<T> {
        self.max_kurtosis = max_kurtosis;
        self
    }
}

impl<T> PeakDetector<T> where T: Copy + fmt::Display + PartialOrd + ToPrimitive + Unsigned {
    /// Detects peaks in full waveform data.
    ///
    /// # Panics
    ///
    /// Panics if a sample value cannot be converted to an `i64` and `f64`.
    ///
    /// # Examples
    ///
    /// ```
    /// use peakbag::PeakDetector;
    /// let detector = PeakDetector::new(0, 8, 2);
    /// let peaks = detector.detect_peaks(&[1u32, 2, 3, 2, 1]);
    /// ```
    pub fn detect_peaks(&self, data: &[T]) -> Vec<Peak<T>> {
        let mut state = State::Ascending(0);
        let mut peaks = Vec::new();
        for (i, &sample) in data.iter().enumerate() {
            if i == 0 {
                // We assume the first sample has a slope of zero, which means it can start a leading
                // edge.
                state = State::Ascending(1);
                continue;
            }
            let slope = sample.to_i64().unwrap() - data[i - 1].to_i64().unwrap();
            if let Some(s) = self.saturation {
                if sample == s {
                    state = State::Saturated;
                }
            }
            match state {
                State::Ascending(n) => {
                    if slope < 0 {
                        state = State::Ascending(0);
                    } else if n == self.width {
                        state = State::Descending(0, i);
                    } else {
                        state = State::Ascending(n + 1);
                    }
                }
                State::Descending(n, index) => {
                    if slope > 0 {
                        if n == 0 {
                            state = State::Descending(0, i);
                        } else {
                            state = State::Ascending(1);
                        }
                    } else if n + 1 == self.width {
                        let amplitude = data[index];
                        if amplitude > self.floor && amplitude <= self.ceiling {
                            let (mean, rms, kurtosis) = self.peak_stats(&data, index);
                            let height_above_background = self.height_above_background(&data,
                                                                                index);
                            if height_above_background >= self.min_height_above_background &&
                               kurtosis < self.max_kurtosis {
                                peaks.push(Peak {
                                    index: index,
                                    amplitude: amplitude,
                                    mean: mean,
                                    rms: rms,
                                    kurtosis: kurtosis,
                                    height_above_background: height_above_background,
                                });
                            }
                        }
                        state = State::Ascending(0);
                    } else {
                        state = State::Descending(n + 1, index);
                    }
                }
                State::Saturated => {
                    // We know if we're below the floor, we have a negative slope, since we must
                    // have just gone below the floor.
                    if sample <= self.floor {
                        state = State::Ascending(0);
                    }
                }
            };
            debug!("({}) sample={}, slope={}, state={:?}",
                   i,
                   sample,
                   slope,
                   state);
        }
        peaks
    }

    fn peak_stats(&self, data: &[T], index: usize) -> (f64, f64, f64) {
        let mut values = 0u64;
        let mut values2 = 0u64;
        let mut nvalues = 0usize;
        for &sample in data.iter().skip(index - self.width).take(self.width * 2 + 1) {
            let sample = sample.to_u64().unwrap();
            values += sample;
            values2 += sample * sample;
            nvalues += 1;
        }
        let mean = values as f64 / nvalues as f64;
        let rms = (values2 as f64 / nvalues as f64 - (values as f64 / nvalues as f64).powi(2))
                      .sqrt();
        let mut kurtosis = 0f64;
        for &sample in data.iter().skip(index - self.width).take(self.width * 2 + 1) {
            let sample = sample.to_u64().unwrap();
            let temp = (sample as f64 - mean) / rms;
            kurtosis += temp.powi(4);
        }
        kurtosis = kurtosis / nvalues as f64 - 3.0;
        (mean, rms, kurtosis)
    }

    fn height_above_background(&self, data: &[T], index: usize) -> f64 {
        let slope: f64 = (data[index + self.width] - data[index - self.width]).to_f64().unwrap() /
                         (2.0 * self.width as f64);
        let intercept = data[index + self.width].to_f64().unwrap() -
                        slope * (index - self.width) as f64;
        data[index].to_f64().unwrap() - (slope * index as f64 + intercept)
    }
}

#[derive(Debug)]
enum State {
    Ascending(usize),
    Descending(usize, usize),
    Saturated,
}

/// A peak in the waveform data.
#[derive(Clone, Copy, Debug)]
pub struct Peak<T: Copy> {
    /// The raw intensity of the peak.
    pub amplitude: T,
    /// The index of the peak in the sample data.
    pub index: usize,
    /// The mean intensity value of the peak.
    pub mean: f64,
    /// The rms error of the peak from that mean.
    pub rms: f64,
    /// The kurtosis of the peak.
    pub kurtosis: f64,
    /// The height of the peak above a background level, as defined by the first and last points in
    /// the peak.
    pub height_above_background: f64,
}

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

    #[test]
    fn level_peak() {
        let peaks = detect_peaks(&[1u32, 2, 3, 4, 4, 4, 4], 3, 0, 5);
        assert_eq!(1, peaks.len());
        assert_eq!(3, peaks[0].index);
    }

    #[test]
    fn floor() {
        // Must be above floor, below or equal to ceil
        let peaks = detect_peaks(&[1u32, 2, 3, 4, 3, 2, 1], 3, 4, 5);
        assert_eq!(0, peaks.len());
    }

    #[test]
    fn ceiling() {
        // Must be above floor, below or equal to ceil
        let peaks = detect_peaks(&[1u32, 2, 3, 4, 3, 2, 1], 3, 0, 3);
        assert_eq!(0, peaks.len());
    }

    #[test]
    fn saturation() {
        let detector = PeakDetector::new(3, 1, 8).saturation(8);
        let peaks = detector.detect_peaks(&[5u32, 6, 7, 8, 7, 6, 5]);
        assert_eq!(0, peaks.len());
    }

    #[test]
    fn stats() {
        let peaks = detect_peaks(&[1u32, 2, 3, 4, 3, 2, 1], 3, 0, 5);
        let ref peak = peaks[0];
        assert_eq!(2.2857142857142856, peak.mean);
        assert_eq!(1.0301575072754257, peak.rms);
        assert_eq!(-1.143491124260356, peak.kurtosis);
        assert_eq!(3.0, peak.height_above_background);
    }

    #[test]
    fn min_height_above_background() {
        let detector = PeakDetector::new(3, 1, 8).min_height_above_background(4.0);
        let peaks = detector.detect_peaks(&[1u32, 2, 3, 4, 3, 2, 1]);
        assert_eq!(0, peaks.len());
    }

    #[test]
    fn peak_kurtosis() {
        let detector = PeakDetector::new(3, 1, 8).max_kurtosis(-2.0);
        let peaks = detector.detect_peaks(&[1u32, 2, 3, 4, 3, 2, 1]);
        assert_eq!(0, peaks.len());
    }

    #[test]
    fn should_be_one_peak() {
        let ref data = [2u16, 2, 1, 2, 5, 18, 51, 107, 166, 195, 176, 125, 70, 34, 14, 7, 5, 4, 5,
                        4, 3, 1, 0, 0];
        let peaks = detect_peaks(data, 2, 15, 255);
        assert_eq!(1, peaks.len());
        assert_eq!(195, peaks[0].amplitude);
    }
}
<|endoftext|>


<commit_before>extern crate json;
extern crate tiled;

extern crate cgmath;
#[macro_use]
extern crate gfx;
extern crate specs;
extern crate genmesh;
extern crate gfx_device_gl;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate image;
extern crate rodio;

mod bullet;
mod gfx_app;
mod game;
mod data;
mod critter;
pub mod graphics;
mod terrain;
mod character;
mod shaders;
mod zombie;

pub fn testi(foo: i32) -> i32 {
  foo + 2
}

pub fn main() {
  let mut window = gfx_app::GlutinWindow::new();
  #[allow(unknown_lints)]
  #[allow(never_loop)]
  loop {
    match gfx_app::init::run(&mut window) {
      gfx_app::GameStatus::Quit => break,
    }
  }
}
<commit_msg>Remove placeholder function<commit_after>extern crate json;
extern crate tiled;

extern crate cgmath;
#[macro_use]
extern crate gfx;
extern crate specs;
extern crate genmesh;
extern crate gfx_device_gl;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate image;
extern crate rodio;

mod bullet;
mod gfx_app;
mod game;
mod data;
mod critter;
pub mod graphics;
mod terrain;
mod character;
mod shaders;
mod zombie;

pub fn main() {
  let mut window = gfx_app::GlutinWindow::new();
  #[allow(unknown_lints)]
  #[allow(never_loop)]
  loop {
    match gfx_app::init::run(&mut window) {
      gfx_app::GameStatus::Quit => break,
    }
  }
}
<|endoftext|>


<commit_before>//! Rsure is a set of utilities for capturing information about files, and later verifying it is
//! still true.
//!
//! The easiest way to use Rsure is to build the `rsure` executable contained in this crate.  This
//! program allows you to use most of the functionality of the crate.
//!
//! However, it is also possible to use the crate programmatically.  At the top level of the crate
//! as some utility functions for the most common operations.
//!
//! For example, to scan a directory or do an update use `update`.
//!
//! This example makes use of several of the building blocks necessary to use the store.  First is
//! the store itself.  `parse_store` is able to decode options that are passed to the command line.
//! it is also possible to build a `store::Plain` store directly.
//!
//! Next are the tags for the snapshot.  Generally, this should hold some kind of information about
//! the snapshot itself.  For the `Plain` store, it can be just an empty map.  Other store types
//! may require certain tags to be present.

#![warn(bare_trait_objects)]

use std::{fs::File, path::Path};

pub use crate::{
    errors::{Error, Result},
    hashes::Estimate,
    node::{
        compare_trees, fs, load_from, HashCombiner, HashUpdater, NodeWriter, ReadIterator, Source,
        SureNode,
    },
    progress::{log_init, Progress},
    show::show_tree,
    store::{parse_store, Store, StoreTags, StoreVersion, TempLoader, Version},
    suretree::AttMap,
};

mod errors;
mod escape;
mod hashes;
pub mod node;
mod progress;
mod show;
mod store;
mod surefs;
mod suretree;

// Some common operations, abstracted here.

/// Perform an update scan, using the given store.
///
/// If 'update' is true, use the hashes from a previous run, otherwise perform a fresh scan.
/// Depending on the [`Store`] type, the tags may be kept, or ignored.
///
/// [`Store`]: trait.Store.html
///
/// A simple example:
///
/// ```rust
/// # use std::error::Error;
/// #
/// # fn try_main() -> Result<(), Box<Error>> {
/// let mut tags = rsure::StoreTags::new();
/// tags.insert("name".into(), "sample".into());
/// let store = rsure::parse_store("2sure.dat.gz")?;
/// rsure::update(".", &*store, false, &tags)?;
/// #     Ok(())
/// # }
/// #
/// # fn main() {
/// #     try_main().unwrap();
/// # }
/// ```
pub fn update<P: AsRef<Path>>(
    dir: P,
    store: &dyn Store,
    is_update: bool,
    tags: &StoreTags,
) -> Result<()> {
    let dir = dir.as_ref();

    let mut estimate = Estimate { files: 0, bytes: 0 };
    let tmp = if is_update {
        // In update mode, first tmp file is just the scan.
        let scan_temp = {
            let mut tmp = store.make_temp()?;
            let src = fs::scan_fs(dir)?;
            node::save_to(&mut tmp, src)?;
            tmp
        }
        .into_loader()?;

        let latest = store.load_iter(Version::Latest)?;

        let tmp = {
            let mut tmp = store.make_temp()?;
            let loader = Loader(&*scan_temp);
            let combiner = HashCombiner::new(latest, loader.iter()?)?.inspect(|node| match node {
                Ok(n @ SureNode::File { .. }) => {
                    if n.needs_hash() {
                        estimate.files += 1;
                        estimate.bytes += n.size();
                    }
                }
                _ => (),
            });
            node::save_to(&mut tmp, combiner)?;
            tmp
        };

        tmp
    } else {
        let mut tmp = store.make_temp()?;
        let src = fs::scan_fs(dir)?.inspect(|node| {
            match node {
                // TODO: This is only correct if this is not an update.
                Ok(n @ SureNode::File { .. }) => {
                    if n.needs_hash() {
                        estimate.files += 1;
                        estimate.bytes += n.size();
                    }
                }
                _ => (),
            }
        });
        node::save_to(&mut tmp, src)?;
        tmp
    }
    .into_loader()?;

    // TODO: If this is an update, pull in hashes from the old version.

    // Update any missing hashes.
    let loader = Loader(&*tmp);
    let hu = HashUpdater::new(loader, store);
    // TODO: This will panic on non-unicode directories.
    let hm = hu.compute_parallel(dir.to_str().unwrap(), &estimate)?;
    let mut tmp2 = store.make_new(tags)?;
    hm.merge(&mut NodeWriter::new(&mut tmp2)?)?;

    tmp2.commit()?;
    /*
        let dir = dir.as_ref();

        let mut new_tree = scan_fs(dir)?;

        if is_update {
            let old_tree = store.load(Version::Latest)?;
            new_tree.update_from(&old_tree);
        }

        let estimate = new_tree.hash_estimate();
        let mut progress = Progress::new(estimate.files, estimate.bytes);
        new_tree.hash_update(dir, &mut progress);
        progress.flush();

        store.write_new(&new_tree, tags)?;
    */
    Ok(())
}

struct Loader<'a>(&'a dyn TempLoader);

impl<'a> Source for Loader<'a> {
    fn iter(&self) -> Result<Box<dyn Iterator<Item = Result<SureNode>> + Send>> {
        let rd = File::open(self.0.path_ref())?;
        Ok(Box::new(load_from(rd)?))
    }
}
<commit_msg>clippy: Change single match to if let<commit_after>//! Rsure is a set of utilities for capturing information about files, and later verifying it is
//! still true.
//!
//! The easiest way to use Rsure is to build the `rsure` executable contained in this crate.  This
//! program allows you to use most of the functionality of the crate.
//!
//! However, it is also possible to use the crate programmatically.  At the top level of the crate
//! as some utility functions for the most common operations.
//!
//! For example, to scan a directory or do an update use `update`.
//!
//! This example makes use of several of the building blocks necessary to use the store.  First is
//! the store itself.  `parse_store` is able to decode options that are passed to the command line.
//! it is also possible to build a `store::Plain` store directly.
//!
//! Next are the tags for the snapshot.  Generally, this should hold some kind of information about
//! the snapshot itself.  For the `Plain` store, it can be just an empty map.  Other store types
//! may require certain tags to be present.

#![warn(bare_trait_objects)]

use std::{fs::File, path::Path};

pub use crate::{
    errors::{Error, Result},
    hashes::Estimate,
    node::{
        compare_trees, fs, load_from, HashCombiner, HashUpdater, NodeWriter, ReadIterator, Source,
        SureNode,
    },
    progress::{log_init, Progress},
    show::show_tree,
    store::{parse_store, Store, StoreTags, StoreVersion, TempLoader, Version},
    suretree::AttMap,
};

mod errors;
mod escape;
mod hashes;
pub mod node;
mod progress;
mod show;
mod store;
mod surefs;
mod suretree;

// Some common operations, abstracted here.

/// Perform an update scan, using the given store.
///
/// If 'update' is true, use the hashes from a previous run, otherwise perform a fresh scan.
/// Depending on the [`Store`] type, the tags may be kept, or ignored.
///
/// [`Store`]: trait.Store.html
///
/// A simple example:
///
/// ```rust
/// # use std::error::Error;
/// #
/// # fn try_main() -> Result<(), Box<Error>> {
/// let mut tags = rsure::StoreTags::new();
/// tags.insert("name".into(), "sample".into());
/// let store = rsure::parse_store("2sure.dat.gz")?;
/// rsure::update(".", &*store, false, &tags)?;
/// #     Ok(())
/// # }
/// #
/// # fn main() {
/// #     try_main().unwrap();
/// # }
/// ```
pub fn update<P: AsRef<Path>>(
    dir: P,
    store: &dyn Store,
    is_update: bool,
    tags: &StoreTags,
) -> Result<()> {
    let dir = dir.as_ref();

    let mut estimate = Estimate { files: 0, bytes: 0 };
    let tmp = if is_update {
        // In update mode, first tmp file is just the scan.
        let scan_temp = {
            let mut tmp = store.make_temp()?;
            let src = fs::scan_fs(dir)?;
            node::save_to(&mut tmp, src)?;
            tmp
        }
        .into_loader()?;

        let latest = store.load_iter(Version::Latest)?;

        let tmp = {
            let mut tmp = store.make_temp()?;
            let loader = Loader(&*scan_temp);
            let combiner = HashCombiner::new(latest, loader.iter()?)?
                .inspect(|node| if let Ok(n @ SureNode::File { .. }) = node {
                    if n.needs_hash() {
                        estimate.files += 1;
                        estimate.bytes += n.size();
                    }
                });
            node::save_to(&mut tmp, combiner)?;
            tmp
        };

        tmp
    } else {
        let mut tmp = store.make_temp()?;
        let src = fs::scan_fs(dir)?.inspect(|node| {
            if let Ok(n @ SureNode::File { .. }) = node {
                if n.needs_hash() {
                    estimate.files += 1;
                    estimate.bytes += n.size();
                }
            }
        });
        node::save_to(&mut tmp, src)?;
        tmp
    }
    .into_loader()?;

    // TODO: If this is an update, pull in hashes from the old version.

    // Update any missing hashes.
    let loader = Loader(&*tmp);
    let hu = HashUpdater::new(loader, store);
    // TODO: This will panic on non-unicode directories.
    let hm = hu.compute_parallel(dir.to_str().unwrap(), &estimate)?;
    let mut tmp2 = store.make_new(tags)?;
    hm.merge(&mut NodeWriter::new(&mut tmp2)?)?;

    tmp2.commit()?;
    /*
        let dir = dir.as_ref();

        let mut new_tree = scan_fs(dir)?;

        if is_update {
            let old_tree = store.load(Version::Latest)?;
            new_tree.update_from(&old_tree);
        }

        let estimate = new_tree.hash_estimate();
        let mut progress = Progress::new(estimate.files, estimate.bytes);
        new_tree.hash_update(dir, &mut progress);
        progress.flush();

        store.write_new(&new_tree, tags)?;
    */
    Ok(())
}

struct Loader<'a>(&'a dyn TempLoader);

impl<'a> Source for Loader<'a> {
    fn iter(&self) -> Result<Box<dyn Iterator<Item = Result<SureNode>> + Send>> {
        let rd = File::open(self.0.path_ref())?;
        Ok(Box::new(load_from(rd)?))
    }
}
<|endoftext|>


<commit_before>// use std::io::Write;
use std::fmt::Write;
use std::str;
use std::iter::Iterator;
use std::collections::HashMap;
use std::string::String;

extern crate regex;
#[macro_use]
extern crate lazy_static;
use regex::Regex;

mod tests;

lazy_static!{
    pub static ref FMT_PAT: Regex = Regex::new(
//        1-ident 2-fill 3-align 4-width  5-precision
        r"([\w\d-_]+)(?::?(.)?([<>^])?([\d]+)?(?:\.([\d]+))?)").unwrap();
// if align doesn't exist, width == fill + width
}

#[derive(Debug, PartialEq)]
enum Align {
    Left,
    Center,
    Right,
    None,
}

pub struct FmtError(String);

/// LOC-fmtu
#[derive(Debug, PartialEq)]
struct Fmt<'a> {
    pub identifier: &'a str,
    pub fill: Option<char>,
    pub align: Align,
    pub width: Option<usize>,
    pub precision: Option<usize>,
}

fn write_char(s: &mut String, c: char, n: usize) {
    for _ in 0..n {
        s.push(c);
    }
}

#[test]
fn test_write_char() {
    let mut s = String::new();
    s.write_str("h ").unwrap();
    write_char(&mut s, 'f', 3);
    assert!(s == "h fff");
}

fn write_from<'a, I>(s: &mut String, f: I, n: usize) -> usize
    where I: Iterator<Item = char>
{
    // eexaust f or run out of n, return chars written
    if n == 0 {
        return 0;
    }
    let mut n_written: usize = 0;
    for c in f {
        s.push(c);
        n_written += 1;
        if n_written == n {
            return n_written;
        }
    }
    n_written
}

#[test]
fn test_write_from() {
    let mut s = String::new();
    s.write_str("h ").unwrap();
    write_from(&mut s, "fff".chars(), 5);
    assert!(s == "h fff");
    write_from(&mut s, "xxxx".chars(), 2);
    assert!(s == "h fffxx");
    write_from(&mut s, "333".chars(), 3);
    assert!(s == "h fffxx333");
}

impl<'a> Fmt<'a> {
    /// create Fmt from format string
    pub fn from_str(fmt: &'a str) -> Result<Fmt, String> {
        let captures = match FMT_PAT.captures(fmt) {
            None => return Err("Invalid format string".to_string()),
            Some(c) => c,
        };
        println!("captures: {:?}", captures);
        let mut out = Fmt {
            identifier: captures.at(1).unwrap(), // not optional==unwrap
            fill: None,
            align: Align::None,
            width: None,
            precision: None,
        };

        let fake_fill = match captures.at(2) {
            None => return Ok(out), // no characters after ':', just return
            Some(f) => f,
        };

        out.align = match captures.at(3) {
            None => Align::None,
            Some("<") => Align::Left,
            Some("^") => Align::Center,
            Some(">") => Align::Right,
            _ => unreachable!(),
        };

        if out.align != Align::None {
            // simple case where everything equals what it should
            out.fill = Some(fake_fill.chars().next().unwrap());
            out.width = match captures.at(4) {
                None => None,
                Some(width) => Some(width.parse::<usize>().unwrap()),
            };
            out.precision = match captures.at(5) {
                None => None,
                Some(prec) => Some(prec.parse::<usize>().unwrap()),
            };
            return Ok(out);
        }

        let fake_width: Option<&str> = captures.at(4);
        let fake_precision: Option<&str> = captures.at(5);

        // we know that align is None

        // if width is not none and fill == '.' then precision == width, width == None
        if fake_width != None && fake_fill == "." {
            out.precision = Some(fake_width.unwrap().parse::<usize>().unwrap());
            return Ok(out);
        }
        let fake_align = match fake_fill {
            "<" => Align::Left,
            "^" => Align::Center,
            ">" => Align::Right,
            _ => Align::None,
        };
        if fake_align != Align::None {
            out.align = fake_align;
            out.width = match fake_width {
                None => None,
                Some(x) => Some(x.parse::<usize>().unwrap()),
            };
            out.precision = match fake_precision {
                None => None,
                Some(x) => Some(x.parse::<usize>().unwrap()),
            };
            return Ok(out);
        }
        // now we know that width == fake_fill + fake_width
        let mut wstr = String::new();
        wstr.write_str(fake_fill).unwrap();
        if fake_width != None {
            wstr.write_str(fake_width.unwrap()).unwrap();
        }
        out.width = match wstr.parse::<usize>() {
            Ok(w) => Some(w),
            Err(_) => return Err("invalid width: must be an int".to_string()),
        };
        out.precision = match fake_precision {
            None => None,
            Some(x) => Some(x.parse::<usize>().unwrap()),
        };
        Ok(out)
    }

    /// write the formatted string to `s` and return true. If there is an error: clear `s`,
    /// write the error and return false
    pub fn write(&self, s: &mut String, vars: &'a HashMap<String, String>) -> bool {
        let ref value = match vars.get(self.identifier) {
            Some(v) => v,
            None => {
                s.clear();
                write!(s, "invalid identifier: {}", self.identifier).unwrap();
                return false;
            }
        };
        let len = value.len();
        let mut value = value.chars();
        let mut written: usize = 0;
        let mut pad: usize = 0;
        let fill = self.fill.unwrap_or(' ');
        let mut precision: Option<usize> = None;
        match self.width {
            Some(mut width) => {
                match width > len {
                    true => {
                        match self.align {
                            Align::Left => pad = width - len,
                            Align::Center => {
                                width = width - len;
                                pad = width / 2;
                                write_char(s, fill, pad);
                                pad += width % 2;
                            }
                            Align::Right | Align::None => {
                                write_char(s, fill, width - len);
                            }
                        }
                    }
                    // width is greater than length, padding not possible but
                    // precision still is.
                    // luckily, the align marker is ignored in this case.
                    false => precision = self.precision,
                }
            }
            None => {
                // no alignment, precision setting is possible
                match self.precision {
                    Some(prec) => precision = Some(prec),

                    None => {} // no special settings
                }
            }
        }
        // deal with precision variable
        match precision {
            Some(prec) => {
                let n = write_from(s, &mut value, prec);
                if n < prec {
                    // only write more if align == Left
                    match self.align {
                        Align::Left => pad = prec - n,
                        _ => return true, // wrote all characters
                    }
                } else {
                    return true; // precision has written maximum characters
                }
            }
            None => {}
        }

        // Done reading settings, now just write and then pad
        s.extend(value);
        write_char(s, fill, pad);
        true
    }
}
<commit_msg>initial strfmt function done<commit_after>// use std::io::Write;
use std::fmt::Write;
use std::iter::Iterator;
use std::collections::HashMap;
use std::string::String;

extern crate regex;
#[macro_use]
extern crate lazy_static;
use regex::Regex;

#[cfg(test)]
mod tests;

lazy_static!{
    pub static ref FMT_PAT: Regex = Regex::new(
//        1-ident 2-fill 3-align 4-width  5-precision
        r"([\w\d-_]+)(?::?(.)?([<>^])?([\d]+)?(?:\.([\d]+))?)").unwrap();
// if align doesn't exist, width == fill + width
}

#[derive(Debug, PartialEq)]
enum Align {
    Left,
    Center,
    Right,
    None,
}

pub struct FmtError(String);

/// LOC-fmtu
#[derive(Debug, PartialEq)]
struct Fmt<'a> {
    pub identifier: &'a str,
    pub fill: Option<char>,
    pub align: Align,
    pub width: Option<usize>,
    pub precision: Option<usize>,
}

fn write_char(s: &mut String, c: char, n: usize) {
    for _ in 0..n {
        s.push(c);
    }
}

#[test]
fn test_write_char() {
    let mut s = String::new();
    s.write_str("h ").unwrap();
    write_char(&mut s, 'f', 3);
    assert!(s == "h fff");
}

fn write_from<'a, I>(s: &mut String, f: I, n: usize) -> usize
    where I: Iterator<Item = char>
{
    // eexaust f or run out of n, return chars written
    if n == 0 {
        return 0;
    }
    let mut n_written: usize = 0;
    for c in f {
        s.push(c);
        n_written += 1;
        if n_written == n {
            return n_written;
        }
    }
    n_written
}

#[test]
fn test_write_from() {
    let mut s = String::new();
    s.write_str("h ").unwrap();
    write_from(&mut s, "fff".chars(), 5);
    assert!(s == "h fff");
    write_from(&mut s, "xxxx".chars(), 2);
    assert!(s == "h fffxx");
    write_from(&mut s, "333".chars(), 3);
    assert!(s == "h fffxx333");
}

impl<'a> Fmt<'a> {
    /// create Fmt from format string
    pub fn from_str(fmt: &'a str) -> Result<Fmt, String> {
        let captures = match FMT_PAT.captures(fmt) {
            None => return Err("Invalid format string".to_string()),
            Some(c) => c,
        };
        println!("captures: {:?}", captures);
        let mut out = Fmt {
            identifier: captures.at(1).unwrap(), // not optional==unwrap
            fill: None,
            align: Align::None,
            width: None,
            precision: None,
        };

        let fake_fill = match captures.at(2) {
            None => return Ok(out), // no characters after ':', just return
            Some(f) => f,
        };

        out.align = match captures.at(3) {
            None => Align::None,
            Some("<") => Align::Left,
            Some("^") => Align::Center,
            Some(">") => Align::Right,
            _ => unreachable!(),
        };

        if out.align != Align::None {
            // simple case where everything equals what it should
            out.fill = Some(fake_fill.chars().next().unwrap());
            out.width = match captures.at(4) {
                None => None,
                Some(width) => Some(width.parse::<usize>().unwrap()),
            };
            out.precision = match captures.at(5) {
                None => None,
                Some(prec) => Some(prec.parse::<usize>().unwrap()),
            };
            return Ok(out);
        }

        let fake_width: Option<&str> = captures.at(4);
        let fake_precision: Option<&str> = captures.at(5);

        // we know that align is None

        // if width is not none and fill == '.' then precision == width, width == None
        if fake_width != None && fake_fill == "." {
            out.precision = Some(fake_width.unwrap().parse::<usize>().unwrap());
            return Ok(out);
        }
        let fake_align = match fake_fill {
            "<" => Align::Left,
            "^" => Align::Center,
            ">" => Align::Right,
            _ => Align::None,
        };
        if fake_align != Align::None {
            out.align = fake_align;
            out.width = match fake_width {
                None => None,
                Some(x) => Some(x.parse::<usize>().unwrap()),
            };
            out.precision = match fake_precision {
                None => None,
                Some(x) => Some(x.parse::<usize>().unwrap()),
            };
            return Ok(out);
        }
        // now we know that width == fake_fill + fake_width
        let mut wstr = String::new();
        wstr.write_str(fake_fill).unwrap();
        if fake_width != None {
            wstr.write_str(fake_width.unwrap()).unwrap();
        }
        out.width = match wstr.parse::<usize>() {
            Ok(w) => Some(w),
            Err(_) => return Err("invalid width: must be an int".to_string()),
        };
        out.precision = match fake_precision {
            None => None,
            Some(x) => Some(x.parse::<usize>().unwrap()),
        };
        Ok(out)
    }

    /// write the formatted string to `s` and return true. If there is an error: clear `s`,
    /// write the error and return false
    pub fn write(&self, s: &mut String, vars: &'a HashMap<String, String>) -> bool {
        let ref value = match vars.get(self.identifier) {
            Some(v) => v,
            None => {
                s.clear();
                write!(s, "invalid identifier: {}", self.identifier).unwrap();
                return false;
            }
        };
        let len = value.len();
        let mut value = value.chars();
        let mut pad: usize = 0;
        let fill = self.fill.unwrap_or(' ');
        let mut precision: Option<usize> = None;
        match self.width {
            Some(mut width) => {
                match width > len {
                    true => {
                        match self.align {
                            Align::Left => pad = width - len,
                            Align::Center => {
                                width = width - len;
                                pad = width / 2;
                                write_char(s, fill, pad);
                                pad += width % 2;
                            }
                            Align::Right | Align::None => {
                                write_char(s, fill, width - len);
                            }
                        }
                    }
                    // width is greater than length, padding not possible but
                    // precision still is.
                    // luckily, the align marker is ignored in this case.
                    false => precision = self.precision,
                }
            }
            None => {
                // no alignment, precision setting is possible
                match self.precision {
                    Some(prec) => precision = Some(prec),

                    None => {} // no special settings
                }
            }
        }
        // deal with precision variable
        match precision {
            Some(prec) => {
                let n = write_from(s, &mut value, prec);
                if n < prec {
                    // only write more if align == Left
                    match self.align {
                        Align::Left => pad = prec - n,
                        _ => return true, // wrote all characters
                    }
                } else {
                    return true; // precision has written maximum characters
                }
            }
            None => {}
        }

        // Done reading settings, now just write and then pad
        s.extend(value);
        write_char(s, fill, pad);
        true
    }
}

/// rust-style format a string given a HashMap of the variables
pub fn strfmt(fmtstr: &str, vars: &HashMap<String, String>) -> Result<String, FmtError> {
    let mut out = String::with_capacity(fmtstr.len() * 2);
    let mut bytes_read: usize = 0;
    let mut opening_brace: usize = 0;
    let mut reading_fmt = false;
    let mut remaining = fmtstr;
    for c in fmtstr.chars() {
        bytes_read += c.len_utf8();
        if c == '{' {
            if reading_fmt && opening_brace == bytes_read - 1 {
                // found {{
                out.push(c);
                out.push(c);
                reading_fmt = false;
            } else if !reading_fmt {
                // found a first {
                reading_fmt = true;
                opening_brace = bytes_read - 1;
            } else {
                // found a { after finding an opening brace, error!
                out.clear();
                out.write_str("extra { found").unwrap();
                return Err(FmtError(out));
            }
        } else if c == '}' {
            if !reading_fmt {
                out.push(c); // extra '}' found, ignore
            } else {
                // discard before opening brace
                let (_, r) = remaining.split_at(opening_brace);
                let (fmt_pattern, r) = r.split_at(bytes_read - opening_brace);
                remaining = r;
                // use the Fmt object to write the formatted string
                match Fmt::from_str(fmt_pattern) {
                    Ok(fmt) => {
                        match fmt.write(&mut out, vars) {
                            true => {}
                            false => {
                                return Err(FmtError(out));
                            }
                        }
                    }
                    Err(err) => return Err(FmtError(err)),
                };
                reading_fmt = false;
                bytes_read = 0;
            }
        } else if !reading_fmt {
            out.push(c)
        } // else we are currently reading a format string, so don't push
    }
    out.shrink_to_fit();
    Ok(out)
}
<|endoftext|>