<commit_before>use super::{c32, c64};
use super::aligned_vec::AlignedVec;
use super::enums::*;
use super::util::FFTW_MUTEX;
use ffi;

use std::os::raw::c_void;
use std::ptr::null;

pub enum RawPlan {
    _64(ffi::fftw_plan),
    _32(ffi::fftwf_plan),
}

impl RawPlan {
    pub unsafe fn execute(&self) {
        self.null_check();
        match *self {
            RawPlan::_64(p) => ffi::fftw_execute(p),
            RawPlan::_32(p) => ffi::fftwf_execute(p),
        }
    }

    fn null_check(&self) {
        let p = match *self {
            RawPlan::_64(p) => p as *const c_void,
            RawPlan::_32(p) => p as *const c_void,
        };
        if p == null() {
            panic!(
                "Plan is NULL. If you use MKL binding, check here: https://software.intel.com/en-us/mkl-developer-reference-c-using-fftw3-wrappers"
            );
        }
    }
}

impl Drop for RawPlan {
    fn drop(&mut self) {
        self.null_check();
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe {
            match *self {
                RawPlan::_64(p) => ffi::fftw_destroy_plan(p),
                RawPlan::_32(p) => ffi::fftwf_destroy_plan(p),
            }
        }
    }
}

pub trait R2R: Sized {
    unsafe fn r2r_1d(n: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, R2R_KIND, FLAG) -> RawPlan;
    unsafe fn r2r_2d(
        n0: usize,
        n1: usize,
        in_: &mut AlignedVec<Self>,
        out: &mut AlignedVec<Self>,
        R2R_KIND,
        R2R_KIND,
        FLAG,
    ) -> RawPlan;
    unsafe fn r2r_3d(
        n0: usize,
        n1: usize,
        n2: usize,
        in_: &mut AlignedVec<Self>,
        out: &mut AlignedVec<Self>,
        R2R_KIND,
        R2R_KIND,
        R2R_KIND,
        FLAG,
    ) -> RawPlan;
}
pub trait C2C: Sized {
    unsafe fn c2c_1d(n: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, SIGN, FLAG) -> RawPlan;
    unsafe fn c2c_2d(
        n0: usize,
        n1: usize,
        in_: &mut AlignedVec<Self>,
        out: &mut AlignedVec<Self>,
        SIGN,
        FLAG,
    ) -> RawPlan;
    unsafe fn c2c_3d(
        n0: usize,
        n1: usize,
        n2: usize,
        in_: &mut AlignedVec<Self>,
        out: &mut AlignedVec<Self>,
        SIGN,
        FLAG,
    ) -> RawPlan;
}

pub trait C2R {
    type Real: Sized;
    type Complex: Sized;
    unsafe fn r2c_1d(n: usize, in_: &mut AlignedVec<Self::Real>, out: &mut AlignedVec<Self::Complex>, FLAG) -> RawPlan;
    unsafe fn c2r_1d(n: usize, in_: &mut AlignedVec<Self::Complex>, out: &mut AlignedVec<Self::Real>, FLAG) -> RawPlan;
    unsafe fn r2c_2d(
        n0: usize,
        n1: usize,
        in_: &mut AlignedVec<Self::Real>,
        out: &mut AlignedVec<Self::Complex>,
        FLAG,
    ) -> RawPlan;
    unsafe fn c2r_2d(
        n0: usize,
        n1: usize,
        in_: &mut AlignedVec<Self::Complex>,
        out: &mut AlignedVec<Self::Real>,
        FLAG,
    ) -> RawPlan;
    unsafe fn r2c_3d(
        n0: usize,
        n1: usize,
        n2: usize,
        in_: &mut AlignedVec<Self::Real>,
        out: &mut AlignedVec<Self::Complex>,
        FLAG,
    ) -> RawPlan;
    unsafe fn c2r_3d(
        n0: usize,
        n1: usize,
        n2: usize,
        in_: &mut AlignedVec<Self::Complex>,
        out: &mut AlignedVec<Self::Real>,
        FLAG,
    ) -> RawPlan;
}

macro_rules! impl_plan_create {
    ($bit:ident, $float:ty, $complex:ty,
     $r2r_1d:ident, $r2c_1d:ident, $c2r_1d:ident, $c2c_1d:ident,
     $r2r_2d:ident, $r2c_2d:ident, $c2r_2d:ident, $c2c_2d:ident,
     $r2r_3d:ident, $r2c_3d:ident, $c2r_3d:ident, $c2c_3d:ident) => {

impl R2R for $float {
    unsafe fn r2r_1d(n: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, kind: R2R_KIND, flag: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2r_1d(n as i32, in_.as_mut_ptr(), out.as_mut_ptr(), kind, flag as u32))
    }
    unsafe fn r2r_2d(n0: usize, n1: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, k0: R2R_KIND, k1: R2R_KIND, flag: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2r_2d(n0 as i32, n1 as i32, in_.as_mut_ptr(), out.as_mut_ptr(), k0, k1, flag as u32))
    }
    unsafe fn r2r_3d(n0: usize, n1: usize, n2: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, k0: R2R_KIND, k1: R2R_KIND, k2: R2R_KIND, flag: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2r_3d(n0 as i32, n1 as i32, n2 as i32, in_.as_mut_ptr(), out.as_mut_ptr(), k0, k1, k2, flag as u32))
    }
}

impl C2C for $complex {
    unsafe fn c2c_1d(n: usize, i: &mut AlignedVec<Self>, o: &mut AlignedVec<Self>, s: SIGN, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2c_1d(n as i32, i.as_mut_ptr(), o.as_mut_ptr(), s as i32, f as u32))
    }
    unsafe fn c2c_2d(n0: usize, n1: usize, i: &mut AlignedVec<Self>, o: &mut AlignedVec<Self>, s: SIGN, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2c_2d(n0 as i32, n1 as i32, i.as_mut_ptr(), o.as_mut_ptr(), s as i32, f as u32))
    }
    unsafe fn c2c_3d(n0: usize, n1: usize, n2: usize, i: &mut AlignedVec<Self>, o: &mut AlignedVec<Self>, s: SIGN, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2c_3d(n0 as i32, n1 as i32, n2 as i32, i.as_mut_ptr(), o.as_mut_ptr(), s as i32, f as u32))
    }
}

