<commit_before>
//! manage endpoint `/changes/`

use clap::{self, App, SubCommand, Arg};
use gerritlib::error::GGRError;
use gerritlib::error::GGRResult;
use gerritlib::gerrit::Gerrit;
use config;

/// returns the *Changes* part of gerrit-rusts menu
pub fn menu<'a, 'b>() -> App<'a, 'b> {
    SubCommand::with_name("changes")
    .about("changes management")
    .subcommand(SubCommand::with_name("query")
                .about("queries changes")
                .arg(Arg::with_name("regexp-selector")
                     .help("select fields to print; via regular expression")
                     .takes_value(true)
                     .conflicts_with("simple-selector")
                     .long("regexp-selector")
                     .multiple(true)
                     .short("f")
                )
                .arg(Arg::with_name("ofields")
                     .help("return optional fields information")
                     .short("o")
                     .takes_value(true)
                )
                .arg(Arg::with_name("userquery")
                     .help("user query for changes")
                     .required(true)
                     .multiple(true)
                     .takes_value(true)
                )
                .arg(Arg::with_name("fieldslist")
                     .help("get all fields useable for --fields options")
                     .short("l")
                )
                .arg(Arg::with_name("raw")
                     .help("print machine readable raw json stream, useful for \
                            pretty printer. `--fields` and `--fieldslist` are \
                            ignored.")
                     .short("r")
                     .conflicts_with("human")
                )
                .arg(Arg::with_name("human")
                     .help("print human readable json stream `--fields` and \
                            `--fieldslist` are ignored.")
                     .short("u")
                     .conflicts_with("raw")
                )
        )
}

/// proxy function of implemented features
///
/// Currently implemented sub commands:
///
/// * query
pub fn manage(x: &clap::ArgMatches, config: config::Config) -> GGRResult<()> {
    match x.subcommand() {
        ("query", Some(y)) => { query(y, config) },
        _ => {
            println!("{}", x.usage());
            Ok(())
        },
    }
}

/// create, call and prints queries to a gerrit server
fn query(y: &clap::ArgMatches, config: config::Config) -> GGRResult<()> {
    let userquery = match y.values_of_lossy("userquery") {
        Some(x) => Query::from(x),
        None => return Err(GGRError::General("No or bad userquery".into())),
    };

    let regsel = match y.values_of_lossy("regexp-selector") {
        Some(b) => b,
        None => vec!(String::from(".*")),
    };

    let fieldslist = y.is_present("fieldslist");
    let raw = y.is_present("raw");
    let human = y.is_present("human");
    let ofields  = y.values_of_lossy("ofields");

    let mut gerrit = Gerrit::new(config.get_base_url());

    let changeinfos = try!(gerrit.changes(Some(userquery.get_query()), ofields, config.get_username(), config.get_password()));

    if raw {
        println!("{}", changeinfos.raw());
        return Ok(());
    }

    if human {
        println!("{}", changeinfos.human());
        return Ok(());
    }

    if fieldslist {
        let (count, hm) = changeinfos.fieldslist();
        let mut printout = String::new();

        let mut vec_hm: Vec<(&String, &usize)> = hm.iter().collect();
        vec_hm.sort();

        for entry in vec_hm {
            printout.push_str(&format!("{}({})", entry.0, entry.1));
            printout.push(' ');
        }
        println!("{} -> {}", count, printout);
    } else {
        println!("{}", changeinfos.as_string_reg(&regsel));
    }

    Ok(())
}

#[derive(Clone)]
struct Query {
    query: Vec<String>,
}

impl From<Vec<String>> for Query {
    fn from(v: Vec<String>) -> Query {
        let mut qb = Query::new();

        for arg in v {
            qb.add_str(arg);
        }
        qb
    }
}

impl Query {
    pub fn new() -> Query {
        Query {
            query: Vec::new()
        }
    }

    /// Split at first ':' from left so we can have ':' in search string
    pub fn add_str(&mut self, x: String) -> &mut Query {
        // TODO: add preparsing of `x` to prevent missuse like `x=y` instead of `x:y`.
        self.query.push(x);
        self
    }

    pub fn get_query(&self) -> &Vec<String> {
        &self.query
    }
}
<commit_msg>changes: remove last new line character<commit_after>
//! manage endpoint `/changes/`

use clap::{self, App, SubCommand, Arg};
use gerritlib::error::GGRError;
use gerritlib::error::GGRResult;
use gerritlib::gerrit::Gerrit;
use config;

/// returns the *Changes* part of gerrit-rusts menu
pub fn menu<'a, 'b>() -> App<'a, 'b> {
    SubCommand::with_name("changes")
    .about("changes management")
    .subcommand(SubCommand::with_name("query")
                .about("queries changes")
                .arg(Arg::with_name("regexp-selector")
                     .help("select fields to print; via regular expression")
                     .takes_value(true)
                     .conflicts_with("simple-selector")
                     .long("regexp-selector")
                     .multiple(true)
                     .short("f")
                )
                .arg(Arg::with_name("ofields")
                     .help("return optional fields information")
                     .short("o")
                     .takes_value(true)
                )
                .arg(Arg::with_name("userquery")
                     .help("user query for changes")
                     .required(true)
                     .multiple(true)
                     .takes_value(true)
                )
                .arg(Arg::with_name("fieldslist")
                     .help("get all fields useable for --fields options")
                     .short("l")
                )
                .arg(Arg::with_name("raw")
                     .help("print machine readable raw json stream, useful for \
                            pretty printer. `--fields` and `--fieldslist` are \
                            ignored.")
                     .short("r")
                     .conflicts_with("human")
                )
                .arg(Arg::with_name("human")
                     .help("print human readable json stream `--fields` and \
                            `--fieldslist` are ignored.")
                     .short("u")
                     .conflicts_with("raw")
                )
        )
}

/// proxy function of implemented features
///
/// Currently implemented sub commands:
///
/// * query
pub fn manage(x: &clap::ArgMatches, config: config::Config) -> GGRResult<()> {
    match x.subcommand() {
        ("query", Some(y)) => { query(y, config) },
        _ => {
            println!("{}", x.usage());
            Ok(())
        },
    }
}

/// create, call and prints queries to a gerrit server
fn query(y: &clap::ArgMatches, config: config::Config) -> GGRResult<()> {
    let userquery = match y.values_of_lossy("userquery") {
        Some(x) => Query::from(x),
        None => return Err(GGRError::General("No or bad userquery".into())),
    };

    let regsel = match y.values_of_lossy("regexp-selector") {
        Some(b) => b,
        None => vec!(String::from(".*")),
    };

    let fieldslist = y.is_present("fieldslist");
    let raw = y.is_present("raw");
    let human = y.is_present("human");
    let ofields  = y.values_of_lossy("ofields");

    let mut gerrit = Gerrit::new(config.get_base_url());

    let changeinfos = try!(gerrit.changes(Some(userquery.get_query()), ofields, config.get_username(), config.get_password()));

    if raw {
        println!("{}", changeinfos.raw());
        return Ok(());
    }

    if human {
        println!("{}", changeinfos.human());
        return Ok(());
    }

    if fieldslist {
        let (count, hm) = changeinfos.fieldslist();
        let mut printout = String::new();

        let mut vec_hm: Vec<(&String, &usize)> = hm.iter().collect();
        vec_hm.sort();

        for entry in vec_hm {
            printout.push_str(&format!("{}({})", entry.0, entry.1));
            printout.push(' ');
        }
        println!("{} -> {}", count, printout);
    } else {
        println!("{}", changeinfos.as_string_reg(&regsel).trim());
    }

    Ok(())
}

#[derive(Clone)]
struct Query {
    query: Vec<String>,
}

impl From<Vec<String>> for Query {
    fn from(v: Vec<String>) -> Query {
        let mut qb = Query::new();

        for arg in v {
            qb.add_str(arg);
        }
        qb
    }
}

impl Query {
    pub fn new() -> Query {
        Query {
            query: Vec::new()
        }
    }

    /// Split at first ':' from left so we can have ':' in search string
    pub fn add_str(&mut self, x: String) -> &mut Query {
        // TODO: add preparsing of `x` to prevent missuse like `x=y` instead of `x:y`.
        self.query.push(x);
        self
    }

    pub fn get_query(&self) -> &Vec<String> {
        &self.query
    }
}
<|endoftext|>


<commit_before>#![allow(unstable)]
extern crate octobuild;

use octobuild::wincmd;

use std::os;
use std::slice::{Iter};

// Scope of command line argument.
#[derive(Show)]
#[derive(PartialEq)]
enum Scope {
// Preprocessing argument
Preprocessor,
// Unknown argument - local build only
Ignore,
}

#[derive(Show)]
#[derive(PartialEq)]
enum InputKind {
Source,
Marker,
Precompiled,
}

#[derive(Show)]
#[derive(PartialEq)]
enum OutputKind {
Object,
}

#[derive(Show)]
#[derive(PartialEq)]
enum Arg {
Flag{scope:Scope, flag: String},
Param{scope:Scope, flag: String, value: String},
Input{kind:InputKind, flag: String, file: String},
Output{kind:OutputKind, flag: String, file: String},
Unknown {arg:String}
}

fn main() {
	println!("Arguments (raw):");
	for arg in os::args()[1..].iter() {
		println!("  {}", arg);
	}
	println!("Arguments (parsed):");
	for arg in parse_arguments(&os::args()[1..]).iter(){
		println!("  {:?}", arg);
	}
}

fn parse_arguments(args: &[String]) -> Vec<Arg> {
	let mut result: Vec<Arg> = Vec::new();
	let mut iter = args.iter();
	loop {
		match parse_argument(&mut iter) {
				Some(arg) => {
					result.push(arg);
			}
				None => {
				break;
			}
			}
	}
	result
}

fn parse_argument(iter: &mut  Iter<String>) -> Option<Arg> {
	match iter.next() {
			Some(arg) => {
				Some(
					if is_param(arg) {
						match arg[1..].as_slice() {
								"c" => {
								Arg::Flag{scope: Scope::Ignore, flag:"c".to_string()}
							}
								"D" => {
								match iter.next() {
										Some(value) if !is_param(value) => {
										Arg::Param{scope: Scope::Preprocessor, flag:"D".to_string(), value:value.to_string()}
									}
										_ => {
										Arg::Unknown{arg:arg.to_string()}
									}
									}
							}
								s if s.starts_with("D") => {
								Arg::Param{scope: Scope::Preprocessor, flag:"D".to_string(), value:s[1..].to_string()}
							}
								s if s.starts_with("Fo") => {
								Arg::Output{kind:OutputKind::Object, flag:"Fo".to_string(), file:s[2..].to_string()}
							}
								s if s.starts_with("Fp") => {
								Arg::Input{kind:InputKind::Precompiled, flag:"Fp".to_string(), file:s[2..].to_string()}
							}
								s if s.starts_with("Yu") => {
								Arg::Input{kind:InputKind::Marker, flag:"Yu".to_string(), file:s[2..].to_string()}
							}
								_ => {
								Arg::Unknown{arg:arg.to_string()}
							}
							}
					} else {
						Arg::Input{kind:InputKind::Source, flag:String::new(), file:arg.to_string()}
					})
		}
			None => {
			None
		}
		}
}

fn is_param(arg: &String) -> bool {
			arg.starts_with("/") || arg.starts_with("-")
}

#[test]
fn test_parse_argument() {
	assert_eq!(
	parse_arguments(&wincmd::parse("/c /Yusample.h /Fpsample.h.pch /Fosample.cpp.o /DTEST /D TEST2 sample.cpp")[]),
	[
	Arg::Flag { scope: Scope::Ignore, flag: "c".to_string()},
	Arg::Input { kind: InputKind::Marker, flag: "Yu".to_string(), file: "sample.h".to_string()},
	Arg::Input { kind: InputKind::Precompiled, flag: "Fp".to_string(), file: "sample.h.pch".to_string()},
	Arg::Output { kind: OutputKind::Object, flag: "Fo".to_string(), file: "sample.cpp.o".to_string()},
	Arg::Param { scope: Scope::Preprocessor, flag: "D".to_string(), value: "TEST".to_string()},
	Arg::Param { scope: Scope::Preprocessor, flag: "D".to_string(), value: "TEST2".to_string()},
	Arg::Input { kind: InputKind::Source, flag: "".to_string(), file: "sample.cpp".to_string()}
	]
	)
}

#[test]
fn test_precompiled_header()  {
		wincmd::parse("/c /Ycsample.h /Fpsample.h.pch /Foprecompiled.cpp.o precompiled.cpp");
}

#[test]
fn test_compile_no_header()   {
		wincmd::parse("/c /Fosample.cpp.o sample.cpp");
}

#[test]
fn test_compile_with_header() {
		wincmd::parse("/c /Yusample.h /Fpsample.h.pch /Fosample.cpp.o sample.cpp");
}<commit_msg>Add support for some cl flags<commit_after>#![allow(unstable)]
extern crate octobuild;

use octobuild::wincmd;

use std::os;
use std::slice::{Iter};

// Scope of command line argument.
#[derive(Show)]
#[derive(PartialEq)]
enum Scope {
// Preprocessing argument
Preprocessor,
// Compiler argument
Compiler,
// Preprocessor & compiler argument
Shared,
// Unknown argument - local build only
Ignore,
}

#[derive(Show)]
#[derive(PartialEq)]
enum InputKind {
Source,
Marker,
Precompiled,
}

#[derive(Show)]
#[derive(PartialEq)]
enum OutputKind {
Object,
}

#[derive(Show)]
#[derive(PartialEq)]
enum Arg {
Flag{scope:Scope, flag: String},
Param{scope:Scope, flag: String, value: String},
Input{kind:InputKind, flag: String, file: String},
Output{kind:OutputKind, flag: String, file: String},
Unknown {arg:String}
}

fn main() {
	println!("Arguments (raw):");
	for arg in os::args()[1..].iter() {
		println!("  {}", arg);
	}
	println!("Arguments (parsed):");
	for arg in parse_arguments(&os::args()[1..]).iter(){
		println!("  {:?}", arg);
	}
}

fn parse_arguments(args: &[String]) -> Vec<Arg> {
	let mut result: Vec<Arg> = Vec::new();
	let mut iter = args.iter();
	loop {
		match parse_argument(&mut iter) {
				Some(arg) => {
					result.push(arg);
			}
				None => {
				break;
			}
			}
	}
	result
}

fn parse_argument(iter: &mut  Iter<String>) -> Option<Arg> {
	match iter.next() {
			Some(arg) => {
				Some(
					if has_param_prefix(arg) {
						let flag = arg[1..].as_slice();
						match is_spaceable_param(flag) {
								Some((prefix, scope)) => {
								if flag == prefix {
									match iter.next() {
											Some(value) if !has_param_prefix(value) => {
											Arg::Param{scope: scope, flag:prefix.to_string(), value:value.to_string()}
										}
											_ => {
											Arg::Unknown{arg:arg.to_string()}
										}
										}
								} else {
									Arg::Param{scope: scope, flag:prefix.to_string(), value:flag[prefix.len()..].to_string()}
								}
							}
								None => {
								match flag {
										"c" | "nologo" => {
										Arg::Flag{scope: Scope::Ignore, flag:flag.to_string()}
									}
										s if s.starts_with("O") => {
										Arg::Flag{scope: Scope::Compiler, flag:flag.to_string()}
									}
										s if s.starts_with("G") => {
										Arg::Flag{scope: Scope::Compiler, flag:flag.to_string()}
									}
										s if s.starts_with("RTC") => {
										Arg::Flag{scope: Scope::Compiler, flag:flag.to_string()}
									}
										s if s.starts_with("Z") => {
										Arg::Flag{scope: Scope::Compiler, flag:flag.to_string()}
									}
										s if s.starts_with("MD") => {
										Arg::Flag{scope: Scope::Compiler, flag:flag.to_string()}
									}
										s if s.starts_with("MT") => {
										Arg::Flag{scope: Scope::Compiler, flag:flag.to_string()}
									}
										s if s.starts_with("Fo") => {
										Arg::Output{kind:OutputKind::Object, flag:"Fo".to_string(), file:s[2..].to_string()}
									}
										s if s.starts_with("Fp") => {
										Arg::Input{kind:InputKind::Precompiled, flag:"Fp".to_string(), file:s[2..].to_string()}
									}
										s if s.starts_with("Yu") => {
										Arg::Input{kind:InputKind::Marker, flag:"Yu".to_string(), file:s[2..].to_string()}
									}
										_ => {
										Arg::Unknown{arg:arg.to_string()}
									}
									}
							}
							}
					} else {
						Arg::Input{kind:InputKind::Source, flag:String::new(), file:arg.to_string()}
					})
		}
			None => {
			None
		}
		}
}

fn is_spaceable_param(flag: &str) -> Option<(&str, Scope)> {
	for prefix in ["I", "D"].iter() {
		if flag.starts_with(*prefix) {
			return Some((*prefix, Scope::Preprocessor));
		}
	}
	for prefix in ["W", "wd", "we", "wo", "w"].iter() {
		if flag.starts_with(*prefix) {
			return Some((*prefix, Scope::Shared));
		}
	}
	None
}

fn has_param_prefix(arg: &String) -> bool {
			arg.starts_with("/") || arg.starts_with("-")
}

#[test]
fn test_parse_argument() {
	assert_eq!(
	parse_arguments(&wincmd::parse("/c /Yusample.h /Fpsample.h.pch /Fosample.cpp.o /DTEST /D TEST2 sample.cpp")[]),
	[
	Arg::Flag { scope: Scope::Ignore, flag: "c".to_string()},
	Arg::Input { kind: InputKind::Marker, flag: "Yu".to_string(), file: "sample.h".to_string()},
	Arg::Input { kind: InputKind::Precompiled, flag: "Fp".to_string(), file: "sample.h.pch".to_string()},
	Arg::Output { kind: OutputKind::Object, flag: "Fo".to_string(), file: "sample.cpp.o".to_string()},
	Arg::Param { scope: Scope::Preprocessor, flag: "D".to_string(), value: "TEST".to_string()},
	Arg::Param { scope: Scope::Preprocessor, flag: "D".to_string(), value: "TEST2".to_string()},
	Arg::Input { kind: InputKind::Source, flag: "".to_string(), file: "sample.cpp".to_string()}
	]
	)
}

#[test]
fn test_precompiled_header()  {
		wincmd::parse("/c /Ycsample.h /Fpsample.h.pch /Foprecompiled.cpp.o precompiled.cpp");
}

#[test]
fn test_compile_no_header()   {
		wincmd::parse("/c /Fosample.cpp.o sample.cpp");
}

#[test]
fn test_compile_with_header() {
		wincmd::parse("/c /Yusample.h /Fpsample.h.pch /Fosample.cpp.o sample.cpp");
}<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::cell::Cell;
use std::sync::Arc;

/// Naive implementation of a `Gauge`.
///
/// It might be nice to make one built on atomics.
#[derive(Debug)]
pub struct StdGauge {
    /// The gauge value.
    pub value: Cell<isize>,
}

/// A snapshot of the value of a `Gauge`.
#[derive(Debug)]
pub struct GaugeSnapshot {
    /// The snapshot of the gauge value.
    pub value: isize,
}

/// `Gauge` is a `Metric` that represents a single numerical value that can
/// arbitrarily go up and down.
///
/// A `Gauge` is typically used for measured values like temperatures or current
/// memory usage, but also "counts" that can go up and down.
pub trait Gauge {
    /// Increment the gauge by 1.
    fn inc(&self);
    /// Decrement the gauge by 1.
    fn dec(&self);
    /// Increment the gauge by the given amount.
    fn add(&self, value: isize);
    /// Decrement the gauge by the given amount.
    fn sub(&self, value: isize);
    /// Set the current value of the gauge.
    fn set(&self, value: isize);
    /// Take a snapshot of the current value for use with a `Reporter`.
    fn snapshot(&self) -> GaugeSnapshot;
}

impl Gauge for StdGauge {
    fn inc(&self) {
        self.value.set(self.value.get() + 1);
    }

    fn dec(&self) {
        self.value.set(self.value.get() - 1);
    }

    fn add(&self, value: isize) {
        self.value.set(self.value.get() + value);
        // TODO check for negative
    }

    fn sub(&self, value: isize) {
        self.value.set(self.value.get() - value);
    }

    fn set(&self, value: isize) {
        self.value.set(value);
    }

    fn snapshot(&self) -> GaugeSnapshot {
        GaugeSnapshot { value: self.value.get() }
    }
}

impl StdGauge {
    /// Create a new `StdGauge`.
    pub fn new() -> Arc<Self> {
        Arc::new(StdGauge { value: Cell::new(0) })
    }
}

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

    #[test]
    fn create_and_snapshot() {
        let g = StdGauge::new();
        let snapshot_1 = g.snapshot();
        g.set(10);
        let snapshot_2 = g.snapshot();

        assert_eq!(g.value.get(), 10);
        assert_eq!(snapshot_1.value, 0);
        assert_eq!(snapshot_2.value, 10);
    }
}
<commit_msg>Switch Gauge to using AtomicIsize.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::sync::atomic::{AtomicIsize, Ordering};
use std::sync::Arc;

/// Naive implementation of a `Gauge`.
#[derive(Debug)]
pub struct StdGauge {
    /// The gauge value.
    pub value: AtomicIsize,
}

/// A snapshot of the value of a `Gauge`.
#[derive(Debug)]
pub struct GaugeSnapshot {
    /// The snapshot of the gauge value.
    pub value: isize,
}

/// `Gauge` is a `Metric` that represents a single numerical value that can
/// arbitrarily go up and down.
///
/// A `Gauge` is typically used for measured values like temperatures or current
/// memory usage, but also "counts" that can go up and down.
pub trait Gauge {
    /// Increment the gauge by 1.
    fn inc(&self);
    /// Decrement the gauge by 1.
    fn dec(&self);
    /// Increment the gauge by the given amount.
    fn add(&self, value: isize);
    /// Decrement the gauge by the given amount.
    fn sub(&self, value: isize);
    /// Set the current value of the gauge.
    fn set(&self, value: isize);
    /// Take a snapshot of the current value for use with a `Reporter`.
    fn snapshot(&self) -> GaugeSnapshot;
}

impl Gauge for StdGauge {
    fn inc(&self) {
        self.value.fetch_add(1, Ordering::Relaxed);
    }

    fn dec(&self) {
        self.value.fetch_sub(1, Ordering::Relaxed);
    }

    fn add(&self, value: isize) {
        self.value.fetch_add(value, Ordering::Relaxed);
        // TODO check for negative
    }

    fn sub(&self, value: isize) {
        self.value.fetch_sub(value, Ordering::Relaxed);
    }

    fn set(&self, value: isize) {
        self.value.store(value, Ordering::Relaxed);
    }

    fn snapshot(&self) -> GaugeSnapshot {
        GaugeSnapshot { value: self.value.load(Ordering::Relaxed) }
    }
}

impl StdGauge {
    /// Create a new `StdGauge`.
    pub fn new() -> Arc<Self> {
        Arc::new(StdGauge { value: AtomicIsize::new(0) })
    }
}

#[cfg(test)]
mod test {
    use std::sync::atomic::Ordering;
    use super::*;

    #[test]
    fn create_and_snapshot() {
        let g = StdGauge::new();
        let snapshot_1 = g.snapshot();
        g.set(10);
        let snapshot_2 = g.snapshot();

        assert_eq!(g.value.load(Ordering::Relaxed), 10);
        assert_eq!(snapshot_1.value, 0);
        assert_eq!(snapshot_2.value, 10);
    }
}
<|endoftext|>


<commit_before>#![feature(proc_macro, generators, pin)]

extern crate futures;

use futures::prelude::*;

#[async_move]
fn foo() -> u32 {
    3
}

#[async_move(boxed)]
fn bar() -> u32 {
    3
}

#[async_stream_move(item = u32)]
fn foos() -> u32 {
    3
}

#[async_stream_move(boxed, item = u32)]
fn bars() -> u32 {
    3
}

fn main() {}
<commit_msg>Fix UI tests<commit_after>#![feature(proc_macro, generators, pin)]

extern crate futures;

use futures::prelude::*;

#[async(unpin)]
fn foo() -> u32 {
    3
}

#[async(unpin, boxed)]
fn bar() -> u32 {
    3
}

#[async_stream(unpin, item = u32)]
fn foos() -> u32 {
    3
}

#[async_stream(unpin, boxed, item = u32)]
fn bars() -> u32 {
    3
}

fn main() {}
<|endoftext|>


<commit_before>#![allow(non_snake_case)]

use std::cmp;
use std::mem;

use rgsl::randist::multinomial::multinomial_pdf;

use bio::stats::combinatorics::combinations;
use bio::stats::logprobs::{Prob, LogProb};
use bio::stats::logprobs;

use io::codebook::Codebook;

pub struct Params {
    p0: Prob,
    p1: Prob,
    codebook: Codebook
}

pub trait Model: Sync {

    fn params(&self) -> &Params;