impl C2R for ($complex, $float) {
    type Real = $float;
    type Complex = $complex;
    unsafe fn r2c_1d(n: usize, i: &mut AlignedVec<Self::Real>, o: &mut AlignedVec<Self::Complex>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2c_1d(n as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn c2r_1d(n: usize, i: &mut AlignedVec<Self::Complex>, o: &mut AlignedVec<Self::Real>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2r_1d(n as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn r2c_2d(n0: usize, n1: usize, i: &mut AlignedVec<Self::Real>, o: &mut AlignedVec<Self::Complex>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2c_2d(n0 as i32, n1 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn c2r_2d(n0: usize, n1: usize, i: &mut AlignedVec<Self::Complex>, o: &mut AlignedVec<Self::Real>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2r_2d(n0 as i32, n1 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn r2c_3d(n0: usize, n1: usize, n2: usize, i: &mut AlignedVec<Self::Real>, o: &mut AlignedVec<Self::Complex>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2c_3d(n0 as i32, n1 as i32, n2 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn c2r_3d(n0: usize, n1: usize, n2: usize, i: &mut AlignedVec<Self::Complex>, o: &mut AlignedVec<Self::Real>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2r_3d(n0 as i32, n1 as i32, n2 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
}

}} // impl_plan_create

impl_plan_create!(
    _64,
    f64,
    c64,
    fftw_plan_r2r_1d,
    fftw_plan_dft_r2c_1d,
    fftw_plan_dft_c2r_1d,
    fftw_plan_dft_1d,
    fftw_plan_r2r_2d,
    fftw_plan_dft_r2c_2d,
    fftw_plan_dft_c2r_2d,
    fftw_plan_dft_2d,
    fftw_plan_r2r_3d,
    fftw_plan_dft_r2c_3d,
    fftw_plan_dft_c2r_3d,
    fftw_plan_dft_3d
);
impl_plan_create!(
    _32,
    f32,
    c32,
    fftwf_plan_r2r_1d,
    fftwf_plan_dft_r2c_1d,
    fftwf_plan_dft_c2r_1d,
    fftwf_plan_dft_1d,
    fftwf_plan_r2r_2d,
    fftwf_plan_dft_r2c_2d,
    fftwf_plan_dft_c2r_2d,
    fftwf_plan_dft_2d,
    fftwf_plan_r2r_3d,
    fftwf_plan_dft_r2c_3d,
    fftwf_plan_dft_c2r_3d,
    fftwf_plan_dft_3d
);
<commit_msg>Rename null_check -> is_null<commit_after>use super::{c32, c64};
use super::aligned_vec::AlignedVec;
use super::enums::*;
use super::util::FFTW_MUTEX;
use ffi;

use std::os::raw::c_void;
use std::ptr::null;

pub enum RawPlan {
    _64(ffi::fftw_plan),
    _32(ffi::fftwf_plan),
}

impl RawPlan {
    pub unsafe fn execute(&self) {
        if self.is_null() {
            panic!("Plan is NULL");
        }
        match *self {
            RawPlan::_64(p) => ffi::fftw_execute(p),
            RawPlan::_32(p) => ffi::fftwf_execute(p),
        }
    }

    pub fn is_null(&self) -> bool {
        let p = match *self {
            RawPlan::_64(p) => p as *const c_void,
            RawPlan::_32(p) => p as *const c_void,
        };
        p == null()
    }
}

impl Drop for RawPlan {
    fn drop(&mut self) {
        if self.is_null() {
            // TODO warning
            return;
        }
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe {
            match *self {
                RawPlan::_64(p) => ffi::fftw_destroy_plan(p),
                RawPlan::_32(p) => ffi::fftwf_destroy_plan(p),
            }
        }
    }
}

pub trait R2R: Sized {
    unsafe fn r2r_1d(n: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, R2R_KIND, FLAG) -> RawPlan;
    unsafe fn r2r_2d(
        n0: usize,
        n1: usize,
        in_: &mut AlignedVec<Self>,
        out: &mut AlignedVec<Self>,
        R2R_KIND,
        R2R_KIND,
        FLAG,
    ) -> RawPlan;
    unsafe fn r2r_3d(
        n0: usize,
        n1: usize,
        n2: usize,
        in_: &mut AlignedVec<Self>,
        out: &mut AlignedVec<Self>,
        R2R_KIND,
        R2R_KIND,
        R2R_KIND,
        FLAG,
    ) -> RawPlan;
}
pub trait C2C: Sized {
    unsafe fn c2c_1d(n: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, SIGN, FLAG) -> RawPlan;
    unsafe fn c2c_2d(
        n0: usize,
        n1: usize,
        in_: &mut AlignedVec<Self>,
        out: &mut AlignedVec<Self>,
        SIGN,
        FLAG,
    ) -> RawPlan;
    unsafe fn c2c_3d(
        n0: usize,
        n1: usize,
        n2: usize,
        in_: &mut AlignedVec<Self>,
        out: &mut AlignedVec<Self>,
        SIGN,
        FLAG,
    ) -> RawPlan;
}

pub trait C2R {
    type Real: Sized;
    type Complex: Sized;
    unsafe fn r2c_1d(n: usize, in_: &mut AlignedVec<Self::Real>, out: &mut AlignedVec<Self::Complex>, FLAG) -> RawPlan;
    unsafe fn c2r_1d(n: usize, in_: &mut AlignedVec<Self::Complex>, out: &mut AlignedVec<Self::Real>, FLAG) -> RawPlan;
    unsafe fn r2c_2d(
        n0: usize,
        n1: usize,
        in_: &mut AlignedVec<Self::Real>,
        out: &mut AlignedVec<Self::Complex>,
        FLAG,
    ) -> RawPlan;
    unsafe fn c2r_2d(
        n0: usize,
        n1: usize,
        in_: &mut AlignedVec<Self::Complex>,
        out: &mut AlignedVec<Self::Real>,
        FLAG,
    ) -> RawPlan;
    unsafe fn r2c_3d(
        n0: usize,
        n1: usize,
        n2: usize,
        in_: &mut AlignedVec<Self::Real>,
        out: &mut AlignedVec<Self::Complex>,
        FLAG,
    ) -> RawPlan;
    unsafe fn c2r_3d(
        n0: usize,
        n1: usize,
        n2: usize,
        in_: &mut AlignedVec<Self::Complex>,
        out: &mut AlignedVec<Self::Real>,
        FLAG,
    ) -> RawPlan;
}

macro_rules! impl_plan_create {
    ($bit:ident, $float:ty, $complex:ty,
     $r2r_1d:ident, $r2c_1d:ident, $c2r_1d:ident, $c2c_1d:ident,
     $r2r_2d:ident, $r2c_2d:ident, $c2r_2d:ident, $c2c_2d:ident,
     $r2r_3d:ident, $r2c_3d:ident, $c2r_3d:ident, $c2c_3d:ident) => {

impl R2R for $float {
    unsafe fn r2r_1d(n: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, kind: R2R_KIND, flag: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2r_1d(n as i32, in_.as_mut_ptr(), out.as_mut_ptr(), kind, flag as u32))
    }
    unsafe fn r2r_2d(n0: usize, n1: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, k0: R2R_KIND, k1: R2R_KIND, flag: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2r_2d(n0 as i32, n1 as i32, in_.as_mut_ptr(), out.as_mut_ptr(), k0, k1, flag as u32))
    }
    unsafe fn r2r_3d(n0: usize, n1: usize, n2: usize, in_: &mut AlignedVec<Self>, out: &mut AlignedVec<Self>, k0: R2R_KIND, k1: R2R_KIND, k2: R2R_KIND, flag: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2r_3d(n0 as i32, n1 as i32, n2 as i32, in_.as_mut_ptr(), out.as_mut_ptr(), k0, k1, k2, flag as u32))
    }
}

impl C2C for $complex {
    unsafe fn c2c_1d(n: usize, i: &mut AlignedVec<Self>, o: &mut AlignedVec<Self>, s: SIGN, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2c_1d(n as i32, i.as_mut_ptr(), o.as_mut_ptr(), s as i32, f as u32))
    }
    unsafe fn c2c_2d(n0: usize, n1: usize, i: &mut AlignedVec<Self>, o: &mut AlignedVec<Self>, s: SIGN, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2c_2d(n0 as i32, n1 as i32, i.as_mut_ptr(), o.as_mut_ptr(), s as i32, f as u32))
    }
    unsafe fn c2c_3d(n0: usize, n1: usize, n2: usize, i: &mut AlignedVec<Self>, o: &mut AlignedVec<Self>, s: SIGN, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2c_3d(n0 as i32, n1 as i32, n2 as i32, i.as_mut_ptr(), o.as_mut_ptr(), s as i32, f as u32))
    }
}

impl C2R for ($complex, $float) {
    type Real = $float;
    type Complex = $complex;
    unsafe fn r2c_1d(n: usize, i: &mut AlignedVec<Self::Real>, o: &mut AlignedVec<Self::Complex>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2c_1d(n as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn c2r_1d(n: usize, i: &mut AlignedVec<Self::Complex>, o: &mut AlignedVec<Self::Real>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2r_1d(n as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn r2c_2d(n0: usize, n1: usize, i: &mut AlignedVec<Self::Real>, o: &mut AlignedVec<Self::Complex>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2c_2d(n0 as i32, n1 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn c2r_2d(n0: usize, n1: usize, i: &mut AlignedVec<Self::Complex>, o: &mut AlignedVec<Self::Real>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2r_2d(n0 as i32, n1 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn r2c_3d(n0: usize, n1: usize, n2: usize, i: &mut AlignedVec<Self::Real>, o: &mut AlignedVec<Self::Complex>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$r2c_3d(n0 as i32, n1 as i32, n2 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn c2r_3d(n0: usize, n1: usize, n2: usize, i: &mut AlignedVec<Self::Complex>, o: &mut AlignedVec<Self::Real>, f: FLAG) -> RawPlan {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        RawPlan::$bit(ffi::$c2r_3d(n0 as i32, n1 as i32, n2 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
}

}} // impl_plan_create

impl_plan_create!(
    _64,
    f64,
    c64,
    fftw_plan_r2r_1d,
    fftw_plan_dft_r2c_1d,
    fftw_plan_dft_c2r_1d,
    fftw_plan_dft_1d,
    fftw_plan_r2r_2d,
    fftw_plan_dft_r2c_2d,
    fftw_plan_dft_c2r_2d,
    fftw_plan_dft_2d,
    fftw_plan_r2r_3d,
    fftw_plan_dft_r2c_3d,
    fftw_plan_dft_c2r_3d,
    fftw_plan_dft_3d
);
impl_plan_create!(
    _32,
    f32,
    c32,
    fftwf_plan_r2r_1d,
    fftwf_plan_dft_r2c_1d,
    fftwf_plan_dft_c2r_1d,
    fftwf_plan_dft_1d,
    fftwf_plan_r2r_2d,
    fftwf_plan_dft_r2c_2d,
    fftwf_plan_dft_c2r_2d,
    fftwf_plan_dft_2d,
    fftwf_plan_r2r_3d,
    fftwf_plan_dft_r2c_3d,
    fftwf_plan_dft_c2r_3d,
    fftwf_plan_dft_3d
);
<|endoftext|>


<commit_before>use Parcel;

pub struct HighLevelAbstraction<HighLevel, LowLevel>;

impl p
<commit_msg>Remove TODO file<commit_after><|endoftext|>


<commit_before>use super::structure::{Program,Condition,Command,Expression,Sensor};

#[derive(Copy,Clone)]
pub struct SensorData {
	pub x: f32,
	pub y: f32,
	pub vx: f32,
	pub vy: f32,
	pub o: f32,
	pub w: f32
}

pub trait Evaluate {
	fn evaluate(&self, sensor_data: SensorData) -> Box<&Command>;
}

impl Evaluate for Program {
	fn evaluate(&self, sensor_data: SensorData) -> Box<&Command> {
		match *self {
			Program::If(ref condition, ref true_program, ref false_program) => {
				if (*condition).value(sensor_data) {
					Box::new(*true_program.evaluate(sensor_data))
				} else {
					Box::new(*false_program.evaluate(sensor_data))
				}
			},
			Program::Command(ref command) => Box::new(command),
		}
	}
}

pub trait NumericValue {
	fn value(&self, sensor_data: SensorData) -> f32;
}

impl NumericValue for Expression {
	fn value(&self, sensor_data: SensorData) -> f32 {
		match *self {
			Expression::Constant(value)               => value,
			Expression::Sensor(ref sensor)            => sensor.value(sensor_data),
			Expression::Plus(ref left, ref right)     => left.value(sensor_data) + right.value(sensor_data),
			Expression::Minus(ref left, ref right)    => left.value(sensor_data) - right.value(sensor_data),
			Expression::Multiply(ref left, ref right) => left.value(sensor_data) * right.value(sensor_data),
			Expression::Divide(ref left, ref right)   => left.value(sensor_data) / right.value(sensor_data)
		}
	}
}

impl NumericValue for Sensor {
	fn value(&self, sensor_data: SensorData) -> f32 {
		match *self {
			Sensor::X  => sensor_data.x,
			Sensor::Y  => sensor_data.y,
			Sensor::Vx => sensor_data.vx,
			Sensor::Vy => sensor_data.vy,
			Sensor::O  => sensor_data.o,
			Sensor::W  => sensor_data.w,
		}
	}
}
pub trait BooleanValue {
	fn value(&self, sensor_data: SensorData) -> bool;
}

impl BooleanValue for Condition {
	fn value(&self, sensor_data: SensorData) -> bool {
		match *self {
			Condition::True                              => true,
			Condition::False                             => false,
			Condition::Not(ref condition)                => !(*condition).value(sensor_data),
			Condition::Or(ref left, ref right)           => (*left).value(sensor_data) || (*right).value(sensor_data),
			Condition::And(ref left, ref right)          => (*left).value(sensor_data) && (*right).value(sensor_data),
			Condition::Less(ref left, ref right)         => (*left).value(sensor_data) <  (*right).value(sensor_data),
			Condition::LessEqual(ref left, ref right)    => (*left).value(sensor_data) <= (*right).value(sensor_data),
			Condition::Equal(ref left, ref right)        => (*left).value(sensor_data) == (*right).value(sensor_data),
			Condition::GreaterEqual(ref left, ref right) => (*left).value(sensor_data) >= (*right).value(sensor_data),
			Condition::Greater(ref left, ref right)      => (*left).value(sensor_data) >  (*right).value(sensor_data),
		}
	}
}<commit_msg>Document ast::data<commit_after>use super::structure::{Program,Condition,Command,Expression,Sensor};

/// `SensorData` represents the information that is available for programs to decide what `ast::structure::Command`
/// to execute when it is evaluated.
///
/// # Examples
///
/// ```
/// let data = ast::data::SensorData { x: 37.0, y: 51.0, vx: 1.0, vy: 0.0, o: 0.0, w: 0.0 };
/// ```
#[derive(Copy,Clone)]
pub struct SensorData {
	pub x:  f32,
	pub y:  f32,
	pub vx: f32,
	pub vy: f32,
	pub o:  f32,
	pub w:  f32
}

/// `Evaluate` returns a specific `ast::structure::Command` to execute, depending on `ast::data::SensorData`
pub trait Evaluate {
	fn evaluate(&self, sensor_data: SensorData) -> Box<&Command>;
}

impl Evaluate for Program {
	fn evaluate(&self, sensor_data: SensorData) -> Box<&Command> {
		match *self {
			Program::If(ref condition, ref true_program, ref false_program) => {
				if (*condition).value(sensor_data) {
					Box::new(*true_program.evaluate(sensor_data))
				} else {
					Box::new(*false_program.evaluate(sensor_data))
				}
			},
			Program::Command(ref command) => Box::new(command),
		}
	}
}

/// The numeric value of an `ast::structure::Expression`
pub trait NumericValue {
	fn value(&self, sensor_data: SensorData) -> f32;
}

impl NumericValue for Expression {
	fn value(&self, sensor_data: SensorData) -> f32 {
		match *self {
			Expression::Constant(value)               => value,
			Expression::Sensor(ref sensor)            => sensor.value(sensor_data),
			Expression::Plus(ref left, ref right)     => left.value(sensor_data) + right.value(sensor_data),
			Expression::Minus(ref left, ref right)    => left.value(sensor_data) - right.value(sensor_data),
			Expression::Multiply(ref left, ref right) => left.value(sensor_data) * right.value(sensor_data),
			Expression::Divide(ref left, ref right)   => left.value(sensor_data) / right.value(sensor_data)
		}
	}
}

impl NumericValue for Sensor {
	fn value(&self, sensor_data: SensorData) -> f32 {
		match *self {
			Sensor::X  => sensor_data.x,
			Sensor::Y  => sensor_data.y,
			Sensor::Vx => sensor_data.vx,
			Sensor::Vy => sensor_data.vy,
			Sensor::O  => sensor_data.o,
			Sensor::W  => sensor_data.w,
		}
	}
}

/// The truth value of an `ast::structure::Condition`
pub trait BooleanValue {
	fn value(&self, sensor_data: SensorData) -> bool;
}

impl BooleanValue for Condition {
	fn value(&self, sensor_data: SensorData) -> bool {
		match *self {
			Condition::True                              => true,
			Condition::False                             => false,
			Condition::Not(ref condition)                => !(*condition).value(sensor_data),
			Condition::Or(ref left, ref right)           => (*left).value(sensor_data) || (*right).value(sensor_data),
			Condition::And(ref left, ref right)          => (*left).value(sensor_data) && (*right).value(sensor_data),
			Condition::Less(ref left, ref right)         => (*left).value(sensor_data) <  (*right).value(sensor_data),
			Condition::LessEqual(ref left, ref right)    => (*left).value(sensor_data) <= (*right).value(sensor_data),
			Condition::Equal(ref left, ref right)        => (*left).value(sensor_data) == (*right).value(sensor_data),
			Condition::GreaterEqual(ref left, ref right) => (*left).value(sensor_data) >= (*right).value(sensor_data),
			Condition::Greater(ref left, ref right)      => (*left).value(sensor_data) >  (*right).value(sensor_data),
		}
	}
}<|endoftext|>


<commit_before>//use std::fmt;
use rand;
use rand::{Rng};

use card::{Suit, Value, Card};

pub struct Deck {
    count_dealt: usize,
    cards: [u16; 52],
}

impl Deck {
    pub fn new() -> Deck {
        let mut d = Deck {
            count_dealt: 0,
            cards: [0; 52],
        };

        let mut value = 0;
        for x in d.cards.iter_mut() {
            *x = value;
            value += 1;
        }

        d.shuffle();

        d
    }

    pub fn reset(&mut self) {
        self.count_dealt = 0;
        self.shuffle();
    }

    fn shuffle(&mut self) {
        let mut rng = rand::thread_rng();
        rng.shuffle(&mut self.cards);
    }

    fn create_card_for_value(&self, value: &u16) -> Card {
        let suit = match value/13 {
            0 => Suit::Spades,
            1 => Suit::Hearts,
            2 => Suit::Diamonds,
            3 => Suit::Clubs,
            _ => panic!("Unexpected suit conversion number")
        };

        let value = match value%13 {
            0 => Value::Two,
            1 => Value::Three,
            2 => Value::Four,
            3 => Value::Five,
            4 => Value::Six,
            5 => Value::Seven,
            6 => Value::Eight,
            7 => Value::Nine,
            8 => Value::Ten,
            9 => Value::Jack,
            10 => Value::Queen,
            11 => Value::King,
            12 => Value::Ace,
            _ => panic!("Unexpected value conversion number")
        };

        Card(value, suit)
    }

    pub fn draw(&mut self) -> Card {
        let value = &self.cards[self.count_dealt];
        self.count_dealt+=1;

        self.create_card_for_value(value)
    }

    //TODO: this is a bit lazy and only for testing. Rather create a function (card -> 0..52)?
    pub fn draw_as_value(&mut self) -> usize {
        let value = &self.cards[self.count_dealt];
        self.count_dealt+=1;

        *value as usize
    }

    pub fn draw_n(&mut self, n: &usize) -> Vec<Card> {
        let mut cards = Vec::new();

        for _ in 0..*n {
            cards.push(self.draw())
        }
        cards
    }
}

<commit_msg>Comment tweaks.<commit_after>//use std::fmt;
use rand;
use rand::{Rng};

use card::{Suit, Value, Card};

pub struct Deck {
    count_dealt: usize,
    cards: [u16; 52],
}

impl Deck {
    pub fn new() -> Deck {
        let mut d = Deck {
            count_dealt: 0,
            cards: [0; 52],
        };

        let mut value = 0;
        for x in d.cards.iter_mut() {
            *x = value;
            value += 1;
        }

        d.shuffle(); //TODO: constructor for unshuffled state?

        d
    }

    pub fn reset(&mut self) { //TODO: is reset the right name?
        self.count_dealt = 0;
        self.shuffle();
    }

    fn shuffle(&mut self) {
        let mut rng = rand::thread_rng();
        rng.shuffle(&mut self.cards);
    }

    fn create_card_for_value(&self, value: &u16) -> Card {
        let suit = match value/13 {
            0 => Suit::Spades,
            1 => Suit::Hearts,
            2 => Suit::Diamonds,
            3 => Suit::Clubs,
            _ => panic!("Unexpected suit conversion number")
        };

        let value = match value%13 {
            0 => Value::Two,
            1 => Value::Three,
            2 => Value::Four,
            3 => Value::Five,
            4 => Value::Six,
            5 => Value::Seven,
            6 => Value::Eight,
            7 => Value::Nine,
            8 => Value::Ten,
            9 => Value::Jack,
            10 => Value::Queen,
            11 => Value::King,
            12 => Value::Ace,
            _ => panic!("Unexpected value conversion number")
        };

        Card(value, suit)
    }

    pub fn draw(&mut self) -> Card {
        let value = &self.cards[self.count_dealt];
        self.count_dealt+=1;

        self.create_card_for_value(value)
    }

    //TODO: this is a bit lazy and only for testing. Rather create a function (card -> 0..52)?
    pub fn draw_as_value(&mut self) -> usize {
        let value = &self.cards[self.count_dealt];
        self.count_dealt+=1;

        *value as usize
    }

    pub fn draw_n(&mut self, n: &usize) -> Vec<Card> {
        let mut cards = Vec::new();

        for _ in 0..*n {
            cards.push(self.draw())
        }
        cards
    }
}

<|endoftext|>


<commit_before>//! Git repository representation for git-global.

use std::fmt;

use git2;

/// A git repository, represented by the full path to its base directory.
#[derive(PartialEq, Eq, Hash, Clone)]
pub struct Repo {
    path: String,
}

impl Repo {
    pub fn new(path: String) -> Repo {
        Repo {
            path: path,
        }
    }

    /// Returns the full path to the repo as a `String`.
    pub fn path(&self) -> String {
        self.path.clone()
    }

    /// Returns the `git2::Repository` equivalent of this repo.
    pub fn as_git2_repo(&self) -> Option<git2::Repository> {
        git2::Repository::open(&self.path).ok()
    }
}

impl fmt::Display for Repo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.path)
    }
}
<commit_msg>Mark Repo.path be a PathBuf instead of a String<commit_after>//! Git repository representation for git-global.

use std::fmt;
use std::path::PathBuf;

use git2;

/// A git repository, represented by the full path to its base directory.
#[derive(Clone, Eq, Hash, PartialEq)]
pub struct Repo {
    path: PathBuf,
}

impl Repo {
    pub fn new(path: String) -> Repo {
        Repo {
            path: PathBuf::from(path),
        }
    }

    /// Returns the `git2::Repository` equivalent of this repo.
    pub fn as_git2_repo(&self) -> Option<git2::Repository> {
        git2::Repository::open(&self.path).ok()
    }
    /// Returns the full path to the repo as a `String`.
    pub fn path(&self) -> String {
        self.path.to_str().unwrap().to_string()
    }
}

impl fmt::Display for Repo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.path())
    }
}
<|endoftext|>


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

use enums::Direction;
use structs::Point;
use traits::HasValues;
use travel::travel;

/// Find points in a spherical ring of a provided radius
///
/// # Example
///
/// ```
/// use hex_math::{Point, ring};
/// use std::collections::HashSet;
///
/// let point: Point = Point::new(1, 2, 5);
/// let set: HashSet<Point> = ring(&point, 2);
///
/// assert!(set.contains(&Point::new(1, 0, 5)));
/// assert!(set.contains(&Point::new(2, 0, 5)));
/// assert!(set.contains(&Point::new(3, 0, 5)));
/// assert!(set.contains(&Point::new(3, 1, 5)));
/// assert!(set.contains(&Point::new(3, 2, 5)));
/// assert!(set.contains(&Point::new(2, 3, 5)));
/// assert!(set.contains(&Point::new(1, 4, 5)));
/// assert!(set.contains(&Point::new(0, 4, 5)));
/// assert!(set.contains(&Point::new(-1, 4, 5)));
/// assert!(set.contains(&Point::new(-1, 3, 5)));
/// assert!(set.contains(&Point::new(-1, 2, 5)));
/// assert!(set.contains(&Point::new(0, 1, 5)));
///
/// assert!(set.contains(&Point::new(1, 1, 6)));
/// assert!(set.contains(&Point::new(2, 1, 6)));
/// assert!(set.contains(&Point::new(2, 2, 6)));
/// assert!(set.contains(&Point::new(1, 3, 6)));
/// assert!(set.contains(&Point::new(0, 3, 6)));
/// assert!(set.contains(&Point::new(0, 2, 6)));
///
/// assert!(set.contains(&Point::new(1, 1, 4)));
/// assert!(set.contains(&Point::new(2, 1, 4)));
/// assert!(set.contains(&Point::new(2, 2, 4)));
/// assert!(set.contains(&Point::new(1, 3, 4)));
/// assert!(set.contains(&Point::new(0, 3, 4)));
/// assert!(set.contains(&Point::new(0, 2, 4)));
///
/// assert!(set.contains(&Point::new(1, 2, 7)));
/// assert!(set.contains(&Point::new(1, 2, 3)));
/// assert_eq!(set.len(), 26);
/// ```
pub fn ring<T: HasValues>(point: &T, range: i32) -> HashSet<Point> {
  let mut set: HashSet<Point> = ring_2d(point, range);

  for index in 1..range + 1 {
    let diff = range - index;
    let up: Point = travel(point, &Direction::Up, index);
    let down: Point = travel(point, &Direction::Down, index);
    let up_ring: HashSet<Point> = ring_2d(&up, diff);
    let down_ring: HashSet<Point> = ring_2d(&down, diff);

    set.extend(up_ring);
    set.extend(down_ring);
  }

  set.insert(travel(point, &Direction::Up, range));
  set.insert(travel(point, &Direction::Down, range));

  set
}

/// Find points at the same height in a ring of a provided radius
///
/// # Example
///
/// ```
/// use hex_math::{Point, ring_2d};
/// use std::collections::HashSet;
///
/// let point: Point = Point::new(1, 2, 5);
/// let set: HashSet<Point> = ring_2d(&point, 1);
///
/// assert!(set.contains(&Point::new(1, 1, 5)));
/// assert!(set.contains(&Point::new(2, 1, 5)));
/// assert!(set.contains(&Point::new(2, 2, 5)));
/// assert!(set.contains(&Point::new(1, 3, 5)));
/// assert!(set.contains(&Point::new(0, 3, 5)));
/// assert!(set.contains(&Point::new(0, 2, 5)));
/// assert_eq!(set.len(), 6);
/// ```
pub fn ring_2d<T: HasValues>(point: &T, range: i32) -> HashSet<Point> {
  let mut set: HashSet<Point> = HashSet::new();
  let mut point: Point = travel(point, &Direction::Northwest, range);

  for direction in Direction::to_vec().iter().take(6) {
    for _ in 0..range {
      let next: Point = travel(&point, direction, 1);

      set.insert(point);
      point = next;
    }
  }

  set
}

<commit_msg>Issue #33: Refactor ring<commit_after>use std::collections::HashSet;

use enums::Direction;
use structs::Point;
use traits::HasValues;
use travel::travel;

/// Find points in a spherical ring of a provided radius
pub fn ring<T: HasValues>(point: &T, range: i32) -> HashSet<Point> {
  let mut set: HashSet<Point> = ring_2d(point, range);

  for index in 1..range + 1 {
    let diff = range - index;
    let up: Point = travel(point, &Direction::Up, index);
    let down: Point = travel(point, &Direction::Down, index);
    let up_ring: HashSet<Point> = ring_2d(&up, diff);
    let down_ring: HashSet<Point> = ring_2d(&down, diff);

    set.extend(up_ring);
    set.extend(down_ring);
  }

  set.insert(travel(point, &Direction::Up, range));
  set.insert(travel(point, &Direction::Down, range));

  set
}

/// Find points at the same height in a ring of a provided radius
pub fn ring_2d<T: HasValues>(point: &T, range: i32) -> HashSet<Point> {
  let mut set: HashSet<Point> = HashSet::new();
  let mut point: Point = travel(point, &Direction::Northwest, range);

  for direction in Direction::to_vec().iter().take(6) {
    for _ in 0..range {
      let next: Point = travel(&point, direction, 1);

      set.insert(point);
      point = next;
    }
  }

  set
}

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

  #[test]
  fn ring() {
    let point: Point = Point::new(1, 2, 5);
    let set: HashSet<Point> = super::ring(&point, 2);

    assert!(set.contains(&Point::new(1, 0, 5)));
    assert!(set.contains(&Point::new(2, 0, 5)));
    assert!(set.contains(&Point::new(3, 0, 5)));
    assert!(set.contains(&Point::new(3, 1, 5)));
    assert!(set.contains(&Point::new(3, 2, 5)));
    assert!(set.contains(&Point::new(2, 3, 5)));
    assert!(set.contains(&Point::new(1, 4, 5)));
    assert!(set.contains(&Point::new(0, 4, 5)));
    assert!(set.contains(&Point::new(-1, 4, 5)));
    assert!(set.contains(&Point::new(-1, 3, 5)));
    assert!(set.contains(&Point::new(-1, 2, 5)));
    assert!(set.contains(&Point::new(0, 1, 5)));

    assert!(set.contains(&Point::new(1, 1, 6)));
    assert!(set.contains(&Point::new(2, 1, 6)));
    assert!(set.contains(&Point::new(2, 2, 6)));
    assert!(set.contains(&Point::new(1, 3, 6)));
    assert!(set.contains(&Point::new(0, 3, 6)));
    assert!(set.contains(&Point::new(0, 2, 6)));

    assert!(set.contains(&Point::new(1, 1, 4)));
    assert!(set.contains(&Point::new(2, 1, 4)));
    assert!(set.contains(&Point::new(2, 2, 4)));
    assert!(set.contains(&Point::new(1, 3, 4)));
    assert!(set.contains(&Point::new(0, 3, 4)));
    assert!(set.contains(&Point::new(0, 2, 4)));

    assert!(set.contains(&Point::new(1, 2, 7)));
    assert!(set.contains(&Point::new(1, 2, 3)));
    assert!(set.len() == 26);
  }

  #[test]
  fn ring_2d() {
    let point: Point = Point::new(1, 2, 5);
    let set: HashSet<Point> = super::ring_2d(&point, 1);

    assert!(set.contains(&Point::new(1, 1, 5)));
    assert!(set.contains(&Point::new(2, 1, 5)));
    assert!(set.contains(&Point::new(2, 2, 5)));
    assert!(set.contains(&Point::new(1, 3, 5)));
    assert!(set.contains(&Point::new(0, 3, 5)));
    assert!(set.contains(&Point::new(0, 2, 5)));
    assert!(set.len() == 6);
  }
}
<|endoftext|>


<commit_before>use std::vec::Vec;

enum Difference {
    Minus,
    Plus,
}

struct Entry {
    line_num: i32,
    difference: Difference,
    line: String,
}

impl Entry {
    fn new(line_num: i32, difference: Difference, line: String) -> Entry {
        Entry {
            line_num: line_num,
            difference: difference,
            line: line,
        }
    }
}

pub struct Diff {
    entries: Vec<Entry>,
}

impl Diff {
    pub fn new() -> Diff {
        let mut entries: Vec<Entry> = Vec::new();
        Diff {
            entries: entries,
        }
    }

    pub fn add_line(&mut self, line_num: i32, line: String) {
        self.entries.push(Entry::new(line_num, Difference::Plus, line));
    }

    pub fn del_line(&mut self, line_num: i32, line: String) {
        self.entries.push(Entry::new(line_num, Difference::Minus, line));
    }
}

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

    #[test]
    fn new_diff_empty() {
        let mut diff = Diff::new();
        assert!(diff.entries.is_empty());
    }

    #[test]
    fn diff_has_lines() {
        let mut diff = Diff::new();
        diff.add_line(1, "Here is a line".to_string());
        diff.add_line(2, "and another".to_string());
        diff.add_line(3, "and one more".to_string());
        assert_eq!(diff.entries.len(), 3);
    }
}
<commit_msg>Add super simple undo mechanism<commit_after>use std::vec::Vec;

enum Difference {
    Minus,
    Plus,
}

struct Entry {
    line_num: i32,
    difference: Difference,
    line: String,
}

impl Entry {
    fn new(line_num: i32, difference: Difference, line: String) -> Entry {
        Entry {
            line_num: line_num,
            difference: difference,
            line: line,
        }
    }
}

pub struct Diff {
    entries: Vec<Entry>,
}

impl Diff {
    pub fn new() -> Diff {
        let mut entries: Vec<Entry> = Vec::new();
        Diff {
            entries: entries,
        }
    }

    pub fn add_line(&mut self, line_num: i32, line: String) {
        self.entries.push(Entry::new(line_num, Difference::Plus, line));
    }

    pub fn del_line(&mut self, line_num: i32, line: String) {
        self.entries.push(Entry::new(line_num, Difference::Minus, line));
    }

    pub fn undo(&mut self) {
        self.entries.pop();
    }
}

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

    #[test]
    fn new_diff_empty() {
        let mut diff = Diff::new();
        assert!(diff.entries.is_empty());
    }

    #[test]
    fn diff_has_lines() {
        let mut diff = Diff::new();
        diff.add_line(1, "Here is a line".to_string());
        diff.add_line(2, "and another".to_string());
        diff.add_line(3, "and one more".to_string());
        assert_eq!(diff.entries.len(), 3);
    }

    #[test]
    fn diff_undo() {
        let mut diff = Diff::new();
        diff.add_line(1, "Here is a line".to_string());
        diff.undo();
        assert!(diff.entries.is_empty());
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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 super::UnknownUnit;
use length::Length;
use scale_factor::ScaleFactor;
use vector::{TypedVector2D, vec2};
use num::*;

use num_traits::NumCast;
use std::fmt;
use std::ops::{Add, Div, Mul, Sub};
use std::marker::PhantomData;

/// A 2d size tagged with a unit.
define_matrix! {
    pub struct TypedSize2D<T, U> {
        pub width: T,
        pub height: T,
    }
}

/// Default 2d size type with no unit.
///
/// `Size2D` provides the same methods as `TypedSize2D`.
pub type Size2D<T> = TypedSize2D<T, UnknownUnit>;

impl<T: fmt::Debug, U> fmt::Debug for TypedSize2D<T, U> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}×{:?}", self.width, self.height)
    }
}

impl<T: fmt::Display, U> fmt::Display for TypedSize2D<T, U> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "({}x{})", self.width, self.height)
    }
}

impl<T, U> TypedSize2D<T, U> {
    /// Constructor taking scalar values.
    pub fn new(width: T, height: T) -> Self {
        TypedSize2D {
            width: width,
            height: height,
            _unit: PhantomData,
        }
    }
}

impl<T: Clone, U> TypedSize2D<T, U> {
    /// Constructor taking scalar strongly typed lengths.
    pub fn from_lengths(width: Length<T, U>, height: Length<T, U>) -> Self {
        TypedSize2D::new(width.get(), height.get())
    }
}

impl<T: Round, U> TypedSize2D<T, U> {
    /// Rounds each component to the nearest integer value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    pub fn round(&self) -> Self {
        TypedSize2D::new(self.width.round(), self.height.round())
    }
}

impl<T: Ceil, U> TypedSize2D<T, U> {
    /// Rounds each component to the smallest integer equal or greater than the original value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    pub fn ceil(&self) -> Self {
        TypedSize2D::new(self.width.ceil(), self.height.ceil())
    }
}

impl<T: Floor, U> TypedSize2D<T, U> {
    /// Rounds each component to the biggest integer equal or lower than the original value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    pub fn floor(&self) -> Self {
        TypedSize2D::new(self.width.floor(), self.height.floor())
    }
}

impl<T: Copy + Add<T, Output=T>, U> Add for TypedSize2D<T, U> {
    type Output = Self;
    fn add(self, other: Self) -> Self {
        TypedSize2D::new(self.width + other.width, self.height + other.height)
    }
}

impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedSize2D<T, U> {
    type Output = Self;
    fn sub(self, other: Self) -> Self {
        TypedSize2D::new(self.width - other.width, self.height - other.height)
    }
}

impl<T: Copy + Clone + Mul<T, Output=U>, U> TypedSize2D<T, U> {
    pub fn area(&self) -> U { self.width * self.height }
}

impl<T, U> TypedSize2D<T, U>
where T: Copy + One + Add<Output=T> + Sub<Output=T> + Mul<Output=T> {
    /// Linearly interpolate between this size and another size.
    ///
    /// `t` is expected to be between zero and one.
    #[inline]
    pub fn lerp(&self, other: Self, t: T) -> Self {
        let one_t = T::one() - t;
        size2(
            one_t * self.width + t * other.width,
            one_t * self.height + t * other.height,
        )
    }
}

impl<T: Zero, U> TypedSize2D<T, U> {
    pub fn zero() -> Self {
        TypedSize2D::new(
            Zero::zero(),
            Zero::zero(),
        )
    }
}

impl<T: Zero, U> Zero for TypedSize2D<T, U> {
    fn zero() -> Self {
        TypedSize2D::new(
            Zero::zero(),
            Zero::zero(),
        )
    }
}

impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedSize2D<T, U> {
    type Output = Self;
    #[inline]
    fn mul(self, scale: T) -> Self {
        TypedSize2D::new(self.width * scale, self.height * scale)
    }
}

impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedSize2D<T, U> {
    type Output = Self;
    #[inline]
    fn div(self, scale: T) -> Self {
        TypedSize2D::new(self.width / scale, self.height / scale)
    }
}

impl<T: Copy + Mul<T, Output=T>, U1, U2> Mul<ScaleFactor<T, U1, U2>> for TypedSize2D<T, U1> {
    type Output = TypedSize2D<T, U2>;
    #[inline]
    fn mul(self, scale: ScaleFactor<T, U1, U2>) -> TypedSize2D<T, U2> {
        TypedSize2D::new(self.width * scale.get(), self.height * scale.get())
    }
}

impl<T: Copy + Div<T, Output=T>, U1, U2> Div<ScaleFactor<T, U1, U2>> for TypedSize2D<T, U2> {
    type Output = TypedSize2D<T, U1>;
    #[inline]
    fn div(self, scale: ScaleFactor<T, U1, U2>) -> TypedSize2D<T, U1> {
        TypedSize2D::new(self.width / scale.get(), self.height / scale.get())
    }
}

impl<T: Copy, U> TypedSize2D<T, U> {
    /// Returns self.width as a Length carrying the unit.
    #[inline]
    pub fn width_typed(&self) -> Length<T, U> { Length::new(self.width) }