    /// Probability to make exactly i 1->0 and j 0->1 errors.
    fn xi(&self, i: u8, j: u8) -> Prob {
        self.params().p1.powi(i as i32) * self.params().p0.powi(j as i32) *
        (1.0 - self.params().p1).powi((self.params().codebook.m - i) as i32) * (1.0 - self.params().p0).powi((self.params().codebook.N - self.params().codebook.m - j) as i32)
    }

    /// Number of possibilities to select i ones and j zeros.
    fn psi(&self, i: u8, j: u8) -> f64 {
        combinations(self.params().codebook.m as u64, i as u64) * combinations((self.params().codebook.N - self.params().codebook.m) as u64, j as u64)
    }

    /// Probability to see an exact readout given that we have a call.
    fn prob_call_exact(&self) -> Prob;

    /// Probability to see a readout with one mismatch given that we have a call.
    fn prob_call_mismatch(&self) -> Prob;

    /// Probability to see an exact readout given that we have a miscall.
    fn prob_miscall_exact(&self, feature: &str) -> Prob;

    /// Probability to see a readout with one mismatch given that we have a miscall.
    fn prob_miscall_mismatch(&self, feature: &str) -> Prob;

    /// Probability to miss or miscall a readout because of too many errors.
    fn prob_missed(&self) -> Prob {
        1.0 - self.prob_call_exact() - self.prob_call_mismatch()
    }

    fn prob_miscall(&self, feature: &str) -> Prob {
        self.prob_miscall_exact(feature) + self.prob_miscall_mismatch(feature)
    }

    /// Probability to completely miss a readout (not miscalled).
    fn prob_nocall(&self, feature: &str) -> Prob {
        1.0 - self.prob_miscall_exact(feature) - self.prob_miscall_mismatch(feature)
    }
}

pub struct MHD4 {
    params: Params
}

impl Model for MHD4 {

    fn params(&self) -> &Params {
        &self.params
    }

    /// Probability to see an exact readout given that we have a call.
    fn prob_call_exact(&self) -> Prob {
        self.xi(0, 0)
    }

    /// Probability to see a readout with one mismatch given that we have a call.
    fn prob_call_mismatch(&self) -> Prob {
        (self.params().codebook.m as f64 * self.xi(1, 0) + (self.params().codebook.N - self.params().codebook.m) as f64 * self.xi(0, 1))
    }

    /// Probability to see an exact readout given that we have a miscall.
    fn prob_miscall_exact(&self, feature: &str) -> Prob {
        println!("{}", self.params().codebook.neighbors(feature, 4).len());
        self.params().codebook.neighbors(feature, 4).len() as f64 * self.xi(2, 2)
    }

    /// Probability to see a readout with one mismatch given that we have a miscall.
    fn prob_miscall_mismatch(&self, feature: &str) -> Prob {
        let n = self.params().codebook.neighbors(feature, 4).len() as f64;

        n * 2 as f64 * self.xi(2, 1) + n * 2 as f64 * self.xi(1, 2) +
        n * (self.params().codebook.m - 2) as f64 * self.xi(3, 2) + n * (self.params().codebook.N - self.params().codebook.m - 2) as f64 * self.xi(2, 3)
    }
}

pub struct MHD2 {
    params: Params
}

impl Model for MHD2 {

    fn params(&self) -> &Params {
        &self.params
    }

    /// Probability to see an exact readout given that we have a call.
    fn prob_call_exact(&self) -> Prob {
        self.xi(0, 0)
    }

    /// Probability to see a readout with one mismatch given that we have a call.
    fn prob_call_mismatch(&self) -> Prob {
        0.0
    }

    /// Probability to see an exact readout given that we have a miscall.
    fn prob_miscall_exact(&self, feature: &str) -> Prob {
        self.params().codebook.neighbors(feature, 2).len() as f64 * self.xi(1, 1) +
        self.params().codebook.neighbors(feature, 4).len() as f64 * self.xi(2, 2)
    }

    /// Probability to see a readout with one mismatch given that we have a miscall.
    #[allow(unused_variables)]
    fn prob_miscall_mismatch(&self, feature: &str) -> Prob {
        0.0
    }
}

pub fn new_model(p0: Prob, p1: Prob, codebook: Codebook) -> Box<Model> {
    let params = Params {p0: p0, p1: p1, codebook: codebook};
    let model: Box<Model> = match params.codebook.min_dist {
        4 => Box::new(MHD4 { params: params }),
        2 => Box::new(MHD2 { params: params }),
        _ => panic!("Hamming distances other than 2 and 4 are unsupported at the moment.")
    };
    model
}

/// Readout probabilities.
pub struct Readout {
    prob_call_exact: Prob,
    prob_call_mismatch: Prob,
    prob_miscall_exact: Prob,
    prob_miscall_mismatch: Prob,
    prob_missed: Prob,
    prob_nocall: Prob,
    prob_miscall: Prob,
    prob_call: Prob,
    margin: u32
}

impl Readout {
    pub fn new(feature: &str, model: &Box<Model>, window_width: u32) -> Self {
        let prob_miscall = model.prob_miscall(feature);
        Readout {
            prob_call_exact: model.prob_call_exact(),
            prob_call_mismatch: model.prob_call_mismatch(),
            prob_miscall_exact: model.prob_miscall_exact(feature),
            prob_miscall_mismatch: model.prob_miscall_mismatch(feature),
            prob_missed: model.prob_missed(),
            prob_nocall: model.prob_nocall(feature),
            prob_miscall: prob_miscall,
            prob_call: 1.0 - prob_miscall,
            margin: window_width / 2
        }
    }

    fn est_x(&self, n: f64) -> u32 {
        (
            n * self.prob_call_exact * self.prob_call +
            n * self.prob_call_mismatch * self.prob_call +
            n * self.prob_missed * self.prob_call
        ).round() as u32
    }

    /// Upper and lower bound for MAP
    pub fn map_bounds(&self, count: u32, count_exact: u32) -> (u32, u32) {
        // estimate n from exact readouts
        let n_0 = count_exact as f64 / (self.prob_call_exact * self.prob_call + self.prob_miscall_exact);
        let n_1 = {
            // estimate n from corrected readouts
            let p = self.prob_call_mismatch * self.prob_call + self.prob_miscall_mismatch;
            if p > 0.0 {
                let n_1 = (count - count_exact) as f64 / p;
                n_1
            } else {
                n_0
            }
        };

        // estimate lower and upper bound of x
        // with MHD2, this is the same and the estimate is equivalent to the MAP
        let mut x_0 = self.est_x(n_0);
        let mut x_1 = self.est_x(n_1);
        if x_0 > x_1 {
            mem::swap(&mut x_0, &mut x_1);
        }

        (x_0 as u32, x_1 as u32)
    }

    pub fn naive_estimate(&self, count: u32) -> u32 {
        let n_avg = count as f64 / (
            self.prob_call_exact * self.prob_call +
            self.prob_call_mismatch * self.prob_call +
            self.prob_miscall_exact +
            self.prob_miscall_mismatch
        );
        self.est_x(n_avg) as u32
    }

    /// Prior window for calculating expression PMF
    pub fn window(&self, count: u32, count_exact: u32) -> (u32, u32) {
        let x = self.naive_estimate(count);

        (cmp::max(x as i32 - self.margin as i32, 0) as u32, x + self.margin)
    }

    pub fn likelihood(&self, x: u32, count: u32, count_exact: u32) -> LogProb {
        let count = count;
        let count_exact = count_exact;
        assert!(count >= count_exact);

        let mut summands = Vec::new();
        let probs = [
            self.prob_call_exact * self.prob_call, // Pr(H=0, E=e) = Pr(H=0 | E=e) * Pr(E=e)
            self.prob_call_mismatch * self.prob_call,
            self.prob_missed * self.prob_call,
            self.prob_miscall_exact,
            self.prob_miscall_mismatch
        ];

        for i in 0..(cmp::min(x, count) + 1) {
            let jmax = cmp::min(count_exact, i);
            // i - j <= count - count_exact
            let jmin = if count_exact + i > count { count_exact + i - count } else { 0 };
            for j in jmin..(jmax + 1) {
                //let n = combinations((count - count_exact) as u64, (i - j) as u64).ln() + combinations(count_exact as u64, j as u64).ln();
                let k = x - i;
                let exact_miscalls = count_exact - j;
                let mismatch_miscalls = count - count_exact - (i - j);

                let p = multinomial_pdf(&probs, &[j, i - j, k, exact_miscalls, mismatch_miscalls]).ln();
                summands.push(p);
            }
        }
        let likelihood = logprobs::sum(&summands);
        assert!(!likelihood.is_nan());
        likelihood
    }

    pub fn expected_total(&self, total_count: u32) -> f64 {
        // c = x - x * p_nocall
        // x = c / (1 - p_nocall)
        total_count as f64 / (1.0 - self.prob_nocall)
    }
}

#[cfg(test)]
mod tests {
    #![allow(non_upper_case_globals)]

    use super::*;
    use nalgebra::ApproxEq;
    use io;

    fn setup_mhd4() -> Box<Model> {
        new_model(0.04, 0.1, io::codebook::Codebook::from_file("test/codebook/simulated-MHD4.txt").unwrap())
    }

    fn setup_mhd2() -> Box<Model> {
        new_model(0.04, 0.1, io::codebook::Codebook::from_file("test/codebook/simulated-MHD2.txt").unwrap())
    }

    #[test]
    fn test_prob_call_exact() {
        let model = setup_mhd4();
        let p = model.prob_call_exact();
        println!("{}", p);
        assert!(p.approx_eq(&0.4019988717840602));
    }

    #[test]
    fn test_prob_call_mismatch() {
        let model = setup_mhd4();
        let p = model.prob_call_mismatch();
        println!("{}", p);
        assert!(p.approx_eq(&0.3796656011293904));
    }

    #[test]
    fn test_prob_miscall_exact() {
        let model = setup_mhd4();
        let p = model.prob_miscall_exact("COL5A1");
        println!("{}", p);
        assert!(p.approx_eq(&0.00031018431464819473));
    }

    #[test]
    fn test_prob_miscall_mismatch() {
        let model = setup_mhd4();
        let p = model.prob_miscall_mismatch("COL5A1");
        println!("{}", p);
        assert!(p.approx_eq(&0.020670338078917206));
    }

    #[test]
    fn test_prob_missed() {
        let model = setup_mhd4();
        let p = model.prob_missed();
        println!("{}", p);
        assert!(p.approx_eq(&0.21833552708654924));
    }

    #[test]
    fn test_mhd2() {
        let model = setup_mhd2();
        println!("{}", model.prob_call_exact());
        println!("{}", model.prob_call_mismatch());
        println!("{}", model.prob_miscall_exact("COL7A1"));
        println!("{}", model.prob_miscall_mismatch("COL7A1"));
        println!("{}", model.prob_missed());
    }

    #[test]
    fn test_xi() {
        let model = setup_mhd4();
        let p = model.xi(0, 0);
        assert!(p.approx_eq(&0.4019988717840602));
        let p = model.xi(1, 0);
        assert!(p.approx_eq(&0.04466654130934002));
        let p = model.xi(0, 1);
        assert!(p.approx_eq(&0.01674995299100251));
        let p = model.xi(2, 2);
        assert!(p.approx_eq(&8.616230962449852e-06));
        let p = model.xi(2, 1);
        assert!(p.approx_eq(&0.00020678954309879646));
        let p = model.xi(1, 2);
        assert!(p.approx_eq(&7.754607866204867e-05));
    }

    #[test]
    fn test_window() {
        let model = setup_mhd4();
        let readout = Readout::new("COL5A1", &model, 100);
        let (lower, upper) = readout.window(175, 75);
        println!("{} {}", lower, upper);
        for x in lower..upper {
            println!("{}={}", x, readout.likelihood(x, 175, 75));
        }
        assert!(readout.likelihood(lower, 175, 75).exp().approx_eq(&0.0));
        assert!(readout.likelihood(upper, 175, 75).exp().approx_eq(&0.0));
    }
}
<commit_msg>Debugging.<commit_after>#![allow(non_snake_case)]

use std::cmp;
use std::mem;

use rgsl::randist::multinomial::multinomial_pdf;

use bio::stats::combinatorics::combinations;
use bio::stats::logprobs::{Prob, LogProb};
use bio::stats::logprobs;

use io::codebook::Codebook;

pub struct Params {
    p0: Prob,
    p1: Prob,
    codebook: Codebook
}

pub trait Model: Sync {

    fn params(&self) -> &Params;