    /// Returns self.height as a Length carrying the unit.
    #[inline]
    pub fn height_typed(&self) -> Length<T, U> { Length::new(self.height) }

    #[inline]
    pub fn to_array(&self) -> [T; 2] { [self.width, self.height] }

    #[inline]
    pub fn to_vector(&self) -> TypedVector2D<T, U> { vec2(self.width, self.height) }

    /// Drop the units, preserving only the numeric value.
    pub fn to_untyped(&self) -> Size2D<T> {
        TypedSize2D::new(self.width, self.height)
    }

    /// Tag a unitless value with units.
    pub fn from_untyped(p: &Size2D<T>) -> Self {
        TypedSize2D::new(p.width, p.height)
    }
}

impl<T: NumCast + Copy, Unit> TypedSize2D<T, Unit> {
    /// Cast from one numeric representation to another, preserving the units.
    ///
    /// When casting from floating point to integer coordinates, the decimals are truncated
    /// as one would expect from a simple cast, but this behavior does not always make sense
    /// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
    pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedSize2D<NewT, Unit>> {
        match (NumCast::from(self.width), NumCast::from(self.height)) {
            (Some(w), Some(h)) => Some(TypedSize2D::new(w, h)),
            _ => None
        }
    }

    // Convenience functions for common casts