    /// Probability to make exactly i 1->0 and j 0->1 errors.
    fn xi(&self, i: u8, j: u8) -> Prob {
        self.params().p1.powi(i as i32) * self.params().p0.powi(j as i32) *
        (1.0 - self.params().p1).powi((self.params().codebook.m - i) as i32) * (1.0 - self.params().p0).powi((self.params().codebook.N - self.params().codebook.m - j) as i32)
    }

    /// Number of possibilities to select i ones and j zeros.
    fn psi(&self, i: u8, j: u8) -> f64 {
        combinations(self.params().codebook.m as u64, i as u64) * combinations((self.params().codebook.N - self.params().codebook.m) as u64, j as u64)
    }

    /// Probability to see an exact readout given that we have a call.
    fn prob_call_exact(&self) -> Prob;

    /// Probability to see a readout with one mismatch given that we have a call.
    fn prob_call_mismatch(&self) -> Prob;

    /// Probability to see an exact readout given that we have a miscall.
    fn prob_miscall_exact(&self, feature: &str) -> Prob;

    /// Probability to see a readout with one mismatch given that we have a miscall.
    fn prob_miscall_mismatch(&self, feature: &str) -> Prob;

    /// Probability to miss or miscall a readout because of too many errors.
    fn prob_missed(&self) -> Prob {
        1.0 - self.prob_call_exact() - self.prob_call_mismatch()
    }

    fn prob_miscall(&self, feature: &str) -> Prob {
        self.prob_miscall_exact(feature) + self.prob_miscall_mismatch(feature)
    }

    /// Probability to completely miss a readout (not miscalled).
    fn prob_nocall(&self, feature: &str) -> Prob {
        1.0 - self.prob_miscall_exact(feature) - self.prob_miscall_mismatch(feature)
    }
}

pub struct MHD4 {
    params: Params
}

impl Model for MHD4 {

    fn params(&self) -> &Params {
        &self.params
    }

    /// Probability to see an exact readout given that we have a call.
    fn prob_call_exact(&self) -> Prob {
        self.xi(0, 0)
    }

    /// Probability to see a readout with one mismatch given that we have a call.
    fn prob_call_mismatch(&self) -> Prob {
        (self.params().codebook.m as f64 * self.xi(1, 0) + (self.params().codebook.N - self.params().codebook.m) as f64 * self.xi(0, 1))
    }

    /// Probability to see an exact readout given that we have a miscall.
    fn prob_miscall_exact(&self, feature: &str) -> Prob {
        println!("{}", self.params().codebook.neighbors(feature, 4).len());
        self.params().codebook.neighbors(feature, 4).len() as f64 * self.xi(2, 2)
    }

    /// Probability to see a readout with one mismatch given that we have a miscall.
    fn prob_miscall_mismatch(&self, feature: &str) -> Prob {
        let n = self.params().codebook.neighbors(feature, 4).len() as f64;

        n * 2 as f64 * self.xi(2, 1) + n * 2 as f64 * self.xi(1, 2) +
        n * (self.params().codebook.m - 2) as f64 * self.xi(3, 2) + n * (self.params().codebook.N - self.params().codebook.m - 2) as f64 * self.xi(2, 3)
    }
}

pub struct MHD2 {
    params: Params
}

impl Model for MHD2 {

    fn params(&self) -> &Params {
        &self.params
    }

    /// Probability to see an exact readout given that we have a call.
    fn prob_call_exact(&self) -> Prob {
        self.xi(0, 0)
    }

    /// Probability to see a readout with one mismatch given that we have a call.
    fn prob_call_mismatch(&self) -> Prob {
        0.0
    }

    /// Probability to see an exact readout given that we have a miscall.
    fn prob_miscall_exact(&self, feature: &str) -> Prob {
        self.params().codebook.neighbors(feature, 2).len() as f64 * self.xi(1, 1) +
        self.params().codebook.neighbors(feature, 4).len() as f64 * self.xi(2, 2)
    }

    /// Probability to see a readout with one mismatch given that we have a miscall.
    #[allow(unused_variables)]
    fn prob_miscall_mismatch(&self, feature: &str) -> Prob {
        0.0
    }
}

pub fn new_model(p0: Prob, p1: Prob, codebook: Codebook) -> Box<Model> {
    let params = Params {p0: p0, p1: p1, codebook: codebook};
    let model: Box<Model> = match params.codebook.min_dist {
        4 => Box::new(MHD4 { params: params }),
        2 => Box::new(MHD2 { params: params }),
        _ => panic!("Hamming distances other than 2 and 4 are unsupported at the moment.")
    };
    model
}

/// Readout probabilities.
pub struct Readout {
    prob_call_exact: Prob,
    prob_call_mismatch: Prob,
    prob_miscall_exact: Prob,
    prob_miscall_mismatch: Prob,
    prob_missed: Prob,
    prob_nocall: Prob,
    prob_miscall: Prob,
    prob_call: Prob,
    margin: u32
}

impl Readout {
    pub fn new(feature: &str, model: &Box<Model>, window_width: u32) -> Self {
        let prob_miscall = model.prob_miscall(feature);
        Readout {
            prob_call_exact: model.prob_call_exact(),
            prob_call_mismatch: model.prob_call_mismatch(),
            prob_miscall_exact: model.prob_miscall_exact(feature),
            prob_miscall_mismatch: model.prob_miscall_mismatch(feature),
            prob_missed: model.prob_missed(),
            prob_nocall: model.prob_nocall(feature),
            prob_miscall: prob_miscall,
            prob_call: 1.0 - prob_miscall,
            margin: window_width / 2
        }
    }

    fn est_x(&self, n: f64) -> u32 {
        (
            n * self.prob_call_exact * self.prob_call +
            n * self.prob_call_mismatch * self.prob_call +
            n * self.prob_missed * self.prob_call
        ).round() as u32
    }

    /// Upper and lower bound for MAP
    pub fn map_bounds(&self, count: u32, count_exact: u32) -> (u32, u32) {
        // estimate n from exact readouts
        let n_0 = count_exact as f64 / (self.prob_call_exact * self.prob_call + self.prob_miscall_exact);
        let n_1 = {
            // estimate n from corrected readouts
            let p = self.prob_call_mismatch * self.prob_call + self.prob_miscall_mismatch;
            if p > 0.0 {
                let n_1 = (count - count_exact) as f64 / p;
                n_1
            } else {
                n_0
            }
        };

        // estimate lower and upper bound of x
        // with MHD2, this is the same and the estimate is equivalent to the MAP
        let mut x_0 = self.est_x(n_0);
        let mut x_1 = self.est_x(n_1);
        if x_0 > x_1 {
            mem::swap(&mut x_0, &mut x_1);
        }

        (x_0 as u32, x_1 as u32)
    }

    pub fn naive_estimate(&self, count: u32) -> u32 {
        let n_avg = count as f64 / (
            self.prob_call_exact * self.prob_call +
            self.prob_call_mismatch * self.prob_call +
            self.prob_miscall_exact +
            self.prob_miscall_mismatch
        );
        self.est_x(n_avg) as u32
    }

    /// Prior window for calculating expression PMF
    pub fn window(&self, count: u32, count_exact: u32) -> (u32, u32) {
        let x = self.naive_estimate(count);

        (cmp::max(x as i32 - self.margin as i32, 0) as u32, x + self.margin)
    }

    pub fn likelihood(&self, x: u32, count: u32, count_exact: u32) -> LogProb {
        let count = count;
        let count_exact = count_exact;
        assert!(count >= count_exact);

        let mut summands = Vec::new();
        let probs = [
            self.prob_call_exact * self.prob_call, // Pr(H=0, E=e) = Pr(H=0 | E=e) * Pr(E=e)
            self.prob_call_mismatch * self.prob_call,
            self.prob_missed * self.prob_call,
            self.prob_miscall_exact,
            self.prob_miscall_mismatch
        ];

        for i in 0..(cmp::min(x, count) + 1) {
            let jmax = cmp::min(count_exact, i);
            // i - j <= count - count_exact
            let jmin = if count_exact + i > count { count_exact + i - count } else { 0 };
            for j in jmin..(jmax + 1) {
                //let n = combinations((count - count_exact) as u64, (i - j) as u64).ln() + combinations(count_exact as u64, j as u64).ln();
                let k = x - i;
                let exact_miscalls = count_exact - j;
                let mismatch_miscalls = count - count_exact - (i - j);

                let p = multinomial_pdf(&probs, &[j, i - j, k, exact_miscalls, mismatch_miscalls]).ln();
                summands.push(p);
            }
        }
        let likelihood = logprobs::sum(&summands);
        assert!(!likelihood.is_nan());
        likelihood
    }

    pub fn expected_total(&self, total_count: u32) -> f64 {
        // c = x - x * p_nocall
        // x = c / (1 - p_nocall)
        total_count as f64 / (1.0 - self.prob_nocall)
    }
}

#[cfg(test)]
mod tests {
    #![allow(non_upper_case_globals)]

    use super::*;
    use nalgebra::ApproxEq;
    use io;

    fn setup_mhd4() -> Box<Model> {
        new_model(0.04, 0.1, io::codebook::Codebook::from_file("test/codebook/simulated-MHD4.txt").unwrap())
    }

    fn setup_mhd2() -> Box<Model> {
        new_model(0.04, 0.1, io::codebook::Codebook::from_file("test/codebook/simulated-MHD2.txt").unwrap())
    }

    #[test]
    fn test_prob_call_exact() {
        let model = setup_mhd4();
        let p = model.prob_call_exact();
        println!("{}", p);
        assert!(p.approx_eq(&0.4019988717840602));
    }

    #[test]
    fn test_prob_call_mismatch() {
        let model = setup_mhd4();
        let p = model.prob_call_mismatch();
        println!("{}", p);
        assert!(p.approx_eq(&0.3796656011293904));
    }

    #[test]
    fn test_prob_miscall_exact() {
        let model = setup_mhd4();
        let p = model.prob_miscall_exact("COL5A1");
        println!("{}", p);
        assert!(p.approx_eq(&0.00031018431464819473));
    }

    #[test]
    fn test_prob_miscall_mismatch() {
        let model = setup_mhd4();
        let p = model.prob_miscall_mismatch("COL5A1");
        println!("{}", p);
        assert!(p.approx_eq(&0.020670338078917206));
    }

    #[test]
    fn test_prob_missed() {
        let model = setup_mhd4();
        let p = model.prob_missed();
        println!("{}", p);
        assert!(p.approx_eq(&0.21833552708654924));
    }

    #[test]
    fn test_mhd2() {
        let model = setup_mhd2();
        println!("{}", model.prob_call_exact());
        println!("{}", model.prob_call_mismatch());
        println!("{}", model.prob_miscall_exact("COL7A1"));
        println!("{}", model.prob_miscall_mismatch("COL7A1"));
        println!("{}", model.prob_missed());
        assert!(false);
    }

    #[test]
    fn test_xi() {
        let model = setup_mhd4();
        let p = model.xi(0, 0);
        assert!(p.approx_eq(&0.4019988717840602));
        let p = model.xi(1, 0);
        assert!(p.approx_eq(&0.04466654130934002));
        let p = model.xi(0, 1);
        assert!(p.approx_eq(&0.01674995299100251));
        let p = model.xi(2, 2);
        assert!(p.approx_eq(&8.616230962449852e-06));
        let p = model.xi(2, 1);
        assert!(p.approx_eq(&0.00020678954309879646));
        let p = model.xi(1, 2);
        assert!(p.approx_eq(&7.754607866204867e-05));
    }

    #[test]
    fn test_window() {
        let model = setup_mhd4();
        let readout = Readout::new("COL5A1", &model, 100);
        let (lower, upper) = readout.window(175, 75);
        println!("{} {}", lower, upper);
        for x in lower..upper {
            println!("{}={}", x, readout.likelihood(x, 175, 75));
        }
        assert!(readout.likelihood(lower, 175, 75).exp().approx_eq(&0.0));
        assert!(readout.likelihood(upper, 175, 75).exp().approx_eq(&0.0));
    }
}
<|endoftext|>


<commit_before>use std::iter::Peekable;
use std::str::Chars;

pub struct Reader<'l> {
    line: usize,
    column: usize,
    offset: usize,
    content: &'l str,
    cursor: Peekable<Chars<'l>>,
}

impl<'l> Reader<'l> {
    #[inline]
    pub fn new(content: &'l str) -> Self {
        Reader {
            line: 1,
            column: 1,
            offset: 0,
            content: content,
            cursor: content.chars().peekable(),
        }
    }