    /// Cast into an `f32` size.
    pub fn to_f32(&self) -> TypedSize2D<f32, Unit> {
        self.cast().unwrap()
    }

    /// Cast into an `uint` size, truncating decimals if any.
    ///
    /// When casting from floating point sizes, it is worth considering whether
    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
    /// the desired conversion behavior.
    pub fn to_usize(&self) -> TypedSize2D<usize, Unit> {
        self.cast().unwrap()
    }

    /// Cast into an `i32` size, truncating decimals if any.
    ///
    /// When casting from floating point sizes, it is worth considering whether
    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
    /// the desired conversion behavior.
    pub fn to_i32(&self) -> TypedSize2D<i32, Unit> {
        self.cast().unwrap()
    }

    /// Cast into an `i64` size, truncating decimals if any.
    ///
    /// When casting from floating point sizes, it is worth considering whether
    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
    /// the desired conversion behavior.
    pub fn to_i64(&self) -> TypedSize2D<i64, Unit> {
        self.cast().unwrap()
    }
}

/// Shorthand for `TypedSize2D::new(w, h)`.
pub fn size2<T, U>(w: T, h: T) -> TypedSize2D<T, U> {
    TypedSize2D::new(w, h)
}

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

    #[test]
    pub fn test_add() {
        let p1 = Size2D::new(1.0, 2.0);
        let p2 = Size2D::new(3.0, 4.0);
        assert_eq!(p1 + p2, Size2D::new(4.0, 6.0));

        let p1 = Size2D::new(1.0, 2.0);
        let p2 = Size2D::new(0.0, 0.0);
        assert_eq!(p1 + p2, Size2D::new(1.0, 2.0));

        let p1 = Size2D::new(1.0, 2.0);
        let p2 = Size2D::new(-3.0, -4.0);
        assert_eq!(p1 + p2, Size2D::new(-2.0, -2.0));

        let p1 = Size2D::new(0.0, 0.0);
        let p2 = Size2D::new(0.0, 0.0);
        assert_eq!(p1 + p2, Size2D::new(0.0, 0.0));
    }