    pub fn capture<F>(&mut self, block: F) -> Option<&'l str>
        where F: Fn(&mut Reader<'l>) -> bool
    {
        let start = self.offset;
        if !block(self) {
            return None;
        }
        let content = &self.content[start..self.offset].trim();
        if content.is_empty() { None } else { Some(content) }
    }

    #[inline]
    pub fn consume_all(&mut self) -> bool {
        self.consume_while(|_| true)
    }

    #[inline]
    pub fn consume_any(&mut self, chars: &str) -> bool {
        self.consume_while(|c| chars.contains(c))
    }

    /// https://www.w3.org/TR/REC-xml/#NT-Attribute
    pub fn consume_attribute(&mut self) -> bool {
        self.consume_name() && self.consume_equality() && self.consume_attribute_value()
    }

    /// https://www.w3.org/TR/REC-xml/#NT-AttValue
    pub fn consume_attribute_value(&mut self) -> bool {
        if self.consume_char('\'') {
            self.consume_until_any("<&'");
            self.consume_char('\'')
        } else if self.consume_char('"') {
            self.consume_until_any("<&\"");
            self.consume_char('"')
        } else {
            false
        }
    }

    pub fn consume_char(&mut self, target: char) -> bool {
        match self.peek() {
            Some(c) if c == target => {
                self.next();
                true
            },
            _ => false,
        }
    }

    #[inline]
    pub fn consume_digits(&mut self) -> bool {
        self.consume_while(|c| c >= '0' && c <= '9')
    }

    /// https://www.w3.org/TR/REC-xml/#NT-Eq
    pub fn consume_equality(&mut self) -> bool {
        self.consume_whitespace();
        let consumed = self.consume_char('=');
        self.consume_whitespace();
        consumed
    }

    pub fn consume_if<F>(&mut self, check: F) -> bool where F: Fn(char) -> bool {
        match self.peek() {
            Some(c) => {
                if check(c) {
                    self.next();
                    true
                } else {
                    false
                }
            },
            _ => false,
        }
    }

    /// https://www.w3.org/TR/REC-xml/#NT-Name
    pub fn consume_name(&mut self) -> bool {
        self.consume_name_start_char() && {
            while self.consume_name_char() {}
            true
        }
    }

    /// https://www.w3.org/TR/REC-xml/#NT-NameChar
    pub fn consume_name_char(&mut self) -> bool {
        self.consume_name_start_char() || self.consume_if(|c| {
            match c {
                '-' |
                '.' |
                '0'...'9' |
                '\u{B7}' |
                '\u{0300}'...'\u{036F}' |
                '\u{203F}'...'\u{2040}' => true,
                _ => false,
            }
        })
    }

    /// https://www.w3.org/TR/REC-xml/#NT-NameStartChar
    pub fn consume_name_start_char(&mut self) -> bool {
        self.consume_if(|c| {
            match c {
                ':' |
                'A'...'Z' |
                '_' |
                'a'...'z' |
                '\u{C0}'...'\u{D6}' |
                '\u{D8}'...'\u{F6}' |
                '\u{F8}'...'\u{2FF}' |
                '\u{370}'...'\u{37D}' |
                '\u{37F}'...'\u{1FFF}' |
                '\u{200C}'...'\u{200D}' |
                '\u{2070}'...'\u{218F}' |
                '\u{2C00}'...'\u{2FEF}' |
                '\u{3001}'...'\u{D7FF}' |
                '\u{F900}'...'\u{FDCF}' |
                '\u{FDF0}'...'\u{FFFD}' |
                '\u{10000}'...'\u{EFFFF}' => true,
                _ => false,
            }
        })
    }

    /// https://www.w3.org/TR/SVG/types.html#DataTypeNumber
    pub fn consume_number(&mut self) -> bool {
        self.consume_sign();
        if !self.consume_digits() || self.consume_char('.') && !self.consume_digits() && false {
            return false;
        }
        if !self.consume_char('e') && !self.consume_char('E') {
            return true;
        }
        self.consume_sign();
        self.consume_digits()
    }

    pub fn consume_sign(&mut self) -> bool {
        self.consume_char('+') || self.consume_char('-')
    }

    #[inline]
    pub fn consume_until_any(&mut self, chars: &str) -> bool {
        self.consume_while(|c| !chars.contains(c))
    }

    #[inline]
    pub fn consume_until_char(&mut self, target: char) -> bool {
        self.consume_while(|c| c != target)
    }

    pub fn consume_while<F>(&mut self, check: F) -> bool where F: Fn(char) -> bool {
        let mut consumed = false;
        while self.consume_if(|c| check(c)) {
            consumed = true;
        }
        consumed
    }

    /// https://www.w3.org/TR/REC-xml/#NT-S
    #[inline]
    pub fn consume_whitespace(&mut self) -> bool {
        self.consume_any("\x20\x09\x0D\x0A")
    }

    #[inline]
    pub fn is_done(&self) -> bool {
        self.offset == self.content.len()
    }

    #[inline]
    pub fn peek(&mut self) -> Option<char> {
        self.cursor.peek().and_then(|&c| Some(c))
    }

    #[inline]
    pub fn position(&self) -> (usize, usize) {
        (self.line, self.column)
    }
}

impl<'l> Iterator for Reader<'l> {
    type Item = char;

    fn next(&mut self) -> Option<char> {
        match self.cursor.next() {
            Some(c) => {
                if c == '\n' {
                    self.line += 1;
                    self.column = 1;
                } else {
                    self.column += 1;
                }
                self.offset += 1;
                Some(c)
            }
            _ => None,
        }
    }
}

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

    #[test]
    fn capture() {
        let mut reader = Reader::new("abcdefg");
        reader.consume_any("ab");
        let content = reader.capture(|reader| {
            reader.consume_any("cde")
        });

        assert_eq!(content.unwrap(), "cde");
    }

    #[test]
    fn consume_attribute() {
        macro_rules! test(
            ($content:expr) => ({
                let mut reader = Reader::new($content);
                assert!(reader.consume_attribute());
            });
        );

        test!("foo='bar'");
        test!("foo = \t 'bar'");
        test!("foo= \"bar\"");

        macro_rules! test(
            ($content:expr) => ({
                let mut reader = Reader::new($content);
                assert!(!reader.consume_attribute());
            });
        );

        test!("foo");
        test!("foo bar");
        test!("foo=bar");
        test!("foo='bar");
        test!("foo=\"bar");
    }

    #[test]
    fn consume_name() {
        macro_rules! test(
            ($content:expr, $value:expr) => ({
                let mut reader = Reader::new($content);
                let value = reader.capture(|reader| {
                    reader.consume_name()
                });
                assert_eq!(value.unwrap(), $value);
            });
        );

        test!("foo", "foo");
        test!("foo bar", "foo");
        test!("foo42 bar", "foo42");
        test!("foo-bar baz", "foo-bar");
        test!("foo/", "foo");

        macro_rules! test(
            ($content:expr) => ({
                let mut reader = Reader::new($content);
                assert!(!reader.consume_name());
            });
        );

        test!(" foo");
        test!("!foo");
        test!("<foo");
        test!("?foo");
    }

    #[test]
    fn consume_number() {
        macro_rules! test(
            ($content:expr, $value:expr) => ({
                let mut reader = Reader::new($content);
                let value = reader.capture(|reader| {
                    reader.consume_number()
                });
                assert_eq!(value.unwrap(), $value);
            });
        );

        test!("-1.20", "-1.20");
        test!("+30.4", "+30.4");
        test!("50az", "50");
        test!("6  ", "6");
        test!("1E-4", "1E-4");
        test!("1e4", "1e4");
        test!("-1E2", "-1E2");
        test!("-0.1E2", "-0.1E2");
        test!("-000.10E0200", "-000.10E0200");
    }

    #[test]
    fn consume_whitespace() {
        let mut reader = Reader::new(" \t  \n\n  \tm ");
        reader.consume_whitespace();

        assert_eq!(reader.line, 3);
        assert_eq!(reader.column, 4);
        assert_eq!(reader.offset, 9);
    }
}
<commit_msg>Reject malformed numbers<commit_after>use std::iter::Peekable;
use std::str::Chars;

pub struct Reader<'l> {
    line: usize,
    column: usize,
    offset: usize,
    content: &'l str,
    cursor: Peekable<Chars<'l>>,
}

impl<'l> Reader<'l> {
    #[inline]
    pub fn new(content: &'l str) -> Self {
        Reader {
            line: 1,
            column: 1,
            offset: 0,
            content: content,
            cursor: content.chars().peekable(),
        }
    }

    pub fn capture<F>(&mut self, block: F) -> Option<&'l str>
        where F: Fn(&mut Reader<'l>) -> bool
    {
        let start = self.offset;
        if !block(self) {
            return None;
        }
        let content = &self.content[start..self.offset].trim();
        if content.is_empty() { None } else { Some(content) }
    }

    #[inline]
    pub fn consume_all(&mut self) -> bool {
        self.consume_while(|_| true)
    }

    #[inline]
    pub fn consume_any(&mut self, chars: &str) -> bool {
        self.consume_while(|c| chars.contains(c))
    }

    /// https://www.w3.org/TR/REC-xml/#NT-Attribute
    pub fn consume_attribute(&mut self) -> bool {
        self.consume_name() && self.consume_equality() && self.consume_attribute_value()
    }

    /// https://www.w3.org/TR/REC-xml/#NT-AttValue
    pub fn consume_attribute_value(&mut self) -> bool {
        if self.consume_char('\'') {
            self.consume_until_any("<&'");
            self.consume_char('\'')
        } else if self.consume_char('"') {
            self.consume_until_any("<&\"");
            self.consume_char('"')
        } else {
            false
        }
    }

    pub fn consume_char(&mut self, target: char) -> bool {
        match self.peek() {
            Some(c) if c == target => {
                self.next();
                true
            },
            _ => false,
        }
    }

    #[inline]
    pub fn consume_digits(&mut self) -> bool {
        self.consume_while(|c| c >= '0' && c <= '9')
    }

    /// https://www.w3.org/TR/REC-xml/#NT-Eq
    pub fn consume_equality(&mut self) -> bool {
        self.consume_whitespace();
        let consumed = self.consume_char('=');
        self.consume_whitespace();
        consumed
    }

    pub fn consume_if<F>(&mut self, check: F) -> bool where F: Fn(char) -> bool {
        match self.peek() {
            Some(c) => {
                if check(c) {
                    self.next();
                    true
                } else {
                    false
                }
            },
            _ => false,
        }
    }

    /// https://www.w3.org/TR/REC-xml/#NT-Name
    pub fn consume_name(&mut self) -> bool {
        self.consume_name_start_char() && {
            while self.consume_name_char() {}
            true
        }
    }

    /// https://www.w3.org/TR/REC-xml/#NT-NameChar
    pub fn consume_name_char(&mut self) -> bool {
        self.consume_name_start_char() || self.consume_if(|c| {
            match c {
                '-' |
                '.' |
                '0'...'9' |
                '\u{B7}' |
                '\u{0300}'...'\u{036F}' |
                '\u{203F}'...'\u{2040}' => true,
                _ => false,
            }
        })
    }

    /// https://www.w3.org/TR/REC-xml/#NT-NameStartChar
    pub fn consume_name_start_char(&mut self) -> bool {
        self.consume_if(|c| {
            match c {
                ':' |
                'A'...'Z' |
                '_' |
                'a'...'z' |
                '\u{C0}'...'\u{D6}' |
                '\u{D8}'...'\u{F6}' |
                '\u{F8}'...'\u{2FF}' |
                '\u{370}'...'\u{37D}' |
                '\u{37F}'...'\u{1FFF}' |
                '\u{200C}'...'\u{200D}' |
                '\u{2070}'...'\u{218F}' |
                '\u{2C00}'...'\u{2FEF}' |
                '\u{3001}'...'\u{D7FF}' |
                '\u{F900}'...'\u{FDCF}' |
                '\u{FDF0}'...'\u{FFFD}' |
                '\u{10000}'...'\u{EFFFF}' => true,
                _ => false,
            }
        })
    }

    /// https://www.w3.org/TR/SVG/types.html#DataTypeNumber
    pub fn consume_number(&mut self) -> bool {
        self.consume_sign();
        if !self.consume_digits() || self.consume_char('.') && !self.consume_digits() {
            return false;
        }
        if !self.consume_char('e') && !self.consume_char('E') {
            return true;
        }
        self.consume_sign();
        self.consume_digits()
    }

    pub fn consume_sign(&mut self) -> bool {
        self.consume_char('+') || self.consume_char('-')
    }

    #[inline]
    pub fn consume_until_any(&mut self, chars: &str) -> bool {
        self.consume_while(|c| !chars.contains(c))
    }

    #[inline]
    pub fn consume_until_char(&mut self, target: char) -> bool {
        self.consume_while(|c| c != target)
    }

    pub fn consume_while<F>(&mut self, check: F) -> bool where F: Fn(char) -> bool {
        let mut consumed = false;
        while self.consume_if(|c| check(c)) {
            consumed = true;
        }
        consumed
    }

    /// https://www.w3.org/TR/REC-xml/#NT-S
    #[inline]
    pub fn consume_whitespace(&mut self) -> bool {
        self.consume_any("\x20\x09\x0D\x0A")
    }

    #[inline]
    pub fn is_done(&self) -> bool {
        self.offset == self.content.len()
    }

    #[inline]
    pub fn peek(&mut self) -> Option<char> {
        self.cursor.peek().and_then(|&c| Some(c))
    }

    #[inline]
    pub fn position(&self) -> (usize, usize) {
        (self.line, self.column)
    }
}

impl<'l> Iterator for Reader<'l> {
    type Item = char;

    fn next(&mut self) -> Option<char> {
        match self.cursor.next() {
            Some(c) => {
                if c == '\n' {
                    self.line += 1;
                    self.column = 1;
                } else {
                    self.column += 1;
                }
                self.offset += 1;
                Some(c)
            }
            _ => None,
        }
    }
}

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

    #[test]
    fn capture() {
        let mut reader = Reader::new("abcdefg");
        reader.consume_any("ab");
        let content = reader.capture(|reader| {
            reader.consume_any("cde")
        });

        assert_eq!(content.unwrap(), "cde");
    }

    #[test]
    fn consume_attribute() {
        macro_rules! test(
            ($content:expr) => ({
                let mut reader = Reader::new($content);
                assert!(reader.consume_attribute());
            });
        );

        test!("foo='bar'");
        test!("foo = \t 'bar'");
        test!("foo= \"bar\"");

        macro_rules! test(
            ($content:expr) => ({
                let mut reader = Reader::new($content);
                assert!(!reader.consume_attribute());
            });
        );

        test!("foo");
        test!("foo bar");
        test!("foo=bar");
        test!("foo='bar");
        test!("foo=\"bar");
    }

    #[test]
    fn consume_name() {
        macro_rules! test(
            ($content:expr, $value:expr) => ({
                let mut reader = Reader::new($content);
                let value = reader.capture(|reader| {
                    reader.consume_name()
                });
                assert_eq!(value.unwrap(), $value);
            });
        );

        test!("foo", "foo");
        test!("foo bar", "foo");
        test!("foo42 bar", "foo42");
        test!("foo-bar baz", "foo-bar");
        test!("foo/", "foo");

        macro_rules! test(
            ($content:expr) => ({
                let mut reader = Reader::new($content);
                assert!(!reader.consume_name());
            });
        );

        test!(" foo");
        test!("!foo");
        test!("<foo");
        test!("?foo");
    }

    #[test]
    fn consume_number() {
        macro_rules! test(
            ($content:expr, $value:expr) => ({
                let mut reader = Reader::new($content);
                let value = reader.capture(|reader| {
                    reader.consume_number()
                });
                assert_eq!(value.unwrap(), $value);
            });
        );

        test!("-1.20", "-1.20");
        test!("+30.4", "+30.4");
        test!("50az", "50");
        test!("6  ", "6");
        test!("1E-4", "1E-4");
        test!("1e4", "1e4");
        test!("-1E2", "-1E2");
        test!("-0.1E2", "-0.1E2");
        test!("-000.10E0200", "-000.10E0200");

        macro_rules! test(
            ($content:expr) => ({
                let mut reader = Reader::new($content);
                assert!(reader.capture(|reader| {
                    reader.consume_number()
                }).is_none());
            });
        );

        test!("1.e2");
        test!("-1.e2");
        test!("+1.e2");
    }

    #[test]
    fn consume_whitespace() {
        let mut reader = Reader::new(" \t  \n\n  \tm ");
        reader.consume_whitespace();

        assert_eq!(reader.line, 3);
        assert_eq!(reader.column, 4);
        assert_eq!(reader.offset, 9);
    }
}
<|endoftext|>


<commit_before>use cgmath::{Deg, Rad, perspective};

use gltf;
use gltf::camera::Projection;

use crate::render::math::*;
use crate::controls::{ZOOM};

#[derive(Clone)]
pub struct Camera {
    pub index: usize, // gltf index
    pub name: Option<String>,

    pub projection_matrix: Matrix4,

    pub znear: f32,
    pub zfar: Option<f32>,

    // perspective camera
    // TODO!: setters that update...
    pub fovy: Deg<f32>,
    aspect_ratio: f32,

    // orthographic camera
    pub xmag: Option<f32>,
    pub ymag: Option<f32>,
}

impl Default for Camera {
    fn default() -> Self {
        Camera {
            index: 0,
            name: None,

            znear: 0.01,
            zfar: Some(1000.0),

            fovy: Deg(ZOOM),
            aspect_ratio: 1.0,

            xmag: None,
            ymag: None,

            projection_matrix: Matrix4::zero(),
        }
    }
}

impl Camera {
    pub fn from_gltf(g_camera: &gltf::Camera<'_>) -> Self {
        let mut camera = Camera {
            index: g_camera.index(),
            name: g_camera.name().map(|n| n.to_owned()),
            projection_matrix: Matrix4::zero(),
            znear: 0.0,
            zfar: None,
            fovy: Deg(0.0),
            aspect_ratio: 1.0,
            xmag: None,
            ymag: None,
        };
        match g_camera.projection() {
            Projection::Perspective(persp) => {
                // TODO!!: ignoring aspect ratio for now as it would require window resizing...
                let _aspect = persp.aspect_ratio();
                camera.fovy = Deg::from(Rad(persp.yfov()));
                camera.znear = persp.znear();
                camera.zfar = persp.zfar();
            },
            Projection::Orthographic(ortho) => {
                camera.xmag = Some(ortho.xmag());
                camera.ymag = Some(ortho.ymag());
                camera.znear = ortho.znear();
                camera.zfar = Some(ortho.zfar());
            }
        }
        camera.update_projection_matrix();
        camera
    }

    pub fn update_aspect_ratio(&mut self, aspect_ratio: f32) {
        self.aspect_ratio = aspect_ratio;
        self.update_projection_matrix();
    }

    pub fn aspect_ratio(&self) -> f32 {
        self.aspect_ratio
    }

    pub fn update_projection_matrix(&mut self) {
        if let Some(xmag) = self.xmag {
            // from https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#orthographic-projection
            let r = xmag;
            let t = self.ymag.unwrap();
            let f = self.zfar.unwrap();
            let n = self.znear;
            self.projection_matrix = Matrix4::new(
                1.0/r, 0.0,   0.0,         0.0,   // NOTE: first column!
                0.0,   1.0/t, 0.0,         0.0,   // 2nd
                0.0,   0.0,   2.0/(n-f),   0.0,   // 3rd
                0.0,   0.0,   (f+n)/(n-f), 1.0    // 4th
            );
        } else if let Some(zfar) = self.zfar {
            self.projection_matrix = perspective(
                self.fovy,
                self.aspect_ratio,
                self.znear, zfar)
        } else {
            // from https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#infinite-perspective-projection
            let a = self.aspect_ratio;
            let y = Rad::from(self.fovy).0;
            let n = self.znear;

            self.projection_matrix = Matrix4::new(
                1.0/(a*(0.5*y).tan()), 0.0,               0.0,   0.0, // NOTE: first column!
                0.0,                   1.0/(0.5*y).tan(), 0.0,   0.0,
                0.0,                   0.0,              -1.0,  -1.0,
                0.0,                   0.0,              -2.0*n, 0.0
            );
        }
    }

    pub fn is_perspective(&self) -> bool {
        self.xmag.is_none()
    }

    pub fn description(&self) -> String {
        let type_ = if !self.is_perspective() {
            "ortho"
        } else if self.zfar.is_none() {
            "infinite perspective"
        } else {
            "perspective"
        };

        format!("{} ({:?}, {})", self.index, self.name, type_)
    }
}
<commit_msg>prevent near plane 0 (resolves #54)<commit_after>use cgmath::{Deg, Rad, perspective};

use gltf;
use gltf::camera::Projection;

use crate::render::math::*;
use crate::controls::{ZOOM};

#[derive(Clone)]
pub struct Camera {
    pub index: usize, // gltf index
    pub name: Option<String>,

    pub projection_matrix: Matrix4,

    pub znear: f32,
    pub zfar: Option<f32>,

    // perspective camera
    // TODO!: setters that update...
    pub fovy: Deg<f32>,
    aspect_ratio: f32,

    // orthographic camera
    pub xmag: Option<f32>,
    pub ymag: Option<f32>,
}

impl Default for Camera {
    fn default() -> Self {
        Camera {
            index: 0,
            name: None,

            znear: 0.01,
            zfar: Some(1000.0),

            fovy: Deg(ZOOM),
            aspect_ratio: 1.0,

            xmag: None,
            ymag: None,

            projection_matrix: Matrix4::zero(),
        }
    }
}

impl Camera {
    pub fn from_gltf(g_camera: &gltf::Camera<'_>) -> Self {
        let mut camera = Camera {
            index: g_camera.index(),
            name: g_camera.name().map(|n| n.to_owned()),
            projection_matrix: Matrix4::zero(),
            znear: 0.0,
            zfar: None,
            fovy: Deg(0.0),
            aspect_ratio: 1.0,
            xmag: None,
            ymag: None,
        };
        match g_camera.projection() {
            Projection::Perspective(persp) => {
                // TODO!!: ignoring aspect ratio for now as it would require window resizing...
                let _aspect = persp.aspect_ratio();
                camera.fovy = Deg::from(Rad(persp.yfov()));
                // cgmath asserts znear > 0, but the gltf spec allows it
                camera.znear = persp.znear().max(0.0001);
                camera.zfar = persp.zfar();
            },
            Projection::Orthographic(ortho) => {
                camera.xmag = Some(ortho.xmag());
                camera.ymag = Some(ortho.ymag());
                camera.znear = ortho.znear();
                camera.zfar = Some(ortho.zfar());
            }
        }
        camera.update_projection_matrix();
        camera
    }

    pub fn update_aspect_ratio(&mut self, aspect_ratio: f32) {
        self.aspect_ratio = aspect_ratio;
        self.update_projection_matrix();
    }

    pub fn aspect_ratio(&self) -> f32 {
        self.aspect_ratio
    }

    pub fn update_projection_matrix(&mut self) {
        if let Some(xmag) = self.xmag {
            // from https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#orthographic-projection
            let r = xmag;
            let t = self.ymag.unwrap();
            let f = self.zfar.unwrap();
            let n = self.znear;
            self.projection_matrix = Matrix4::new(
                1.0/r, 0.0,   0.0,         0.0,   // NOTE: first column!
                0.0,   1.0/t, 0.0,         0.0,   // 2nd
                0.0,   0.0,   2.0/(n-f),   0.0,   // 3rd
                0.0,   0.0,   (f+n)/(n-f), 1.0    // 4th
            );
        } else if let Some(zfar) = self.zfar {
            self.projection_matrix = perspective(
                self.fovy,
                self.aspect_ratio,
                self.znear, zfar)
        } else {
            // from https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#infinite-perspective-projection
            let a = self.aspect_ratio;
            let y = Rad::from(self.fovy).0;
            let n = self.znear;

            self.projection_matrix = Matrix4::new(
                1.0/(a*(0.5*y).tan()), 0.0,               0.0,   0.0, // NOTE: first column!
                0.0,                   1.0/(0.5*y).tan(), 0.0,   0.0,
                0.0,                   0.0,              -1.0,  -1.0,
                0.0,                   0.0,              -2.0*n, 0.0
            );
        }
    }

    pub fn is_perspective(&self) -> bool {
        self.xmag.is_none()
    }

    pub fn description(&self) -> String {
        let type_ = if !self.is_perspective() {
            "ortho"
        } else if self.zfar.is_none() {
            "infinite perspective"
        } else {
            "perspective"
        };

        format!("{} ({:?}, {})", self.index, self.name, type_)
    }
}
<|endoftext|>


<commit_before>/// Allow user to define custom functions to be called from libsass.
/// https://github.com/sass/libsass/wiki/Custom-Functions-internal

use sass_value::SassValue;
use sass_sys;
use std::ffi;
use std::mem;

/// Type of the function to be defined by the user.
pub type SassFunction = fn(& SassValue)->SassValue;

/// Dispatcher function called from libsass (C interface).
/// The cookie argument is setup in SassFunctionCallback::from_sig_fn.
/// Note that the SassFunctionCallback is not used directly in the dispatch.
extern "C" fn dispatch(arg1: *const sass_sys::Union_Sass_Value,
                       cookie: *mut ::libc::c_void) -> *mut sass_sys::Union_Sass_Value {
    let _fn :SassFunction = unsafe {mem::transmute(cookie)};
    let result = _fn(&SassValue::from_raw(arg1)).as_raw();
    match result {
        Some(raw) => raw,
        None => SassValue::sass_error("bad call").as_raw().unwrap()
    }

}

/// Associate the signature with the C callback.
#[derive(Debug)]
pub struct SassFunctionCallback {
    pub signature: String,
    pub c_callback:sass_sys::Sass_C_Function_Callback
}

impl SassFunctionCallback {
    /// Create the C callback structure used by libsass.
    pub fn make_sass_c_callback(signature:&str,_fn:SassFunction) -> sass_sys::Sass_C_Function_Callback {
        let c_sig = ffi::CString::new(signature).unwrap();
        unsafe {sass_sys::sass_make_function(c_sig.as_ptr(), Some(dispatch), mem::transmute(_fn))}
    }

    /// Build a SassFunctionCallback.
    pub fn from_sig_fn(signature:String,_fn:SassFunction) -> SassFunctionCallback {
        let cb = SassFunctionCallback::make_sass_c_callback(&signature,_fn);
        SassFunctionCallback {
            signature: signature,
            c_callback: cb
        }
    }

}
<commit_msg>Use transmute to stop rust from freeing mem<commit_after>/// Allow user to define custom functions to be called from libsass.
/// https://github.com/sass/libsass/wiki/Custom-Functions-internal

use sass_value::SassValue;
use sass_sys;
use std::ffi;
use std::mem;

/// Type of the function to be defined by the user.
pub type SassFunction = fn(& SassValue)->SassValue;

/// Dispatcher function called from libsass (C interface).
/// The cookie argument is setup in SassFunctionCallback::from_sig_fn.
/// Note that the SassFunctionCallback is not used directly in the dispatch.
extern "C" fn dispatch(arg1: *const sass_sys::Union_Sass_Value,
                       cookie: *mut ::libc::c_void) -> *mut sass_sys::Union_Sass_Value {
    let _fn :SassFunction = unsafe {mem::transmute(cookie)};
    let result = _fn(&SassValue::from_raw(arg1)).as_raw();
    match result {
        Some(raw) => raw,
        None => SassValue::sass_error("bad call").as_raw().unwrap()
    }

}

/// Associate the signature with the C callback.
#[derive(Debug)]
pub struct SassFunctionCallback {
    pub signature: String,
    pub c_callback:sass_sys::Sass_C_Function_Callback
}

impl SassFunctionCallback {
    /// Create the C callback structure used by libsass.
    pub fn make_sass_c_callback(signature:&str,_fn:SassFunction) -> sass_sys::Sass_C_Function_Callback {
        // NOTE: this generates a memory leak.
        let boxed = Box::new(ffi::CString::new(signature).unwrap());

        unsafe {
            // move the value outside the rust memory management model
            let c_sig: *const ffi::CString = mem::transmute(boxed);

            // use
            sass_sys::sass_make_function((&*c_sig).as_ptr(), Some(dispatch), mem::transmute(_fn))
        }
    }

    /// Build a SassFunctionCallback.
    pub fn from_sig_fn(signature:String,_fn:SassFunction) -> SassFunctionCallback {
        let cb = SassFunctionCallback::make_sass_c_callback(&signature,_fn);
        SassFunctionCallback {
            signature: signature,
            c_callback: cb
        }
    }

}
<|endoftext|>


<commit_before>use log;
use core::fmt;
use collections::String;

const PORT: u16 = 0x3f8;

#[derive(Default)]
pub struct SerialLogger(());

fn outw(port: u16, data: u16) {
    unsafe {
        asm!("outw %ax, %dx" : : "{dx}" (port as u16), "{ax}" (data));
    }
}

fn outb(port: u16, data: u8) {
    unsafe {
        asm!("outb %al, %dx" : : "{dx}" (port as u16), "{al}" (data));
    }
}

fn inb(port: u16) -> u8 {
    let data: u8;
    unsafe {
        asm!("inb %dx, %al" : "={al}"(data) : "{dx}"(port as u16));
    }
    data
}

impl fmt::Write for SerialLogger {
    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
        for c in s.chars() {
            while (inb(PORT + 5) & 0x20) == 0 {}
            outb(PORT, c as u8);
        }
        Ok(())
    }
}