    #[test]
    pub fn test_sub() {
        let p1 = Size2D::new(1.0, 2.0);
        let p2 = Size2D::new(3.0, 4.0);
        assert_eq!(p1 - p2, Size2D::new(-2.0, -2.0));

        let p1 = Size2D::new(1.0, 2.0);
        let p2 = Size2D::new(0.0, 0.0);
        assert_eq!(p1 - p2, Size2D::new(1.0, 2.0));

        let p1 = Size2D::new(1.0, 2.0);
        let p2 = Size2D::new(-3.0, -4.0);
        assert_eq!(p1 - p2, Size2D::new(4.0, 6.0));

        let p1 = Size2D::new(0.0, 0.0);
        let p2 = Size2D::new(0.0, 0.0);
        assert_eq!(p1 - p2, Size2D::new(0.0, 0.0));
    }
}
<commit_msg>Auto merge of #222 - kvark:area, r=nical<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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 super::UnknownUnit;
use length::Length;
use scale_factor::ScaleFactor;
use vector::{TypedVector2D, vec2};
use num::*;

use num_traits::NumCast;
use std::fmt;
use std::ops::{Add, Div, Mul, Sub};
use std::marker::PhantomData;

/// A 2d size tagged with a unit.
define_matrix! {
    pub struct TypedSize2D<T, U> {
        pub width: T,
        pub height: T,
    }
}

/// Default 2d size type with no unit.
///
/// `Size2D` provides the same methods as `TypedSize2D`.
pub type Size2D<T> = TypedSize2D<T, UnknownUnit>;

impl<T: fmt::Debug, U> fmt::Debug for TypedSize2D<T, U> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}×{:?}", self.width, self.height)
    }
}

impl<T: fmt::Display, U> fmt::Display for TypedSize2D<T, U> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "({}x{})", self.width, self.height)
    }
}

impl<T, U> TypedSize2D<T, U> {
    /// Constructor taking scalar values.
    pub fn new(width: T, height: T) -> Self {
        TypedSize2D {
            width: width,
            height: height,
            _unit: PhantomData,
        }
    }
}

impl<T: Clone, U> TypedSize2D<T, U> {
    /// Constructor taking scalar strongly typed lengths.
    pub fn from_lengths(width: Length<T, U>, height: Length<T, U>) -> Self {
        TypedSize2D::new(width.get(), height.get())
    }
}

impl<T: Round, U> TypedSize2D<T, U> {
    /// Rounds each component to the nearest integer value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    pub fn round(&self) -> Self {
        TypedSize2D::new(self.width.round(), self.height.round())
    }
}

impl<T: Ceil, U> TypedSize2D<T, U> {
    /// Rounds each component to the smallest integer equal or greater than the original value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    pub fn ceil(&self) -> Self {
        TypedSize2D::new(self.width.ceil(), self.height.ceil())
    }
}

impl<T: Floor, U> TypedSize2D<T, U> {
    /// Rounds each component to the biggest integer equal or lower than the original value.
    ///
    /// This behavior is preserved for negative values (unlike the basic cast).
    pub fn floor(&self) -> Self {
        TypedSize2D::new(self.width.floor(), self.height.floor())
    }
}

impl<T: Copy + Add<T, Output=T>, U> Add for TypedSize2D<T, U> {
    type Output = Self;
    fn add(self, other: Self) -> Self {
        TypedSize2D::new(self.width + other.width, self.height + other.height)
    }
}

impl<T: Copy + Sub<T, Output=T>, U> Sub for TypedSize2D<T, U> {
    type Output = Self;
    fn sub(self, other: Self) -> Self {
        TypedSize2D::new(self.width - other.width, self.height - other.height)
    }
}

impl<T: Copy + Clone + Mul<T>, U> TypedSize2D<T, U> {
    pub fn area(&self) -> T::Output { self.width * self.height }
}

impl<T, U> TypedSize2D<T, U>
where T: Copy + One + Add<Output=T> + Sub<Output=T> + Mul<Output=T> {
    /// Linearly interpolate between this size and another size.
    ///
    /// `t` is expected to be between zero and one.
    #[inline]
    pub fn lerp(&self, other: Self, t: T) -> Self {
        let one_t = T::one() - t;
        size2(
            one_t * self.width + t * other.width,
            one_t * self.height + t * other.height,
        )
    }
}

impl<T: Zero, U> TypedSize2D<T, U> {
    pub fn zero() -> Self {
        TypedSize2D::new(
            Zero::zero(),
            Zero::zero(),
        )
    }
}

impl<T: Zero, U> Zero for TypedSize2D<T, U> {
    fn zero() -> Self {
        TypedSize2D::new(
            Zero::zero(),
            Zero::zero(),
        )
    }
}

impl<T: Copy + Mul<T, Output=T>, U> Mul<T> for TypedSize2D<T, U> {
    type Output = Self;
    #[inline]
    fn mul(self, scale: T) -> Self {
        TypedSize2D::new(self.width * scale, self.height * scale)
    }
}

impl<T: Copy + Div<T, Output=T>, U> Div<T> for TypedSize2D<T, U> {
    type Output = Self;
    #[inline]
    fn div(self, scale: T) -> Self {
        TypedSize2D::new(self.width / scale, self.height / scale)
    }
}

impl<T: Copy + Mul<T, Output=T>, U1, U2> Mul<ScaleFactor<T, U1, U2>> for TypedSize2D<T, U1> {
    type Output = TypedSize2D<T, U2>;
    #[inline]
    fn mul(self, scale: ScaleFactor<T, U1, U2>) -> TypedSize2D<T, U2> {
        TypedSize2D::new(self.width * scale.get(), self.height * scale.get())
    }
}

impl<T: Copy + Div<T, Output=T>, U1, U2> Div<ScaleFactor<T, U1, U2>> for TypedSize2D<T, U2> {
    type Output = TypedSize2D<T, U1>;
    #[inline]
    fn div(self, scale: ScaleFactor<T, U1, U2>) -> TypedSize2D<T, U1> {
        TypedSize2D::new(self.width / scale.get(), self.height / scale.get())
    }
}

impl<T: Copy, U> TypedSize2D<T, U> {
    /// Returns self.width as a Length carrying the unit.
    #[inline]
    pub fn width_typed(&self) -> Length<T, U> { Length::new(self.width) }

    /// Returns self.height as a Length carrying the unit.
    #[inline]
    pub fn height_typed(&self) -> Length<T, U> { Length::new(self.height) }

    #[inline]
    pub fn to_array(&self) -> [T; 2] { [self.width, self.height] }

    #[inline]
    pub fn to_vector(&self) -> TypedVector2D<T, U> { vec2(self.width, self.height) }

    /// Drop the units, preserving only the numeric value.
    pub fn to_untyped(&self) -> Size2D<T> {
        TypedSize2D::new(self.width, self.height)
    }

    /// Tag a unitless value with units.
    pub fn from_untyped(p: &Size2D<T>) -> Self {
        TypedSize2D::new(p.width, p.height)
    }
}

impl<T: NumCast + Copy, Unit> TypedSize2D<T, Unit> {
    /// Cast from one numeric representation to another, preserving the units.
    ///
    /// When casting from floating point to integer coordinates, the decimals are truncated
    /// as one would expect from a simple cast, but this behavior does not always make sense
    /// geometrically. Consider using `round()`, `ceil()` or `floor()` before casting.
    pub fn cast<NewT: NumCast + Copy>(&self) -> Option<TypedSize2D<NewT, Unit>> {
        match (NumCast::from(self.width), NumCast::from(self.height)) {
            (Some(w), Some(h)) => Some(TypedSize2D::new(w, h)),
            _ => None
        }
    }

    // Convenience functions for common casts

    /// Cast into an `f32` size.
    pub fn to_f32(&self) -> TypedSize2D<f32, Unit> {
        self.cast().unwrap()
    }

    /// Cast into an `uint` size, truncating decimals if any.
    ///
    /// When casting from floating point sizes, it is worth considering whether
    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
    /// the desired conversion behavior.
    pub fn to_usize(&self) -> TypedSize2D<usize, Unit> {
        self.cast().unwrap()
    }

    /// Cast into an `i32` size, truncating decimals if any.
    ///
    /// When casting from floating point sizes, it is worth considering whether
    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
    /// the desired conversion behavior.
    pub fn to_i32(&self) -> TypedSize2D<i32, Unit> {
        self.cast().unwrap()
    }

    /// Cast into an `i64` size, truncating decimals if any.
    ///
    /// When casting from floating point sizes, it is worth considering whether
    /// to `round()`, `ceil()` or `floor()` before the cast in order to obtain
    /// the desired conversion behavior.
    pub fn to_i64(&self) -> TypedSize2D<i64, Unit> {
        self.cast().unwrap()
    }
}

/// Shorthand for `TypedSize2D::new(w, h)`.
pub fn size2<T, U>(w: T, h: T) -> TypedSize2D<T, U> {
    TypedSize2D::new(w, h)
}

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

    #[test]
    pub fn test_add() {
        let p1 = Size2D::new(1.0, 2.0);
        let p2 = Size2D::new(3.0, 4.0);
        assert_eq!(p1 + p2, Size2D::new(4.0, 6.0));

        let p1 = Size2D::new(1.0, 2.0);
        let p2 = Size2D::new(0.0, 0.0);
        assert_eq!(p1 + p2, Size2D::new(1.0, 2.0));

        let p1 = Size2D::new(1.0, 2.0);
        let p2 = Size2D::new(-3.0, -4.0);
        assert_eq!(p1 + p2, Size2D::new(-2.0, -2.0));

        let p1 = Size2D::new(0.0, 0.0);
        let p2 = Size2D::new(0.0, 0.0);
        assert_eq!(p1 + p2, Size2D::new(0.0, 0.0));
    }

    #[test]
    pub fn test_sub() {
        let p1 = Size2D::new(1.0, 2.0);
        let p2 = Size2D::new(3.0, 4.0);
        assert_eq!(p1 - p2, Size2D::new(-2.0, -2.0));

        let p1 = Size2D::new(1.0, 2.0);
        let p2 = Size2D::new(0.0, 0.0);
        assert_eq!(p1 - p2, Size2D::new(1.0, 2.0));

        let p1 = Size2D::new(1.0, 2.0);
        let p2 = Size2D::new(-3.0, -4.0);
        assert_eq!(p1 - p2, Size2D::new(4.0, 6.0));

        let p1 = Size2D::new(0.0, 0.0);
        let p2 = Size2D::new(0.0, 0.0);
        assert_eq!(p1 - p2, Size2D::new(0.0, 0.0));
    }

    #[test]
    pub fn test_area() {
        let p = Size2D::new(1.5, 2.0);
        assert_eq!(p.area(), 3.0);
    }
}
<|endoftext|>


<commit_before>//!
//! # Tools
//!

use std::result::Result;
use std::error::Error;
use serde::*;
use serde_json::*;

///
/// Trait implemented by things that represent a tool
///
/// A tool is simply a routine that takes some input, does some processing
/// and returns a value or an error. The main difference between a tool and
/// a simple function is that a tool's input and output must be simple data,
/// which for Rust we define as 'can be serialized to JSON'.
///
/// Tools also have the requirement that they are encapsulated and can instantiate
/// themselves with no dependencies other than those they can discover from
/// their environment.
///
/// These two requirements mean that tools can be invoked simply by specifying
/// the input data (without necessarily having to know the exact Rust type involved!).
/// Test cases for tools can be specified as simple JSON data with no need for any
/// actual code. Tools can be turned into stand-alone command line programs or
/// web endpoints with no modification.
///
pub trait JsonTool {
    ///
    /// Invokes this tool with its input and output specified using JSON
    ///
    fn invoke_json(&self, input: Value) -> Result<Value, Value>;
}