pub fn write_static(s: &'static str) {
    for c in s.chars() {
        while (inb(PORT + 5) & 0x20) == 0 {}
        outb(PORT, c as u8);
    }
}

impl SerialLogger {
    fn init(&self) {
        outw(PORT + 1, 0x00);
        outw(PORT + 3, 0x80);
        outw(PORT, 0x01);
        outw(PORT + 1, 0x00);
        outw(PORT + 3, 0x03);
        outw(PORT + 2, 0xc7);
        outw(PORT + 4, 0x0b);
        outw(PORT + 1, 0x01);
    }

    fn write_string(&self, s: String) {
        for c in s.chars() {
            while (inb(PORT + 5) & 0x20) == 0 {}
            outb(PORT, c as u8);
        }
    }
}

impl log::Log for SerialLogger {
    fn enabled(&self, metadata: &log::LogMetadata) -> bool {
        metadata.level() <= log::LogLevel::Info
    }

    fn log(&self, record: &log::LogRecord) {
        if self.enabled(record.metadata()) {
            let log_message = format!("{}: {}\n", record.level(), record.args());
            self.write_string(log_message);
        }
    }
}

pub fn init() -> Result<(), log::SetLoggerError> {
    unsafe {
        log::set_logger_raw(|max_log_level| {
            static LOGGER: SerialLogger = SerialLogger(());
            LOGGER.init();
            max_log_level.set(log::LogLevelFilter::Debug);
            &LOGGER
        })
    }
}

pub fn fini() -> Result<(), log::ShutdownLoggerError> {
    log::shutdown_logger_raw().map(|_logger| {})
}
<commit_msg>Refactor serial logger to not use String<commit_after>use log;
//#[macro_use]
use core::fmt;
use core::fmt::Write;
use spin:: Mutex;

const PORT: u16 = 0x3f8;

#[derive(Default)]
pub struct SerialPort;

#[derive(Default)]
pub struct SerialLogger;

static SERIAL_PORT_MUTEX: Mutex<SerialPort> = Mutex::new(SerialPort);

fn outw(port: u16, data: u16) {
    unsafe {
        asm!("outw %ax, %dx" : : "{dx}" (port as u16), "{ax}" (data));
    }
}

fn outb(port: u16, data: u8) {
    unsafe {
        asm!("outb %al, %dx" : : "{dx}" (port as u16), "{al}" (data));
    }
}

fn inb(port: u16) -> u8 {
    let data: u8;
    unsafe {
        asm!("inb %dx, %al" : "={al}"(data) : "{dx}"(port as u16));
    }
    data
}

impl fmt::Write for SerialPort {
    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
        for c in s.chars() {
            while (inb(PORT + 5) & 0x20) == 0 {}
            outb(PORT, c as u8);
        }
        Ok(())
    }
}

impl fmt::Write for SerialLogger {
    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
        SERIAL_PORT_MUTEX.lock().write_str(s)
    }
}

impl SerialLogger {
    fn init(&self) {
        outw(PORT + 1, 0x00);
        outw(PORT + 3, 0x80);
        outw(PORT, 0x01);
        outw(PORT + 1, 0x00);
        outw(PORT + 3, 0x03);
        outw(PORT + 2, 0xc7);
        outw(PORT + 4, 0x0b);
        outw(PORT + 1, 0x01);
    }
}

impl log::Log for SerialLogger {
    fn enabled(&self, metadata: &log::LogMetadata) -> bool {
        metadata.level() <= log::LogLevel::Info
    }

    fn log(&self, record: &log::LogRecord) {
        if self.enabled(record.metadata()) {
            let _ = write!(SERIAL_PORT_MUTEX.lock(), "{}: {}\n", record.level(), record.args());
        }
    }
}

pub fn init() -> Result<(), log::SetLoggerError> {
    unsafe {
        log::set_logger_raw(|max_log_level| {
            static LOGGER: SerialLogger = SerialLogger;
            LOGGER.init();
            max_log_level.set(log::LogLevelFilter::Debug);
            &LOGGER
        })
    }
}

pub fn fini() -> Result<(), log::ShutdownLoggerError> {
    log::shutdown_logger_raw().map(|_logger| {})
}
<|endoftext|>


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

//!
//! A symbol reader reads one symbol at a time from a source
//!

use std::slice::Iter;
use std::io::Read;
use std::io::Bytes;
use std::str::Chars;

///
/// A symbol reader reads one symbol at a time from a source
///
pub trait SymbolReader<Symbol> {
    ///
    /// Reads the next symbol from this reader
    ///
    fn next_symbol(&mut self) -> Option<Symbol>;
}

///
/// Trait that can be implemented by things that can construct a symbol reader
///
pub trait SymbolSource<'a, Symbol> {
    /// The type of symbol reader that will be generated by this call
    type SymbolReader: SymbolReader<Symbol>+'a;

    /// Returns a new object that can read the symbols from this one
    fn read_symbols(self) -> Self::SymbolReader;
}

impl<'a, Symbol: Clone+'a> SymbolSource<'a, Symbol> for &'a Vec<Symbol> {
    type SymbolReader = Iter<'a, Symbol>;

    fn read_symbols(self) -> Self::SymbolReader {
        self.iter()
    }
}

impl<'a, Symbol: Clone+'a> SymbolReader<Symbol> for Iter<'a, Symbol> {
    fn next_symbol(&mut self) -> Option<Symbol> {
        if let Some(sym) = self.next() {
            Some(sym.clone())
        } else {
            None
        }
    }
}

// Can read from streams

//
// TODO: implementing SymbolSource for Read would be nice
// It's just a matter of calling bytes() on the appropriate type, but Rust's type system is simultaneously too clever and not clever enough
// to allow that in any sensible way. You can't do it an an arbitrary Read because the Bytes object is not sized without knowing its real
// type; I couldn't figure out a trick using the Self type to get around that, though those do work sometimes.
// `impl<X: Read> SymbolReader for X` sounds like a nice idea but Rust thinks X can be anything and won't allow any other implementations
// of the interface, which makes that useless too.
// Screwing around with lifetimes and references like below seems like it should work, but Rust doesn't seem to see the implementations on
// actual streams.
//

/*
impl<'a> SymbolSource<'a, u8> for &'a mut Read {
    type SymbolReader = ByteSymbolReader<Self>;

    fn read_symbols(self) -> Self::SymbolReader {
        ByteSymbolReader::new(self.bytes())
    }
}

impl<'a> SymbolSource<'a, u8> for &'a mut BufRead {
    type SymbolReader = ByteSymbolReader<Self>;

    fn read_symbols(self) -> Self::SymbolReader {
        ByteSymbolReader::new(self.bytes())
    }
}
*/

///
/// The ByteSymbolReader turns a `std::io::Bytes` object into a symbol reader
///
pub struct ByteSymbolReader<Reader: Read> {
    bytes: Bytes<Reader>
}

impl<Reader: Read> ByteSymbolReader<Reader> {
    pub fn new(bytes: Bytes<Reader>) -> ByteSymbolReader<Reader> {
        ByteSymbolReader { bytes: bytes }
    }

    pub fn from(reader: Reader) -> ByteSymbolReader<Reader> {
        Self::new(reader.bytes())
    }
}

impl<Reader: Read> SymbolReader<u8> for ByteSymbolReader<Reader> {
    fn next_symbol(&mut self) -> Option<u8> {
        if let Some(Ok(sym)) = self.bytes.next() {
            Some(sym.clone())
        } else {
            None
        }
    }
}

//
// Can read from strings
//
impl<'a> SymbolSource<'a, char> for &'a str {
    type SymbolReader = Chars<'a>;

    fn read_symbols(self) -> Self::SymbolReader {
        self.chars()
    }
}

impl<'a> SymbolReader<char> for Chars<'a> {
    fn next_symbol(&mut self) -> Option<char> {
        self.next()
    }
}

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

    #[test]
    fn can_read_from_vec() {
        let source      = vec![1, 2, 3];
        let mut reader  = source.read_symbols();

        assert!(reader.next_symbol() == Some(1));
        assert!(reader.next_symbol() == Some(2));
        assert!(reader.next_symbol() == Some(3));
        assert!(reader.next_symbol() == None);
    }

    #[test]
    fn can_read_from_bytes_reader() {
        let array: [u8; 3] = [1, 2, 3];
        let slice = &array[..];
        let mut reader = ByteSymbolReader::from(slice);

        assert!(reader.next_symbol() == Some(1));
        assert!(reader.next_symbol() == Some(2));
        assert!(reader.next_symbol() == Some(3));
        assert!(reader.next_symbol() == None);
    }

    #[test]
    fn can_read_from_string_reader() {
        let mut reader = "abc".read_symbols();

        assert!(reader.next_symbol() == Some('a'));
        assert!(reader.next_symbol() == Some('b'));
        assert!(reader.next_symbol() == Some('c'));
        assert!(reader.next_symbol() == None);
    }
}
<commit_msg>Add a way to convert the contents of a symbol reader straight to a vec<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! A symbol reader reads one symbol at a time from a source
//!

use std::slice::Iter;
use std::io::Read;
use std::io::Bytes;
use std::str::Chars;

///
/// A symbol reader reads one symbol at a time from a source
///
pub trait SymbolReader<Symbol> {
    ///
    /// Reads the next symbol from this reader
    ///
    fn next_symbol(&mut self) -> Option<Symbol>;
}

///
/// Trait that can be implemented by things that can construct a symbol reader
///
pub trait SymbolSource<'a, Symbol> {
    /// The type of symbol reader that will be generated by this call
    type SymbolReader: SymbolReader<Symbol>+'a;

    /// Returns a new object that can read the symbols from this one
    fn read_symbols(self) -> Self::SymbolReader;
}

impl<'a, Symbol: Clone+'a> SymbolSource<'a, Symbol> for &'a Vec<Symbol> {
    type SymbolReader = Iter<'a, Symbol>;

    fn read_symbols(self) -> Self::SymbolReader {
        self.iter()
    }
}

impl<'a, Symbol: Clone+'a> SymbolReader<Symbol> for Iter<'a, Symbol> {
    fn next_symbol(&mut self) -> Option<Symbol> {
        if let Some(sym) = self.next() {
            Some(sym.clone())
        } else {
            None
        }
    }
}

// Can read from streams

//
// TODO: implementing SymbolSource for Read would be nice
// It's just a matter of calling bytes() on the appropriate type, but Rust's type system is simultaneously too clever and not clever enough
// to allow that in any sensible way. You can't do it an an arbitrary Read because the Bytes object is not sized without knowing its real
// type; I couldn't figure out a trick using the Self type to get around that, though those do work sometimes.
// `impl<X: Read> SymbolReader for X` sounds like a nice idea but Rust thinks X can be anything and won't allow any other implementations
// of the interface, which makes that useless too.
// Screwing around with lifetimes and references like below seems like it should work, but Rust doesn't seem to see the implementations on
// actual streams.
//

/*
impl<'a> SymbolSource<'a, u8> for &'a mut Read {
    type SymbolReader = ByteSymbolReader<Self>;

    fn read_symbols(self) -> Self::SymbolReader {
        ByteSymbolReader::new(self.bytes())
    }
}

impl<'a> SymbolSource<'a, u8> for &'a mut BufRead {
    type SymbolReader = ByteSymbolReader<Self>;

    fn read_symbols(self) -> Self::SymbolReader {
        ByteSymbolReader::new(self.bytes())
    }
}
*/

///
/// The ByteSymbolReader turns a `std::io::Bytes` object into a symbol reader
///
pub struct ByteSymbolReader<Reader: Read> {
    bytes: Bytes<Reader>
}

impl<Reader: Read> ByteSymbolReader<Reader> {
    pub fn new(bytes: Bytes<Reader>) -> ByteSymbolReader<Reader> {
        ByteSymbolReader { bytes: bytes }
    }

    pub fn from(reader: Reader) -> ByteSymbolReader<Reader> {
        Self::new(reader.bytes())
    }
}

impl<Reader: Read> SymbolReader<u8> for ByteSymbolReader<Reader> {
    fn next_symbol(&mut self) -> Option<u8> {
        if let Some(Ok(sym)) = self.bytes.next() {
            Some(sym.clone())
        } else {
            None
        }
    }
}

//
// Can read from strings
//
impl<'a> SymbolSource<'a, char> for &'a str {
    type SymbolReader = Chars<'a>;

    fn read_symbols(self) -> Self::SymbolReader {
        self.chars()
    }
}

impl<'a> SymbolReader<char> for Chars<'a> {
    fn next_symbol(&mut self) -> Option<char> {
        self.next()
    }
}

//
// Can convert symbol streams to vectors
//
pub trait ReaderToVector<Symbol> {
    /// Reads every symbol in this object and returns a vector
    fn to_vec(&mut self) -> Vec<Symbol>;
}

impl<Symbol, Reader: SymbolReader<Symbol>> ReaderToVector<Symbol> for Reader {
    #[inline]
    fn to_vec(&mut self) -> Vec<Symbol> {
        let mut result = vec![];

        while let Some(symbol) = self.next_symbol() {
            result.push(symbol);
        }

        result
    }
}

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

    #[test]
    fn can_read_from_vec() {
        let source      = vec![1, 2, 3];
        let mut reader  = source.read_symbols();

        assert!(reader.next_symbol() == Some(1));
        assert!(reader.next_symbol() == Some(2));
        assert!(reader.next_symbol() == Some(3));
        assert!(reader.next_symbol() == None);
    }

    #[test]
    fn can_convert_to_vec() {
        let source      = vec![1, 2, 3];
        let mut reader  = source.read_symbols();
        let result      = reader.to_vec();

        assert!(result == vec![1, 2, 3]);
    }

    #[test]
    fn can_read_from_bytes_reader() {
        let array: [u8; 3] = [1, 2, 3];
        let slice = &array[..];
        let mut reader = ByteSymbolReader::from(slice);

        assert!(reader.next_symbol() == Some(1));
        assert!(reader.next_symbol() == Some(2));
        assert!(reader.next_symbol() == Some(3));
        assert!(reader.next_symbol() == None);
    }

    #[test]
    fn can_read_from_string_reader() {
        let mut reader = "abc".read_symbols();

        assert!(reader.next_symbol() == Some('a'));
        assert!(reader.next_symbol() == Some('b'));
        assert!(reader.next_symbol() == Some('c'));
        assert!(reader.next_symbol() == None);
    }
}
<|endoftext|>


<commit_before>use crate::lib::*;

#[cfg(feature = "std")]
use parking_lot::Mutex;

#[cfg(not(feature = "std"))]
use spin::Mutex;

#[derive(Clone)]
/// Wraps the atomic operations on a Decider's state in a threadsafe
/// fashion.
pub(crate) struct ThreadsafeWrapper<T>
where
    T: fmt::Debug + Default + Clone + PartialEq + Eq,
{
    data: Arc<Mutex<T>>,
}

impl<T> Default for ThreadsafeWrapper<T>
where
    T: fmt::Debug + Default + Clone + PartialEq + Eq,
{
    fn default() -> Self {
        ThreadsafeWrapper {
            data: Arc::new(Mutex::new(T::default())),
        }
    }
}

impl<T> PartialEq<Self> for ThreadsafeWrapper<T>
where
    T: fmt::Debug + Default + Clone + PartialEq + Eq,
{
    fn eq(&self, other: &Self) -> bool {
        let mine = self.data.lock();
        let other = other.data.lock();
        *other == *mine
    }
}

impl<T> Eq for ThreadsafeWrapper<T> where T: fmt::Debug + Default + Clone + PartialEq + Eq {}

impl<T> fmt::Debug for ThreadsafeWrapper<T>
where
    T: fmt::Debug + Default + Clone + PartialEq + Eq,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let data = self.data.lock();
        data.fmt(f)
    }
}

#[cfg(feature = "std")]
mod std {
    use super::*;
    use evmap::ShallowCopy;

    impl<T> ShallowCopy for ThreadsafeWrapper<T>
    where
        T: fmt::Debug + Default + Clone + PartialEq + Eq,
    {
        unsafe fn shallow_copy(&mut self) -> Self {
            ThreadsafeWrapper {
                data: self.data.shallow_copy(),
            }
        }
    }
}

impl<T> ThreadsafeWrapper<T>
where
    T: fmt::Debug + Default + Clone + PartialEq + Eq,
{
    #[inline]
    /// Wraps retrieving a bucket's data, calls a function to make a
    /// decision and return a new state, and then tries to set the
    /// state on the bucket.
    ///
    /// This function can loop and call the decision closure again if
    /// the bucket state couldn't be set.
    ///
    /// # Panics
    /// Panics if an error occurs in acquiring any locks.
    pub(crate) fn measure_and_replace<F, E>(&self, f: F) -> Result<(), E>
    where
        F: Fn(&T) -> (Result<(), E>, Option<T>),
    {
        let mut data = self.data.lock();
        let (decision, new_data) = f(&*data);
        if let Some(new_data) = new_data {
            *data = new_data;
        }
        decision
    }

    /// Retrieves and returns a snapshot of the bucket state. This
    /// isn't thread safe, but can be used to restore an old copy of
    /// the bucket if necessary.
    ///
    /// # Thread safety
    /// This function operates threadsafely, but you're literally
    /// taking a copy of data that will change. Relying on the data
    /// that is returned *will* race.
    pub(crate) fn snapshot(&self) -> T {
        let data = self.data.lock();
        data.clone()
    }
}
<commit_msg>ThreadsafeWrapper: fix deadlock caused by comparing with itself<commit_after>use crate::lib::*;

#[cfg(feature = "std")]
use parking_lot::Mutex;

#[cfg(not(feature = "std"))]
use spin::Mutex;

#[derive(Clone)]
/// Wraps the atomic operations on a Decider's state in a threadsafe
/// fashion.
pub(crate) struct ThreadsafeWrapper<T>
where
    T: fmt::Debug + Default + Clone + PartialEq + Eq,
{
    data: Arc<Mutex<T>>,
}

impl<T> Default for ThreadsafeWrapper<T>
where
    T: fmt::Debug + Default + Clone + PartialEq + Eq,
{
    fn default() -> Self {
        ThreadsafeWrapper {
            data: Arc::new(Mutex::new(T::default())),
        }
    }
}

impl<T> PartialEq<Self> for ThreadsafeWrapper<T>
where
    T: fmt::Debug + Default + Clone + PartialEq + Eq,
{
    fn eq(&self, other: &Self) -> bool {
        if self as *const _ == other as *const _ {
            return true;
        }
        let mine = self.data.lock();
        let other = other.data.lock();
        *other == *mine
    }
}

impl<T> Eq for ThreadsafeWrapper<T> where T: fmt::Debug + Default + Clone + PartialEq + Eq {}

impl<T> fmt::Debug for ThreadsafeWrapper<T>
where
    T: fmt::Debug + Default + Clone + PartialEq + Eq,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let data = self.data.lock();
        data.fmt(f)
    }
}

#[cfg(feature = "std")]
mod std {
    use super::*;
    use evmap::ShallowCopy;

    impl<T> ShallowCopy for ThreadsafeWrapper<T>
    where
        T: fmt::Debug + Default + Clone + PartialEq + Eq,
    {
        unsafe fn shallow_copy(&mut self) -> Self {
            ThreadsafeWrapper {
                data: self.data.shallow_copy(),
            }
        }
    }
}

impl<T> ThreadsafeWrapper<T>
where
    T: fmt::Debug + Default + Clone + PartialEq + Eq,
{
    #[inline]
    /// Wraps retrieving a bucket's data, calls a function to make a
    /// decision and return a new state, and then tries to set the
    /// state on the bucket.
    ///
    /// This function can loop and call the decision closure again if
    /// the bucket state couldn't be set.
    ///
    /// # Panics
    /// Panics if an error occurs in acquiring any locks.
    pub(crate) fn measure_and_replace<F, E>(&self, f: F) -> Result<(), E>
    where
        F: Fn(&T) -> (Result<(), E>, Option<T>),
    {
        let mut data = self.data.lock();
        let (decision, new_data) = f(&*data);
        if let Some(new_data) = new_data {
            *data = new_data;
        }
        decision
    }

    /// Retrieves and returns a snapshot of the bucket state. This
    /// isn't thread safe, but can be used to restore an old copy of
    /// the bucket if necessary.
    ///
    /// # Thread safety
    /// This function operates threadsafely, but you're literally
    /// taking a copy of data that will change. Relying on the data
    /// that is returned *will* race.
    pub(crate) fn snapshot(&self) -> T {
        let data = self.data.lock();
        data.clone()
    }
}
<|endoftext|>