///
/// Represents a tool made from a function
///
pub struct FnTool<TIn: Deserialize, TOut: Serialize, TErr: Serialize> {
    function: Box<Fn(TIn) -> Result<TOut, TErr>>
}

pub fn make_tool<TIn: Deserialize, TOut: Serialize, TErr: Serialize, F: 'static+Fn(TIn) -> Result<TOut, TErr>>(function: F) -> FnTool<TIn, TOut, TErr> {
    FnTool { function: Box::new(function) }
}

impl<TIn, TOut, TErr> JsonTool for FnTool<TIn, TOut, TErr>
where TIn: Deserialize, TOut: Serialize, TErr: Serialize {
    fn invoke_json(&self, input: Value) -> Result<Value, Value> {
        // Decode
        let input_decoded = from_value::<TIn>(input);

        // Chain into the tool itself
        match input_decoded {
            Ok(input_decoded) => {
                // Successfully decoded as the tool's input format
                let result = (self.function)(input_decoded);

                // Encode the error or the result
                // The encoding can go wrong, and we need to handle it slightly differently for the error or the success case
                match result {
                    Ok(res) => {
                        let encoded = to_value(res);
                        match encoded {
                            Ok(final_value) => Ok(final_value),
                            Err(erm)        => Err(json![{
                                "error":        "JSON encode failed",
                                "description":  erm.description()
                            }])
                        }
                    },

                    Err(erm) => {
                        let encoded = to_value(erm);
                        match encoded {
                            Ok(final_value) => Ok(final_value),
                            Err(erm)        => Err(json![{
                                "error":        "Error encode failed",
                                "description":  erm.description()
                            }])
                        }
                    }
                }
            },

            Err(input_error) => {
                // Input does not match the format expected by the tool
                Err(json![{
                    "error":        "JSON input decode failed",
                    "description":  input_error.description(),
                }])
            }
        }
    }
}

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

    #[derive(Serialize, Deserialize)]
    struct TestIn {
        input: i32
    }

    #[derive(Serialize, Deserialize, PartialEq, Eq)]
    struct TestOut {
        output: i32
    }

    fn test_tool(x: TestIn) -> Result<TestOut, ()> {
        Ok(TestOut { output: x.input + 1 })
    }

    #[test]
    fn can_call_tool_via_json_interface() {
        let tool = make_tool(test_tool);
        let result = tool.invoke_json(json![{ "input": 4 }]);

        assert!(result == Ok(json![{ "output": 5 }]));
    }
}
<commit_msg>Add doc comment<commit_after>//!
//! # Tools
//!

use std::result::Result;
use std::error::Error;
use serde::*;
use serde_json::*;

///
/// Trait implemented by things that represent a tool
///
/// A tool is simply a routine that takes some input, does some processing
/// and returns a value or an error. The main difference between a tool and
/// a simple function is that a tool's input and output must be simple data,
/// which for Rust we define as 'can be serialized to JSON'.
///
/// Tools also have the requirement that they are encapsulated and can instantiate
/// themselves with no dependencies other than those they can discover from
/// their environment.
///
/// These two requirements mean that tools can be invoked simply by specifying
/// the input data (without necessarily having to know the exact Rust type involved!).
/// Test cases for tools can be specified as simple JSON data with no need for any
/// actual code. Tools can be turned into stand-alone command line programs or
/// web endpoints with no modification.
///
pub trait JsonTool {
    ///
    /// Invokes this tool with its input and output specified using JSON
    ///
    fn invoke_json(&self, input: Value) -> Result<Value, Value>;
}

///
/// Represents a tool made from a function
///
pub struct FnTool<TIn: Deserialize, TOut: Serialize, TErr: Serialize> {
    function: Box<Fn(TIn) -> Result<TOut, TErr>>
}

///
/// Creates a Tool from a function
///
pub fn make_tool<TIn: Deserialize, TOut: Serialize, TErr: Serialize, F: 'static+Fn(TIn) -> Result<TOut, TErr>>(function: F) -> FnTool<TIn, TOut, TErr> {
    FnTool { function: Box::new(function) }
}

impl<TIn, TOut, TErr> JsonTool for FnTool<TIn, TOut, TErr>
where TIn: Deserialize, TOut: Serialize, TErr: Serialize {
    fn invoke_json(&self, input: Value) -> Result<Value, Value> {
        // Decode
        let input_decoded = from_value::<TIn>(input);

        // Chain into the tool itself
        match input_decoded {
            Ok(input_decoded) => {
                // Successfully decoded as the tool's input format
                let result = (self.function)(input_decoded);

                // Encode the error or the result
                // The encoding can go wrong, and we need to handle it slightly differently for the error or the success case
                match result {
                    Ok(res) => {
                        let encoded = to_value(res);
                        match encoded {
                            Ok(final_value) => Ok(final_value),
                            Err(erm)        => Err(json![{
                                "error":        "JSON encode failed",
                                "description":  erm.description()
                            }])
                        }
                    },

                    Err(erm) => {
                        let encoded = to_value(erm);
                        match encoded {
                            Ok(final_value) => Ok(final_value),
                            Err(erm)        => Err(json![{
                                "error":        "Error encode failed",
                                "description":  erm.description()
                            }])
                        }
                    }
                }
            },

            Err(input_error) => {
                // Input does not match the format expected by the tool
                Err(json![{
                    "error":        "JSON input decode failed",
                    "description":  input_error.description(),
                }])
            }
        }
    }
}

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

    #[derive(Serialize, Deserialize)]
    struct TestIn {
        input: i32
    }

    #[derive(Serialize, Deserialize, PartialEq, Eq)]
    struct TestOut {
        output: i32
    }

    fn test_tool(x: TestIn) -> Result<TestOut, ()> {
        Ok(TestOut { output: x.input + 1 })
    }

    #[test]
    fn can_call_tool_via_json_interface() {
        let tool = make_tool(test_tool);
        let result = tool.invoke_json(json![{ "input": 4 }]);

        assert!(result == Ok(json![{ "output": 5 }]));
    }
}
<|endoftext|>


<commit_before>use futures::{Future, future};
use futures::sync::oneshot;
use std::collections::{HashMap, VecDeque};
use std::sync::{Arc, Mutex, RwLock, Weak};
use uuid::Uuid;

#[derive(Debug, PartialEq)]
pub enum Error {
    Invalid,
    NotFound,
    Dropped,
    NotReady,
    Eof,
    Other,
}

pub const MAX_SIZE: usize = 65536;
pub const MAX_CAPACITY: u64 = 16777216;

#[derive(Debug)]
pub enum Chunk {
    Data(u64, Vec<u8>),
    Eof(u64),
}

impl Chunk {
    fn data(data: Vec<u8>) -> Self {
        Chunk::Data(0, data)
    }

    fn eof() -> Self {
        Chunk::Eof(0)
    }

    fn count(&self) -> u64 {
        match *self {
            Chunk::Data(count, ..) => count,
            Chunk::Eof(count, ..) => count,
        }
    }

    fn len(&self) -> u64 {
        match *self {
            Chunk::Data(_, ref data) => data.len() as u64,
            Chunk::Eof(..) => 0,
        }
    }
}

type SharedChunk = Arc<Mutex<Chunk>>;

#[derive(Clone, Debug)]
enum State {
    Streaming,
    Stop,
}

pub struct Config {
    pub length: Option<u64>,
    pub capacity: u64,
    pub lifecount: u64,
}

pub struct Statistic {
    pub pushed: u64,
    pub dropped: u64,
    pub buffered: u64,
}

pub struct Flow {
    reference: Weak<RwLock<Flow>>,
    pub id: String,
    pub config: Config,
    pub statistic: Statistic,
    state: State,
    next_index: u64,
    head_index: u64,
    pub tail_index: u64,
    bucket: HashMap<u64, SharedChunk>,
    waiting_push: VecDeque<(u64, oneshot::Sender<()>)>,
    waiting_pull: Arc<Mutex<HashMap<u64, Vec<oneshot::Sender<SharedChunk>>>>>,
}

type FlowFuture<T> = future::BoxFuture<T, Error>;

impl Flow {
    pub fn new(length: Option<u64>) -> Arc<RwLock<Self>> {
        let mut flow = Flow {
            reference: Weak::new(),
            id: Uuid::new_v4().simple().to_string(),
            config: Config {
                length,
                capacity: MAX_CAPACITY,
                lifecount: 1,
            },
            statistic: Statistic {
                pushed: 0,
                dropped: 0,
                buffered: 0,
            },
            state: State::Streaming,
            next_index: 0,
            head_index: 0,
            tail_index: 0,
            bucket: HashMap::new(),
            waiting_push: VecDeque::new(),
            waiting_pull: Arc::new(Mutex::new(HashMap::new())),
        };
        let flow_ptr = Arc::new(RwLock::new(flow));
        flow_ptr.write().unwrap().reference = Arc::downgrade(&flow_ptr);
        flow_ptr
    }

    fn is_streaming(&self) -> bool {
        match self.state {
            State::Streaming => true,
            _ => false,
        }
    }

    fn acquire_chunk(&mut self, chunk: Chunk) -> FlowFuture<u64> {
        let chunk_len = chunk.len() as u64;

        // Check if the flow is EOF.
        if !self.is_streaming() {
            return future::err(Error::Invalid).boxed();
        }
        // Check if the flow is already overflow.
        if self.statistic.buffered > self.config.capacity {
            return future::err(Error::Invalid).boxed();
        }

        // Update statistic.
        let new_pushed = match self.statistic.pushed.checked_add(chunk_len) {
            Some(new_pushed) => {
                if let Some(length) = self.config.length {
                    // Check if the length is over.
                    if new_pushed > length {
                        return future::err(Error::Invalid).boxed();
                    }
                }
                new_pushed
            }
            None => return future::err(Error::Invalid).boxed(),
        };
        let new_buffered = match self.statistic.buffered.checked_add(chunk_len) {
            Some(new_buffered) => new_buffered,
            None => return future::err(Error::Invalid).boxed(),
        };
        self.statistic.pushed = new_pushed;
        self.statistic.buffered = new_buffered;

        // Update EOF state.
        if let Chunk::Eof(..) = chunk {
            self.state = State::Stop;
        }

        // Acquire the chunk index.
        let chunk_index = self.next_index;
        self.next_index += 1;

        let shared_chunk = Arc::new(Mutex::new(chunk));
        // Insert the chunk.
        self.bucket.insert(chunk_index, shared_chunk.clone());

        // Check if we need to block for overflow.
        let fut = if self.statistic.buffered > self.config.capacity {
            let (tx, rx) = oneshot::channel();
            self.waiting_push.push_back((chunk_len, tx));
            rx.map_err(|_| Error::Other).boxed()
        } else {
            future::ok(()).boxed()
        };

        // Wake up the waiting pulls.
        let mut waiting_pull = self.waiting_pull.lock().unwrap();
        if let Some(waits) = waiting_pull.remove(&chunk_index) {
            for wait in waits {
                // Don't unwrap, since the receiver can early quit.
                wait.send(shared_chunk.clone()).is_ok();
            }
        }

        fut.map(move |_| chunk_index).boxed()
    }

    fn sanitize_buffer(&mut self) {
        let mut tail_index = self.tail_index;
        let head_index = self.head_index;

        while tail_index < head_index {
            {
                // Get should always success.
                let chunk = self.bucket.get(&tail_index).unwrap().lock().unwrap();
                if chunk.count() < self.config.lifecount {
                    break;
                }

                self.statistic.buffered -= chunk.len();

                let mut remain = chunk.len();
                while remain > 0 {
                    let new_wait = if let Some(wait) = self.waiting_push.front_mut() {
                        let (new_remain, new_wait) = if remain >= wait.0 {
                            (remain - wait.0, 0)
                        } else {
                            (0, wait.0 - remain)
                        };
                        remain = new_remain;
                        wait.0 = new_wait;
                        wait.0
                    } else {
                        break;
                    };
                    if new_wait == 0 {
                        // Remove should always success.
                        self.waiting_push.pop_front().unwrap();
                    }
                }
            }

            // Remove should always success.
            self.bucket.remove(&tail_index).unwrap();

            tail_index += 1;
        }

        self.tail_index = tail_index;
    }

    pub fn push(&mut self, data: &[u8]) -> FlowFuture<u64> {
        if data.len() > MAX_SIZE {
            return future::err(Error::Invalid).boxed();
        }
        self.acquire_chunk(Chunk::data(data.to_vec()))
    }

    pub fn close(&mut self) -> FlowFuture<()> {
        if self.is_streaming() {
            self.acquire_chunk(Chunk::eof()).map(|_| ()).boxed()
        } else {
            future::err(Error::Invalid).boxed()
        }
    }

    pub fn pull(&self, chunk_index: u64, timeout: Option<u64>) -> FlowFuture<Vec<u8>> {
        // Clone the chunk if exists.
        let chunk = match self.bucket.get(&chunk_index) {
            Some(chunk) => Some(chunk.clone()),
            None => None,
        };
        // Try to get the chunk.
        let fut = if let Some(chunk) = chunk {
            future::ok(chunk).boxed()
        } else {
            if chunk_index < self.next_index {
                future::err(Error::Dropped).boxed()
            } else if let Some(0) = timeout {
                future::err(Error::NotReady).boxed()
            } else {
                let (tx, rx) = oneshot::channel();
                let mut waiting_pull = self.waiting_pull.lock().unwrap();
                let waits = waiting_pull.entry(chunk_index).or_insert(Vec::new());
                waits.push(tx);
                rx.map_err(|_| Error::Other).boxed()
            }
        };

        let flow_ref = self.reference.clone();
        let lifecount = self.config.lifecount;
        fut.and_then(move |chunk| {
                let flow_ptr = match flow_ref.upgrade() {
                    Some(ptr) => ptr.clone(),
                    None => return future::err(Error::Other),
                };

                let mut chunk = chunk.lock().unwrap();
                let (count, result) = match *chunk {
                    Chunk::Data(ref mut count, ref data) => (count, Ok(data.to_vec())),
                    Chunk::Eof(ref mut count) => (count, Err(Error::Eof)),
                };

                *count += 1;

                if *count >= lifecount {
                    let mut flow = flow_ptr.write().unwrap();
                    flow.sanitize_buffer();
                }

                future::result(result)
            })
            .boxed()
    }
}

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

    macro_rules! sync_assert_eq {
        ($a:expr, $b:expr) => {
            let fut = $a;
            assert_eq!(fut.wait(), $b);
        }
    }

    #[test]
    fn basic_flow_operations() {
        let ptr = Flow::new(None);
        sync_assert_eq!(ptr.write().unwrap().push(&[1u8; 1234]), Ok(0));
        sync_assert_eq!(ptr.write().unwrap().push(&[2u8; MAX_SIZE]), Ok(1));
        sync_assert_eq!(ptr.write().unwrap().push(b"hello"), Ok(2));
        sync_assert_eq!(ptr.write().unwrap().push(&[2u8; MAX_SIZE + 1]), Err(Error::Invalid));
        sync_assert_eq!(ptr.read().unwrap().pull(2, Some(0)), Ok(Vec::from(b"hello" as &[u8])));
        sync_assert_eq!(ptr.read().unwrap().pull(100, Some(0)), Err(Error::NotReady));
    }

    #[test]
    fn fixed_size_flow() {
        let ptr = Flow::new(Some(10));
        sync_assert_eq!(ptr.write().unwrap().push(b"hello"), Ok(0));
        sync_assert_eq!(ptr.write().unwrap().push(b"world"), Ok(1));
        sync_assert_eq!(ptr.write().unwrap().push(b"!"), Err(Error::Invalid));
    }

    #[test]
    fn pull_chunk() {
        let ptr = Flow::new(None);
        sync_assert_eq!(ptr.read().unwrap().pull(0, Some(0)), Err(Error::NotReady));
        let fut = ptr.read().unwrap().pull(1, None);
        let fut1 = ptr.write().unwrap().push(b"ello");
        let fut2 = ptr.write().unwrap().push(b"hello");
        sync_assert_eq!(fut.join3(fut1, fut2), Ok((Vec::from(b"hello" as &[u8]), 0, 1)));
    }

    #[test]
    fn close_flow() {
        let ptr = Flow::new(None);
        sync_assert_eq!(ptr.write().unwrap().push(b"hello"), Ok(0));
        sync_assert_eq!(ptr.read().unwrap().pull(0, Some(0)), Ok(Vec::from(b"hello" as &[u8])));
        sync_assert_eq!(ptr.write().unwrap().close(), Ok(()));
        sync_assert_eq!(ptr.write().unwrap().push(b"hello"), Err(Error::Invalid));
        sync_assert_eq!(ptr.read().unwrap().pull(1, Some(0)), Err(Error::Eof));
        sync_assert_eq!(ptr.write().unwrap().close(), Err(Error::Invalid));
    }
}
<commit_msg>Add dropped test<commit_after>use futures::{Future, future};
use futures::sync::oneshot;
use std::collections::{HashMap, VecDeque};
use std::sync::{Arc, Mutex, RwLock, Weak};
use uuid::Uuid;

#[derive(Debug, PartialEq)]
pub enum Error {
    Invalid,
    NotFound,
    Dropped,
    NotReady,
    Eof,
    Other,
}

pub const MAX_SIZE: usize = 65536;
pub const MAX_CAPACITY: u64 = 16777216;

#[derive(Debug)]
pub enum Chunk {
    Data(u64, Vec<u8>),
    Eof(u64),
}

impl Chunk {
    fn data(data: Vec<u8>) -> Self {
        Chunk::Data(0, data)
    }

    fn eof() -> Self {
        Chunk::Eof(0)
    }

    fn count(&self) -> u64 {
        match *self {
            Chunk::Data(count, ..) => count,
            Chunk::Eof(count, ..) => count,
        }
    }

    fn len(&self) -> u64 {
        match *self {
            Chunk::Data(_, ref data) => data.len() as u64,
            Chunk::Eof(..) => 0,
        }
    }
}

type SharedChunk = Arc<Mutex<Chunk>>;

#[derive(Clone, Debug)]
enum State {
    Streaming,
    Stop,
}

pub struct Config {
    pub length: Option<u64>,
    pub capacity: u64,
    pub lifecount: u64,
}

pub struct Statistic {
    pub pushed: u64,
    pub dropped: u64,
    pub buffered: u64,
}

pub struct Flow {
    reference: Weak<RwLock<Flow>>,
    pub id: String,
    pub config: Config,
    pub statistic: Statistic,
    state: State,
    next_index: u64,
    pub tail_index: u64,
    bucket: HashMap<u64, SharedChunk>,
    waiting_push: VecDeque<(u64, oneshot::Sender<()>)>,
    waiting_pull: Arc<Mutex<HashMap<u64, Vec<oneshot::Sender<SharedChunk>>>>>,
}

type FlowFuture<T> = future::BoxFuture<T, Error>;

impl Flow {
    pub fn new(length: Option<u64>) -> Arc<RwLock<Self>> {
        let flow = Flow {
            reference: Weak::new(),
            id: Uuid::new_v4().simple().to_string(),
            config: Config {
                length,
                capacity: MAX_CAPACITY,
                lifecount: 1,
            },
            statistic: Statistic {
                pushed: 0,
                dropped: 0,
                buffered: 0,
            },
            state: State::Streaming,
            next_index: 0,
            tail_index: 0,
            bucket: HashMap::new(),
            waiting_push: VecDeque::new(),
            waiting_pull: Arc::new(Mutex::new(HashMap::new())),
        };
        let flow_ptr = Arc::new(RwLock::new(flow));
        flow_ptr.write().unwrap().reference = Arc::downgrade(&flow_ptr);
        flow_ptr
    }

    fn is_streaming(&self) -> bool {
        match self.state {
            State::Streaming => true,
            _ => false,
        }
    }

    fn acquire_chunk(&mut self, chunk: Chunk) -> FlowFuture<u64> {
        let chunk_len = chunk.len() as u64;

        // Check if the flow is EOF.
        if !self.is_streaming() {
            return future::err(Error::Invalid).boxed();
        }
        // Check if the flow is already overflow.
        if self.statistic.buffered > self.config.capacity {
            return future::err(Error::Invalid).boxed();
        }

        // Update statistic.
        let new_pushed = match self.statistic.pushed.checked_add(chunk_len) {
            Some(new_pushed) => {
                if let Some(length) = self.config.length {
                    // Check if the length is over.
                    if new_pushed > length {
                        return future::err(Error::Invalid).boxed();
                    }
                }
                new_pushed
            }
            None => return future::err(Error::Invalid).boxed(),
        };
        let new_buffered = match self.statistic.buffered.checked_add(chunk_len) {
            Some(new_buffered) => new_buffered,
            None => return future::err(Error::Invalid).boxed(),
        };
        self.statistic.pushed = new_pushed;
        self.statistic.buffered = new_buffered;

        // Update EOF state.
        if let Chunk::Eof(..) = chunk {
            self.state = State::Stop;
        }

        // Acquire the chunk index.
        let chunk_index = self.next_index;
        self.next_index += 1;

        let shared_chunk = Arc::new(Mutex::new(chunk));
        // Insert the chunk.
        self.bucket.insert(chunk_index, shared_chunk.clone());

        // Check if we need to block for overflow.
        let fut = if self.statistic.buffered > self.config.capacity {
            let (tx, rx) = oneshot::channel();
            self.waiting_push.push_back((chunk_len, tx));
            rx.map_err(|_| Error::Other).boxed()
        } else {
            future::ok(()).boxed()
        };

        // Wake up the waiting pulls.
        let mut waiting_pull = self.waiting_pull.lock().unwrap();
        if let Some(waits) = waiting_pull.remove(&chunk_index) {
            for wait in waits {
                // Don't unwrap, since the receiver can early quit.
                wait.send(shared_chunk.clone()).is_ok();
            }
        }

        fut.map(move |_| chunk_index).boxed()
    }

    fn sanitize_buffer(&mut self) {
        let mut tail_index = self.tail_index;
        let next_index = self.next_index;
        let lifecount = self.config.lifecount;

        while tail_index < next_index {
            {
                // Get should always success.
                let chunk = self.bucket.get(&tail_index).unwrap().lock().unwrap();
                if chunk.count() < lifecount {
                    break;
                }

                self.statistic.buffered -= chunk.len();

                let mut remain = chunk.len();
                while remain > 0 {
                    let new_wait = if let Some(wait) = self.waiting_push.front_mut() {
                        let (new_remain, new_wait) = if remain >= wait.0 {
                            (remain - wait.0, 0)
                        } else {
                            (0, wait.0 - remain)
                        };
                        remain = new_remain;
                        wait.0 = new_wait;
                        wait.0
                    } else {
                        break;
                    };
                    if new_wait == 0 {
                        // Remove should always success.
                        self.waiting_push.pop_front().unwrap();
                    }
                }
            }

            // Remove should always success.
            self.bucket.remove(&tail_index).unwrap();

            tail_index += 1;
        }

        self.tail_index = tail_index;
    }

    pub fn push(&mut self, data: &[u8]) -> FlowFuture<u64> {
        if data.len() > MAX_SIZE {
            return future::err(Error::Invalid).boxed();
        }
        self.acquire_chunk(Chunk::data(data.to_vec()))
    }

    pub fn close(&mut self) -> FlowFuture<()> {
        if self.is_streaming() {
            self.acquire_chunk(Chunk::eof()).map(|_| ()).boxed()
        } else {
            future::err(Error::Invalid).boxed()
        }
    }

    pub fn pull(&self, chunk_index: u64, timeout: Option<u64>) -> FlowFuture<Vec<u8>> {
        // Clone the chunk if exists.
        let chunk = match self.bucket.get(&chunk_index) {
            Some(chunk) => Some(chunk.clone()),
            None => None,
        };
        // Try to get the chunk.
        let fut = if let Some(chunk) = chunk {
            future::ok(chunk).boxed()
        } else {
            if chunk_index < self.next_index {
                future::err(Error::Dropped).boxed()
            } else if let Some(0) = timeout {
                future::err(Error::NotReady).boxed()
            } else {
                let (tx, rx) = oneshot::channel();
                let mut waiting_pull = self.waiting_pull.lock().unwrap();
                let waits = waiting_pull.entry(chunk_index).or_insert(Vec::new());
                waits.push(tx);
                rx.map_err(|_| Error::Other).boxed()
            }
        };

        let flow_ref = self.reference.clone();
        let lifecount = self.config.lifecount;
        fut.and_then(move |chunk| {
                let flow_ptr = match flow_ref.upgrade() {
                    Some(ptr) => ptr.clone(),
                    None => return future::err(Error::Other),
                };

                let (count, result) = {
                    let mut chunk = chunk.lock().unwrap();
                    let (count, result) = match *chunk {
                        Chunk::Data(ref mut count, ref data) => (count, Ok(data.to_vec())),
                        Chunk::Eof(ref mut count) => (count, Err(Error::Eof)),
                    };
                    *count += 1;
                    (*count, result)
                };

                // Fast check if we need to sanitize.
                if count >= lifecount {
                    let mut flow = flow_ptr.write().unwrap();
                    flow.sanitize_buffer();
                }

                future::result(result)
            })
            .boxed()
    }
}

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

    macro_rules! sync_assert_eq {
        ($a:expr, $b:expr) => {
            let fut = $a;
            assert_eq!(fut.wait(), $b);
        }
    }

    #[test]
    fn basic_flow_operations() {
        let ptr = Flow::new(None);
        sync_assert_eq!(ptr.write().unwrap().push(&[1u8; 1234]), Ok(0));
        sync_assert_eq!(ptr.write().unwrap().push(&[2u8; MAX_SIZE]), Ok(1));
        sync_assert_eq!(ptr.write().unwrap().push(b"hello"), Ok(2));
        sync_assert_eq!(ptr.write().unwrap().push(&[2u8; MAX_SIZE + 1]), Err(Error::Invalid));
        sync_assert_eq!(ptr.read().unwrap().pull(0, Some(0)), Ok(Vec::from(&[1u8; 1234] as &[u8])));
        sync_assert_eq!(ptr.read().unwrap().pull(2, Some(0)), Ok(Vec::from(b"hello" as &[u8])));
        sync_assert_eq!(ptr.read().unwrap().pull(100, Some(0)), Err(Error::NotReady));
    }

    #[test]
    fn fixed_size_flow() {
        let ptr = Flow::new(Some(10));
        sync_assert_eq!(ptr.write().unwrap().push(b"hello"), Ok(0));
        sync_assert_eq!(ptr.write().unwrap().push(b"world"), Ok(1));
        sync_assert_eq!(ptr.write().unwrap().push(b"!"), Err(Error::Invalid));
    }

    #[test]
    fn pull_chunk() {
        let ptr = Flow::new(None);
        sync_assert_eq!(ptr.read().unwrap().pull(0, Some(0)), Err(Error::NotReady));
        let fut = ptr.read().unwrap().pull(1, None);
        let fut1 = ptr.write().unwrap().push(b"ello");
        let fut2 = ptr.write().unwrap().push(b"hello");
        sync_assert_eq!(fut.join3(fut1, fut2), Ok((Vec::from(b"hello" as &[u8]), 0, 1)));
    }

    #[test]
    fn close_flow() {
        let ptr = Flow::new(None);
        sync_assert_eq!(ptr.write().unwrap().push(b"hello"), Ok(0));
        sync_assert_eq!(ptr.read().unwrap().pull(0, Some(0)), Ok(Vec::from(b"hello" as &[u8])));
        sync_assert_eq!(ptr.write().unwrap().close(), Ok(()));
        sync_assert_eq!(ptr.write().unwrap().push(b"hello"), Err(Error::Invalid));
        sync_assert_eq!(ptr.read().unwrap().pull(1, Some(0)), Err(Error::Eof));
        sync_assert_eq!(ptr.write().unwrap().close(), Err(Error::Invalid));
    }

    #[test]
    fn dropped_chunk() {
        let ptr = Flow::new(None);
        sync_assert_eq!(ptr.write().unwrap().push(b"A"), Ok(0));
        sync_assert_eq!(ptr.write().unwrap().push(b"B"), Ok(1));
        sync_assert_eq!(ptr.write().unwrap().push(b"C"), Ok(2));
        sync_assert_eq!(ptr.read().unwrap().pull(0, Some(0)), Ok(Vec::from(b"A" as &[u8])));
        sync_assert_eq!(ptr.read().unwrap().pull(0, Some(0)), Err(Error::Dropped));
    }
}
<|endoftext|>


<commit_before>extern crate env_logger;
extern crate lapin_futures as lapin;
#[macro_use]
extern crate log;
extern crate futures;
extern crate tokio;

use std::io;

use futures::future::Future;
use futures::{IntoFuture, Stream};
use tokio::io::{AsyncRead, AsyncWrite};
use tokio::net::TcpStream;
use tokio::runtime::Runtime;
use lapin::types::FieldTable;
use lapin::client::{Client, ConnectionOptions};
use lapin::channel::{BasicConsumeOptions, BasicProperties, BasicPublishOptions, ConfirmSelectOptions, QueueDeclareOptions};

const N_CONSUMERS : u8 = 8;
const N_MESSAGES  : u8 = 5;

fn create_consumer<T: AsyncRead + AsyncWrite + Sync + Send + 'static>(client: &Client<T>, n: u8) -> impl Future<Item = (), Error = ()> + Send + 'static {
    info!("will create consumer {}", n);

    let queue = format!("test-queue-{}", n);

    client.create_confirm_channel(ConfirmSelectOptions::default()).and_then(move |channel| {
        info!("creating queue {}", queue);
        channel.queue_declare(&queue, QueueDeclareOptions::default(), FieldTable::new()).map(move |queue| (channel, queue))
    }).and_then(move |(channel, queue)| {
        info!("creating consumer {}", n);
        channel.basic_consume(&queue, "", BasicConsumeOptions::default(), FieldTable::new()).map(move |stream| (channel, stream))
    }).and_then(move |(channel, stream)| {
        info!("got stream for consumer {}", n);
        stream.for_each(move |message| {
            println!("consumer '{}' got '{}'", n, std::str::from_utf8(&message.data).unwrap());
            channel.basic_ack(message.delivery_tag, false)
        })
    }).map(|_| ()).map_err(move |err| eprintln!("got error in consumer '{}': {:?}", n, err))
}

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

    let addr        = std::env::var("AMQP_ADDR").unwrap_or_else(|_| "127.0.0.1:5672".to_string()).parse().unwrap();
    let mut runtime = Runtime::new().unwrap();
    // let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap();

    runtime.block_on(
        TcpStream::connect(&addr).and_then(|stream| {
            Client::connect(stream, ConnectionOptions {
                frame_max: 65535,
                ..Default::default()
            })
        }).and_then(|(client, heartbeat)| {
            tokio::spawn(heartbeat.map_err(|e| eprintln!("heartbeat error: {:?}", e)))
                .into_future().map(|_| client).map_err(|_| io::Error::new(io::ErrorKind::Other, "spawn error"))
        }).and_then(|client| {
            let _client = client.clone();
            futures::stream::iter_ok(0..N_CONSUMERS).for_each(move |n| tokio::spawn(create_consumer(&_client, n)))
                .into_future().map(move |_| client).map_err(|_| io::Error::new(io::ErrorKind::Other, "spawn error"))
        }).and_then(|client| {
            client.create_confirm_channel(ConfirmSelectOptions::default()).and_then(move |channel| {
                futures::stream::iter_ok((0..N_CONSUMERS).flat_map(|c| {
                    (0..N_MESSAGES).map(move |m| (c, m))
                })).for_each(move |(c, m)| {
                    let queue   = format!("test-queue-{}", c);
                    let message = format!("message {} for consumer {}", m, c);
                    let channel = channel.clone();

                    info!("will publish {}", message);

                    channel.queue_declare(&queue, QueueDeclareOptions::default(), FieldTable::new()).and_then(move |_| {
                        channel.basic_publish("", &queue, message.as_str().as_bytes(), BasicPublishOptions::default(), BasicProperties::default()).map(move |confirmation| {
                            println!("got confirmation (consumer {}, message {}): {:?}", c, m, confirmation);
                        })
                    })
                })
            })
        }).map_err(|err| eprintln!("error: {:?}", err))
    ).expect("runtime exited with failure");

    runtime.shutdown_on_idle().wait().expect("runtime shutdown exited with error");
}
<commit_msg>futures: lower heartbeat for consumers example<commit_after>extern crate env_logger;
extern crate lapin_futures as lapin;
#[macro_use]
extern crate log;
extern crate futures;
extern crate tokio;

use std::io;

use futures::future::Future;
use futures::{IntoFuture, Stream};
use tokio::io::{AsyncRead, AsyncWrite};
use tokio::net::TcpStream;
use tokio::runtime::Runtime;
use lapin::types::FieldTable;
use lapin::client::{Client, ConnectionOptions};
use lapin::channel::{BasicConsumeOptions, BasicProperties, BasicPublishOptions, ConfirmSelectOptions, QueueDeclareOptions};

const N_CONSUMERS : u8 = 8;
const N_MESSAGES  : u8 = 5;

fn create_consumer<T: AsyncRead + AsyncWrite + Sync + Send + 'static>(client: &Client<T>, n: u8) -> impl Future<Item = (), Error = ()> + Send + 'static {
    info!("will create consumer {}", n);

    let queue = format!("test-queue-{}", n);

    client.create_confirm_channel(ConfirmSelectOptions::default()).and_then(move |channel| {
        info!("creating queue {}", queue);
        channel.queue_declare(&queue, QueueDeclareOptions::default(), FieldTable::new()).map(move |queue| (channel, queue))
    }).and_then(move |(channel, queue)| {
        info!("creating consumer {}", n);
        channel.basic_consume(&queue, "", BasicConsumeOptions::default(), FieldTable::new()).map(move |stream| (channel, stream))
    }).and_then(move |(channel, stream)| {
        info!("got stream for consumer {}", n);
        stream.for_each(move |message| {
            println!("consumer '{}' got '{}'", n, std::str::from_utf8(&message.data).unwrap());
            channel.basic_ack(message.delivery_tag, false)
        })
    }).map(|_| ()).map_err(move |err| eprintln!("got error in consumer '{}': {:?}", n, err))
}

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

    let addr        = std::env::var("AMQP_ADDR").unwrap_or_else(|_| "127.0.0.1:5672".to_string()).parse().unwrap();
    let mut runtime = Runtime::new().unwrap();
    // let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap();

    runtime.block_on(
        TcpStream::connect(&addr).and_then(|stream| {
            Client::connect(stream, ConnectionOptions {
                frame_max: 65535,
                heartbeat: 10,
                ..Default::default()
            })
        }).and_then(|(client, heartbeat)| {
            tokio::spawn(heartbeat.map_err(|e| eprintln!("heartbeat error: {:?}", e)))
                .into_future().map(|_| client).map_err(|_| io::Error::new(io::ErrorKind::Other, "spawn error"))
        }).and_then(|client| {
            let _client = client.clone();
            futures::stream::iter_ok(0..N_CONSUMERS).for_each(move |n| tokio::spawn(create_consumer(&_client, n)))
                .into_future().map(move |_| client).map_err(|_| io::Error::new(io::ErrorKind::Other, "spawn error"))
        }).and_then(|client| {
            client.create_confirm_channel(ConfirmSelectOptions::default()).and_then(move |channel| {
                futures::stream::iter_ok((0..N_CONSUMERS).flat_map(|c| {
                    (0..N_MESSAGES).map(move |m| (c, m))
                })).for_each(move |(c, m)| {
                    let queue   = format!("test-queue-{}", c);
                    let message = format!("message {} for consumer {}", m, c);
                    let channel = channel.clone();

                    info!("will publish {}", message);

                    channel.queue_declare(&queue, QueueDeclareOptions::default(), FieldTable::new()).and_then(move |_| {
                        channel.basic_publish("", &queue, message.as_str().as_bytes(), BasicPublishOptions::default(), BasicProperties::default()).map(move |confirmation| {
                            println!("got confirmation (consumer {}, message {}): {:?}", c, m, confirmation);
                        })
                    })
                })
            })
        }).map_err(|err| eprintln!("error: {:?}", err))
    ).expect("runtime exited with failure");

    runtime.shutdown_on_idle().wait().expect("runtime shutdown exited with error");
}
<|endoftext|>