<commit_before>use std::ops::{Add, Neg, Sub};

use euclid::*;

use num::Integer as IntegerTrait;
use rug::Integer;
use rug;
use rug::ops::{DivRounding, Pow};

use defs::*;

#[inline]
pub fn coerce_up(v: ChildVec) -> UVec {
    UVec::new(v.x, v.y)
}

#[inline]
pub fn truncate_up(v: ChildVec) -> UVec {
    UVec::new(
        v.x.div_floor(&(ZOOM_SCALE as i32)),
        v.y.div_floor(&(ZOOM_SCALE as i32)),
    )
}

#[inline]
pub fn mod_up(v: ChildVec) -> ChildVec {
    ChildVec::new(v.x % ZOOM_SCALE as i32, v.y % ZOOM_SCALE as i32)
}

#[inline]
pub fn split_up(v: ChildVec) -> (UVec, ChildVec) {
    (truncate_up(v), mod_up(v))
}

#[inline]
pub fn shift_down(v: UVec) -> ChildVec {
    ChildVec::new(v.x * (ZOOM_SCALE as i32), v.y * (ZOOM_SCALE as i32))
}

#[inline]
pub fn coerce_down(v: UVec) -> ChildVec {
    ChildVec::new(v.x, v.y)
}

#[inline]
pub fn add_vec<T: Add<T, Output = T>, U>(
    v: TypedVector2D<T, U>,
    u: TypedVector2D<T, U>,
) -> TypedVector2D<T, U> {
    TypedVector2D::new(v.x + u.x, v.y + u.y)
}

#[inline]
pub fn sub_vec<T: Sub<T, Output = T>, U>(
    v: TypedVector2D<T, U>,
    u: TypedVector2D<T, U>,
) -> TypedVector2D<T, U> {
    TypedVector2D::new(v.x - u.x, v.y - u.y)
}

#[inline]
pub fn scale_vec<U>(v: &TypedVector2D<Integer, U>, amount: Integer) -> TypedVector2D<Integer, U> {
    TypedVector2D::new(amount.clone() * &v.x, amount.clone() * &v.y)
}

#[inline]
pub fn div_vec<U>(v: &TypedVector2D<Integer, U>, amount: &Integer) -> TypedVector2D<Integer, U> {
    TypedVector2D::new(v.x.clone().div_floor(amount), v.y.clone().div_floor(amount))
}

pub fn scaled_bigint_to_float(int: &rug::Integer, scale: i16) -> f32 {
    if scale < 0 {
        (int * rug::Integer::from(ZOOM_SCALE).pow(-scale as u32)).to_f32()
    } else if scale == 0 {
        int.to_f32()
    } else {
        // self.zdelta > 0
        let denom = rug::Integer::from(ZOOM_SCALE).pow(scale as u32);
        rug::Rational::from((int, denom)).to_f32()
    }
}

// TODO: Could be more generic
pub fn smoothstep(x: f32) -> f32 {
    if x < 0.0 {
        0.0
    } else if x > 1.0 {
        1.0
    } else {
        x * x * x * (x * (x * 6.0 - 15.0) + 10.0)
    }
}

// TODO: turn the following into a pub trait TypedRectExt
// pub trait TypedRectExt<T, U> {
//     fn center(&self) -> TypedPoint2D<T, U>;
//     fn transform_to<U2>(&self, other: TypedRect<T, U2>) -> TypedTransform2D<f32, U, U2>;
//     fn transform_to_fit<U2>(&self, other: TypedRect<T, U2>) -> TypedTransform2D<f32, U, U2>;
// }

pub mod transform {
    use euclid::*;
    use defs::*;

    #[inline]
    pub fn screen_to_gl(
        resolution: TypedSize2D<u32, ScreenSpace>,
    ) -> TypedTransform2D<f32, ScreenSpace, GLSpace> {
        let scalex = 1.0 / (resolution.width as f32);
        let scaley = 1.0 / (resolution.height as f32);

        TypedTransform2D::create_scale(scalex, scaley)
    }

    #[inline]
    pub fn rect_to_rect<U, U2>(
        source: &TypedRect<f32, U>,
        target: &TypedRect<f32, U2>,
    ) -> TypedTransform2D<f32, U, U2> {
        let x_scale = target.size.width / source.size.width;
        let y_scale = target.size.height / source.size.height;
        TypedTransform2D::create_translation(-source.origin.x, -source.origin.y)
            .post_scale(x_scale, y_scale)
            .post_translate(TypedVector2D::from_untyped(&target
                .origin
                .to_untyped()
                .to_vector()))
    }

    // TODO: doesn't have to be f32
    // #[inline]
    pub fn fit_rect_in<U, U2>(
        source: &TypedRect<f32, U>,
        target: &TypedRect<f32, U2>,
    ) -> TypedTransform2D<f32, U, U2> {
        let source_ratio = source.size.width / source.size.height;
        let target_ratio = target.size.width / target.size.height;

        if source_ratio > target_ratio {
            // source is wider than target, so fills target width
            let image_height = target.size.width / source_ratio;
            let image_origin_y =
                (target.origin.y + target.size.height / 2.0) - (image_height / 2.0);

            let image = TypedRect::new(
                TypedPoint2D::new(target.origin.x, image_origin_y),
                TypedSize2D::new(target.size.width, image_height),
            );

            rect_to_rect(source, &image)
        } else {
            // source is thinner than target
            let image_width = target.size.height * source_ratio;
            let image_origin_x = (target.origin.x + target.size.width / 2.0) - (image_width / 2.0);

            let image = TypedRect::new(
                TypedPoint2D::new(image_origin_x, target.origin.y),
                TypedSize2D::new(image_width, target.size.height),
            );

            rect_to_rect(source, &image)
        }
    }

    pub fn transform_to_pair<U, U2>(
        transform: &TypedTransform2D<f32, U, U2>,
    ) -> (TypedVector2D<f32, U2>, f32) {
        let offset = transform.transform_point(&TypedPoint2D::new(0.0, 0.0));
        let scale = transform.transform_point(&TypedPoint2D::new(1.0, 0.0)) - offset;

        (offset.to_vector(), scale.x)
    }

    pub fn transform_from_pair<U, U2>(
        offset: TypedVector2D<f32, U2>,
        scale: f32,
    ) -> TypedTransform2D<f32, U, U2> {
        TypedTransform2D::identity()
            .post_scale(scale, scale)
            .post_translate(offset)
    }

    // pub fn transform_scale<U, U2>(
    //     transform: &TypedTransform2D<f32, U, U2>,
    //     amount: f32,
    // ) -> TypedTransform2D<f32, U, U2> {
    //     let (offset, scale) = transform_to_pair(transform);

    //     transform_from_pair(offset * amount, 1.0 + (scale - 1.0) * amount)
    // }

    pub fn lerp<U, U2>(
        transform1: &TypedTransform2D<f32, U, U2>,
        transform2: &TypedTransform2D<f32, U, U2>,
        amount: f32,
    ) -> TypedTransform2D<f32, U, U2> {
        let (offset1, scale1) = transform_to_pair(transform1);
        let (offset2, scale2) = transform_to_pair(transform2);

        transform_from_pair(
            offset1 + (offset2 - offset1) * amount,
            scale1 + (scale2 - scale1) * amount,
        )
    }
}

pub trait To2dGlTransform {
    fn to_gl_mat3(&self) -> [[f32; 3]; 3];
}

impl<U> To2dGlTransform for TypedTransform2D<f32, U, GLSpace> {
    fn to_gl_mat3(&self) -> [[f32; 3]; 3] {
        let [m11, m12, m21, m22, m31, m32] = self.to_row_major_array();

        #[rustfmt_skip]
        [[m11, m12, 0.0],
         [m21, m22, 0.0],
         [m31, m32, 1.0]]
    }
}

pub mod time {
    use std::time;

    // TODO: f64?
    pub fn duration_to_secs(time_delta: time::Duration) -> f32 {
        time_delta.as_secs() as f32 + time_delta.subsec_nanos() as f32 * 1e-9
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right,
}

impl Direction {
    pub fn to_vect<F, U>(self) -> TypedVector2D<F, U>
    where
        F: From<i32>,
    {
        use Direction::*;
        match self {
            Up => TypedVector2D::new(F::from(0), F::from(1)),
            Down => TypedVector2D::new(F::from(0), F::from(-1)),
            Left => TypedVector2D::new(F::from(-1), F::from(0)),
            Right => TypedVector2D::new(F::from(1), F::from(0)),
        }
    }
}
<commit_msg>transform::scale<commit_after>use std::ops::{Add, Neg, Sub};

use euclid::*;

use num::Integer as IntegerTrait;
use rug;
use rug::ops::{DivRounding, Pow};
use rug::Integer;

use defs::*;

#[inline]
pub fn coerce_up(v: ChildVec) -> UVec {
    UVec::new(v.x, v.y)
}

#[inline]
pub fn truncate_up(v: ChildVec) -> UVec {
    UVec::new(
        v.x.div_floor(&(ZOOM_SCALE as i32)),
        v.y.div_floor(&(ZOOM_SCALE as i32)),
    )
}

#[inline]
pub fn mod_up(v: ChildVec) -> ChildVec {
    ChildVec::new(v.x % ZOOM_SCALE as i32, v.y % ZOOM_SCALE as i32)
}

#[inline]
pub fn split_up(v: ChildVec) -> (UVec, ChildVec) {
    (truncate_up(v), mod_up(v))
}

#[inline]
pub fn shift_down(v: UVec) -> ChildVec {
    ChildVec::new(v.x * (ZOOM_SCALE as i32), v.y * (ZOOM_SCALE as i32))
}

#[inline]
pub fn coerce_down(v: UVec) -> ChildVec {
    ChildVec::new(v.x, v.y)
}

#[inline]
pub fn add_vec<T: Add<T, Output = T>, U>(
    v: TypedVector2D<T, U>,
    u: TypedVector2D<T, U>,
) -> TypedVector2D<T, U> {
    TypedVector2D::new(v.x + u.x, v.y + u.y)
}

#[inline]
pub fn sub_vec<T: Sub<T, Output = T>, U>(
    v: TypedVector2D<T, U>,
    u: TypedVector2D<T, U>,
) -> TypedVector2D<T, U> {
    TypedVector2D::new(v.x - u.x, v.y - u.y)
}

#[inline]
pub fn scale_vec<U>(v: &TypedVector2D<Integer, U>, amount: Integer) -> TypedVector2D<Integer, U> {
    TypedVector2D::new(amount.clone() * &v.x, amount.clone() * &v.y)
}

#[inline]
pub fn div_vec<U>(v: &TypedVector2D<Integer, U>, amount: &Integer) -> TypedVector2D<Integer, U> {
    TypedVector2D::new(v.x.clone().div_floor(amount), v.y.clone().div_floor(amount))
}

pub fn scaled_bigint_to_float(int: &rug::Integer, scale: i16) -> f32 {
    if scale < 0 {
        (int * rug::Integer::from(ZOOM_SCALE).pow(-scale as u32)).to_f32()
    } else if scale == 0 {
        int.to_f32()
    } else {
        // self.zdelta > 0
        let denom = rug::Integer::from(ZOOM_SCALE).pow(scale as u32);
        rug::Rational::from((int, denom)).to_f32()
    }
}

// TODO: Could be more generic
pub fn smoothstep(x: f32) -> f32 {
    if x < 0.0 {
        0.0
    } else if x > 1.0 {
        1.0
    } else {
        x * x * x * (x * (x * 6.0 - 15.0) + 10.0)
    }
}

// TODO: turn the following into a pub trait TypedRectExt
// pub trait TypedRectExt<T, U> {
//     fn center(&self) -> TypedPoint2D<T, U>;
//     fn transform_to<U2>(&self, other: TypedRect<T, U2>) -> TypedTransform2D<f32, U, U2>;
//     fn transform_to_fit<U2>(&self, other: TypedRect<T, U2>) -> TypedTransform2D<f32, U, U2>;
// }

pub mod transform {
    use defs::*;
    use euclid::*;

    #[inline]
    pub fn screen_to_gl(
        resolution: TypedSize2D<u32, ScreenSpace>,
    ) -> TypedTransform2D<f32, ScreenSpace, GLSpace> {
        let scalex = 1.0 / (resolution.width as f32);
        let scaley = 1.0 / (resolution.height as f32);

        TypedTransform2D::create_scale(scalex, scaley)
    }

    #[inline]
    pub fn rect_to_rect<U, U2>(
        source: &TypedRect<f32, U>,
        target: &TypedRect<f32, U2>,
    ) -> TypedTransform2D<f32, U, U2> {
        let x_scale = target.size.width / source.size.width;
        let y_scale = target.size.height / source.size.height;
        TypedTransform2D::create_translation(-source.origin.x, -source.origin.y)
            .post_scale(x_scale, y_scale)
            .post_translate(TypedVector2D::from_untyped(&target
                .origin
                .to_untyped()
                .to_vector()))
    }

    // TODO: doesn't have to be f32
    // #[inline]
    pub fn fit_rect_in<U, U2>(
        source: &TypedRect<f32, U>,
        target: &TypedRect<f32, U2>,
    ) -> TypedTransform2D<f32, U, U2> {
        let source_ratio = source.size.width / source.size.height;
        let target_ratio = target.size.width / target.size.height;

        if source_ratio > target_ratio {
            // source is wider than target, so fills target width
            let image_height = target.size.width / source_ratio;
            let image_origin_y =
                (target.origin.y + target.size.height / 2.0) - (image_height / 2.0);

            let image = TypedRect::new(
                TypedPoint2D::new(target.origin.x, image_origin_y),
                TypedSize2D::new(target.size.width, image_height),
            );

            rect_to_rect(source, &image)
        } else {
            // source is thinner than target
            let image_width = target.size.height * source_ratio;
            let image_origin_x = (target.origin.x + target.size.width / 2.0) - (image_width / 2.0);

            let image = TypedRect::new(
                TypedPoint2D::new(image_origin_x, target.origin.y),
                TypedSize2D::new(image_width, target.size.height),
            );

            rect_to_rect(source, &image)
        }
    }

    pub fn transform_to_pair<U, U2>(
        transform: &TypedTransform2D<f32, U, U2>,
    ) -> (TypedVector2D<f32, U2>, f32) {
        let offset = transform.transform_point(&TypedPoint2D::new(0.0, 0.0));
        let scale = transform.transform_point(&TypedPoint2D::new(1.0, 0.0)) - offset;

        (offset.to_vector(), scale.x)
    }

    pub fn scale<U, U2>(t: &TypedTransform2D<f32, U, U2>) -> f32 {
        transform_to_pair(t).1
    }

    pub fn transform_from_pair<U, U2>(
        offset: TypedVector2D<f32, U2>,
        scale: f32,
    ) -> TypedTransform2D<f32, U, U2> {
        TypedTransform2D::identity()
            .post_scale(scale, scale)
            .post_translate(offset)
    }

    // pub fn transform_scale<U, U2>(
    //     transform: &TypedTransform2D<f32, U, U2>,
    //     amount: f32,
    // ) -> TypedTransform2D<f32, U, U2> {
    //     let (offset, scale) = transform_to_pair(transform);

    //     transform_from_pair(offset * amount, 1.0 + (scale - 1.0) * amount)
    // }

    pub fn lerp<U, U2>(
        transform1: &TypedTransform2D<f32, U, U2>,
        transform2: &TypedTransform2D<f32, U, U2>,
        amount: f32,
    ) -> TypedTransform2D<f32, U, U2> {
        let (offset1, scale1) = transform_to_pair(transform1);
        let (offset2, scale2) = transform_to_pair(transform2);

        transform_from_pair(
            offset1 + (offset2 - offset1) * amount,
            scale1 + (scale2 - scale1) * amount,
        )
    }
}

pub trait To2dGlTransform {
    fn to_gl_mat3(&self) -> [[f32; 3]; 3];
}

impl<U> To2dGlTransform for TypedTransform2D<f32, U, GLSpace> {
    fn to_gl_mat3(&self) -> [[f32; 3]; 3] {
        let [m11, m12, m21, m22, m31, m32] = self.to_row_major_array();

        #[rustfmt_skip]
        [[m11, m12, 0.0],
         [m21, m22, 0.0],
         [m31, m32, 1.0]]
    }
}

pub mod time {
    use std::time;

    // TODO: f64?
    pub fn duration_to_secs(time_delta: time::Duration) -> f32 {
        time_delta.as_secs() as f32 + time_delta.subsec_nanos() as f32 * 1e-9
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right,
}

impl Direction {
    pub fn to_vect<F, U>(self) -> TypedVector2D<F, U>
    where
        F: From<i32>,
    {
        use Direction::*;
        match self {
            Up => TypedVector2D::new(F::from(0), F::from(1)),
            Down => TypedVector2D::new(F::from(0), F::from(-1)),
            Left => TypedVector2D::new(F::from(-1), F::from(0)),
            Right => TypedVector2D::new(F::from(1), F::from(0)),
        }
    }
}
<|endoftext|>


<commit_before>use syntax::ptr::P;
use syntax::ast;
use syntax::ast::*;
use syntax::ast_util::{is_comparison_binop, binop_to_string};
use syntax::visit::{FnKind};
use rustc::lint::{Context, LintPass, LintArray, Lint, Level};
use rustc::middle::ty::{self, expr_ty, ty_str, ty_ptr, ty_rptr, ty_float};
use syntax::codemap::{Span, Spanned};

use types::span_note_and_lint;

fn walk_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> {
	match ty.sty {
		ty_ptr(ref tm) | ty_rptr(_, ref tm) => walk_ty(tm.ty),
		_ => ty
	}
}

/// Handles uncategorized lints
/// Currently handles linting of if-let-able matches
#[allow(missing_copy_implementations)]
pub struct MiscPass;

declare_lint!(pub SINGLE_MATCH, Warn,
              "Warn on usage of matches with a single nontrivial arm");

impl LintPass for MiscPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(SINGLE_MATCH)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let ExprMatch(ref ex, ref arms, ast::MatchSource::Normal) = expr.node {
            if arms.len() == 2 {
                if arms[0].guard.is_none() && arms[1].pats.len() == 1 {
                    match arms[1].body.node {
                        ExprTup(ref v) if v.len() == 0 && arms[1].guard.is_none() => (),
                        ExprBlock(ref b) if b.stmts.len() == 0 && arms[1].guard.is_none() => (),
                         _ => return
                    }
                    // In some cases, an exhaustive match is preferred to catch situations when
                    // an enum is extended. So we only consider cases where a `_` wildcard is used
                    if arms[1].pats[0].node == PatWild(PatWildSingle) && arms[0].pats.len() == 1 {
                        let map = cx.sess().codemap();
                        span_note_and_lint(cx, SINGLE_MATCH, expr.span,
                              "You seem to be trying to use match for destructuring a single type. Did you mean to use `if let`?",
                              &*format!("Try if let {} = {} {{ ... }}",
                                      &*map.span_to_snippet(arms[0].pats[0].span).unwrap_or("..".to_string()),
                                      &*map.span_to_snippet(ex.span).unwrap_or("..".to_string()))
                        );
                    }
                }
            }
        }
    }
}

declare_lint!(pub STR_TO_STRING, Warn, "Warn when a String could use to_owned() instead of to_string()");

#[allow(missing_copy_implementations)]
pub struct StrToStringPass;

impl LintPass for StrToStringPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(STR_TO_STRING)
    }

    fn check_expr(&mut self, cx: &Context, expr: &ast::Expr) {
        match expr.node {
            ast::ExprMethodCall(ref method, _, ref args)
                if method.node.as_str() == "to_string"
                && is_str(cx, &*args[0]) => {
                cx.span_lint(STR_TO_STRING, expr.span, "str.to_owned() is faster");
            },
            _ => ()
        }

        fn is_str(cx: &Context, expr: &ast::Expr) -> bool {
            match walk_ty(expr_ty(cx.tcx, expr)).sty {
                ty_str => true,
                _ => false
            }
        }
    }
}

declare_lint!(pub TOPLEVEL_REF_ARG, Warn, "Warn about pattern matches with top-level `ref` bindings");

#[allow(missing_copy_implementations)]
pub struct TopLevelRefPass;

impl LintPass for TopLevelRefPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(TOPLEVEL_REF_ARG)
    }

    fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) {
        for ref arg in decl.inputs.iter() {
            if let PatIdent(BindByRef(_), _, _) = arg.pat.node {
                cx.span_lint(
                    TOPLEVEL_REF_ARG,
                    arg.pat.span,
                    "`ref` directly on a function argument is ignored. Have you considered using a reference type instead?"
                );
            }
        }
    }
}

declare_lint!(pub CMP_NAN, Deny, "Deny comparisons to std::f32::NAN or std::f64::NAN");

#[derive(Copy,Clone)]
pub struct CmpNan;

impl LintPass for CmpNan {
	fn get_lints(&self) -> LintArray {
        lint_array!(CMP_NAN)
	}

	fn check_expr(&mut self, cx: &Context, expr: &Expr) {
		if let ExprBinary(ref cmp, ref left, ref right) = expr.node {
			if is_comparison_binop(cmp.node) {
				if let &ExprPath(_, ref path) = &left.node {
					check_nan(cx, path, expr.span);
				}
				if let &ExprPath(_, ref path) = &right.node {
					check_nan(cx, path, expr.span);
				}
			}
		}
	}
}

fn check_nan(cx: &Context, path: &Path, span: Span) {
	path.segments.last().map(|seg| if seg.identifier.as_str() == "NAN" {
		cx.span_lint(CMP_NAN, span, "Doomed comparison with NAN, use std::{f32,f64}::is_nan instead");
	});
}

declare_lint!(pub FLOAT_CMP, Warn,
			  "Warn on ==/!= comparison of floaty values");

#[derive(Copy,Clone)]
pub struct FloatCmp;

impl LintPass for FloatCmp {
	fn get_lints(&self) -> LintArray {
        lint_array!(FLOAT_CMP)
	}

	fn check_expr(&mut self, cx: &Context, expr: &Expr) {
		if let ExprBinary(ref cmp, ref left, ref right) = expr.node {
			let op = cmp.node;
			if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) {
				let map = cx.sess().codemap();
				cx.span_lint(FLOAT_CMP, expr.span, &format!(
					"{}-Comparison of f32 or f64 detected. You may want to change this to 'abs({} - {}) < epsilon' for some suitable value of epsilon",
					binop_to_string(op), &*map.span_to_snippet(left.span).unwrap_or("..".to_string()),
					&*map.span_to_snippet(right.span).unwrap_or("..".to_string())));
			}
		}
	}
}

fn is_float(cx: &Context, expr: &Expr) -> bool {
	if let ty_float(_) = walk_ty(expr_ty(cx.tcx, expr)).sty { true } else { false }
}

declare_lint!(pub PRECEDENCE, Warn,
			  "Warn on mixing bit ops with integer arithmetic without parenthesis");

#[derive(Copy,Clone)]
pub struct Precedence;

impl LintPass for Precedence {
	fn get_lints(&self) -> LintArray {
        lint_array!(PRECEDENCE)
	}

	fn check_expr(&mut self, cx: &Context, expr: &Expr) {
		if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node {
			if is_bit_op(op) {
				if let ExprBinary(Spanned { node: lop, ..}, _, _) = left.node {
					if is_arith_op(lop) {
						cx.span_lint(PRECEDENCE, expr.span, "Operator precedence can trip the unwary. Please consider adding parenthesis to the subexpression to make the meaning more clear.");
					}
				} else {
					if let ExprBinary(Spanned { node: rop, ..}, _, _) = right.node {
						if is_arith_op(rop) {
							cx.span_lint(PRECEDENCE, expr.span, "Operator precedence can trip the unwary. Please consider adding parenthesis to the subexpression to make the meaning more clear.");
						}
					}
				}
			}
		}
	}
}

fn is_bit_op(op : BinOp_) -> bool {
	match op {
		BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr => true,
		_ => false
	}
}

fn is_arith_op(op : BinOp_) -> bool {
	match op {
		BiAdd | BiSub | BiMul | BiDiv | BiRem => true,
		_ => false
	}
}
<commit_msg>refactored precedence lint<commit_after>use syntax::ptr::P;
use syntax::ast;
use syntax::ast::*;
use syntax::ast_util::{is_comparison_binop, binop_to_string};
use syntax::visit::{FnKind};
use rustc::lint::{Context, LintPass, LintArray, Lint, Level};
use rustc::middle::ty::{self, expr_ty, ty_str, ty_ptr, ty_rptr, ty_float};
use syntax::codemap::{Span, Spanned};

use types::span_note_and_lint;

fn walk_ty<'t>(ty: ty::Ty<'t>) -> ty::Ty<'t> {
	match ty.sty {
		ty_ptr(ref tm) | ty_rptr(_, ref tm) => walk_ty(tm.ty),
		_ => ty
	}
}

/// Handles uncategorized lints
/// Currently handles linting of if-let-able matches
#[allow(missing_copy_implementations)]
pub struct MiscPass;

declare_lint!(pub SINGLE_MATCH, Warn,
              "Warn on usage of matches with a single nontrivial arm");

impl LintPass for MiscPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(SINGLE_MATCH)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let ExprMatch(ref ex, ref arms, ast::MatchSource::Normal) = expr.node {
            if arms.len() == 2 {
                if arms[0].guard.is_none() && arms[1].pats.len() == 1 {
                    match arms[1].body.node {
                        ExprTup(ref v) if v.len() == 0 && arms[1].guard.is_none() => (),
                        ExprBlock(ref b) if b.stmts.len() == 0 && arms[1].guard.is_none() => (),
                         _ => return
                    }
                    // In some cases, an exhaustive match is preferred to catch situations when
                    // an enum is extended. So we only consider cases where a `_` wildcard is used
                    if arms[1].pats[0].node == PatWild(PatWildSingle) && arms[0].pats.len() == 1 {
                        let map = cx.sess().codemap();
                        span_note_and_lint(cx, SINGLE_MATCH, expr.span,
                              "You seem to be trying to use match for destructuring a single type. Did you mean to use `if let`?",
                              &*format!("Try if let {} = {} {{ ... }}",
                                      &*map.span_to_snippet(arms[0].pats[0].span).unwrap_or("..".to_string()),
                                      &*map.span_to_snippet(ex.span).unwrap_or("..".to_string()))
                        );
                    }
                }
            }
        }
    }
}

declare_lint!(pub STR_TO_STRING, Warn, "Warn when a String could use to_owned() instead of to_string()");

#[allow(missing_copy_implementations)]
pub struct StrToStringPass;

impl LintPass for StrToStringPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(STR_TO_STRING)
    }

    fn check_expr(&mut self, cx: &Context, expr: &ast::Expr) {
        match expr.node {
            ast::ExprMethodCall(ref method, _, ref args)
                if method.node.as_str() == "to_string"
                && is_str(cx, &*args[0]) => {
                cx.span_lint(STR_TO_STRING, expr.span, "str.to_owned() is faster");
            },
            _ => ()
        }

        fn is_str(cx: &Context, expr: &ast::Expr) -> bool {
            match walk_ty(expr_ty(cx.tcx, expr)).sty {
                ty_str => true,
                _ => false
            }
        }
    }
}

declare_lint!(pub TOPLEVEL_REF_ARG, Warn, "Warn about pattern matches with top-level `ref` bindings");

#[allow(missing_copy_implementations)]
pub struct TopLevelRefPass;

impl LintPass for TopLevelRefPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(TOPLEVEL_REF_ARG)
    }

    fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) {
        for ref arg in decl.inputs.iter() {
            if let PatIdent(BindByRef(_), _, _) = arg.pat.node {
                cx.span_lint(
                    TOPLEVEL_REF_ARG,
                    arg.pat.span,
                    "`ref` directly on a function argument is ignored. Have you considered using a reference type instead?"
                );
            }
        }
    }
}

declare_lint!(pub CMP_NAN, Deny, "Deny comparisons to std::f32::NAN or std::f64::NAN");

#[derive(Copy,Clone)]
pub struct CmpNan;

impl LintPass for CmpNan {
	fn get_lints(&self) -> LintArray {
        lint_array!(CMP_NAN)
	}

	fn check_expr(&mut self, cx: &Context, expr: &Expr) {
		if let ExprBinary(ref cmp, ref left, ref right) = expr.node {
			if is_comparison_binop(cmp.node) {
				if let &ExprPath(_, ref path) = &left.node {
					check_nan(cx, path, expr.span);
				}
				if let &ExprPath(_, ref path) = &right.node {
					check_nan(cx, path, expr.span);
				}
			}
		}
	}
}

fn check_nan(cx: &Context, path: &Path, span: Span) {
	path.segments.last().map(|seg| if seg.identifier.as_str() == "NAN" {
		cx.span_lint(CMP_NAN, span, "Doomed comparison with NAN, use std::{f32,f64}::is_nan instead");
	});
}

declare_lint!(pub FLOAT_CMP, Warn,
			  "Warn on ==/!= comparison of floaty values");

#[derive(Copy,Clone)]
pub struct FloatCmp;

impl LintPass for FloatCmp {
	fn get_lints(&self) -> LintArray {
        lint_array!(FLOAT_CMP)
	}

	fn check_expr(&mut self, cx: &Context, expr: &Expr) {
		if let ExprBinary(ref cmp, ref left, ref right) = expr.node {
			let op = cmp.node;
			if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) {
				let map = cx.sess().codemap();
				cx.span_lint(FLOAT_CMP, expr.span, &format!(
					"{}-Comparison of f32 or f64 detected. You may want to change this to 'abs({} - {}) < epsilon' for some suitable value of epsilon",
					binop_to_string(op), &*map.span_to_snippet(left.span).unwrap_or("..".to_string()),
					&*map.span_to_snippet(right.span).unwrap_or("..".to_string())));
			}
		}
	}
}

fn is_float(cx: &Context, expr: &Expr) -> bool {
	if let ty_float(_) = walk_ty(expr_ty(cx.tcx, expr)).sty { true } else { false }
}

declare_lint!(pub PRECEDENCE, Warn,
			  "Warn on mixing bit ops with integer arithmetic without parenthesis");

#[derive(Copy,Clone)]
pub struct Precedence;

impl LintPass for Precedence {
	fn get_lints(&self) -> LintArray {
        lint_array!(PRECEDENCE)
	}

	fn check_expr(&mut self, cx: &Context, expr: &Expr) {
		if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node {
			if is_bit_op(op) && (is_arith_expr(left) || is_arith_expr(right)) {
				cx.span_lint(PRECEDENCE, expr.span,
					"Operator precedence can trip the unwary. Consider adding parenthesis to the subexpression.");
			}
		}
	}
}

fn is_arith_expr(expr : &Expr) -> bool {
	match expr.node {
		ExprBinary(Spanned { node: op, ..}, _, _) => is_arith_op(lop),
		_ => false
	}
}

fn is_bit_op(op : BinOp_) -> bool {
	match op {
		BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr => true,
		_ => false
	}
}

fn is_arith_op(op : BinOp_) -> bool {
	match op {
		BiAdd | BiSub | BiMul | BiDiv | BiRem => true,
		_ => false
	}
}
<|endoftext|>


<commit_before>extern mod std;
use std::hashmap::HashMap;
use sexpr;

// A very simple LISP-like language
// Globally scoped, no closures

/// Our value types
#[deriving(Eq)]
#[deriving(Clone)]
pub enum LispValue {
	List(~[LispValue]),
	Atom(~str),
	Str(~str),
	Num(float),
	Fn(~[~str], ~LispValue) // args, body
}

fn from_sexpr(sexpr: &sexpr::Value) -> ~LispValue {
	match *sexpr {
		sexpr::List(ref v) => ~List(v.map(|x| *from_sexpr(x))),
		sexpr::Num(v) => ~Num(v),
		sexpr::Str(ref v) => ~Str(v.clone()),
		sexpr::Atom(ref v) => ~Atom(v.clone())
	}
}

/// The type of the global symbol table (string to a value mapping).
type SymbolTable = HashMap<~str, ~LispValue>;

/// Creates a new symbol table and returns it
pub fn new_symt() -> SymbolTable {
	HashMap::new()
}

/// Binds a symbol in the symbol table. Replaces if it already exists.
pub fn bind(symt: &mut SymbolTable, name: ~str, value: ~LispValue) {
	symt.insert(name, value);
}

/// Look up a symbol in the symbol table. Fails if not found.
pub fn lookup(symt: &SymbolTable, name: ~str) -> ~LispValue {
	match symt.find(&name) {
		Some(v) => v.clone(),
		None => fail!("couldn't find symbol: %s", name)
	}
}

/// Evaluates an s-expression and returns a value.
pub fn eval(symt: &mut SymbolTable, input: sexpr::Value) -> ~LispValue {
	match input {
		sexpr::List(v) => {
			if(v.len() == 0) {
				fail!("eval given empty list")
			}

			// evaluate a list as a function call
			match v[0] {
				sexpr::Atom(sym) => {
					let f = lookup(symt, sym);
					fail!("stub: eval")
				}
				_ => fail!("function calls take an atom"),
			}

		}
		_ => from_sexpr(&input) // return non-list values as they are
	}
}

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

	fn read(input: &str) -> sexpr::Value {
		from_str(input).unwrap()
	}

	#[test]
	fn test_eval() {
		let mut symt = new_symt();
		assert_eq!(eval(&mut symt, read("123")), ~Num(123.0));
		assert_eq!(eval(&mut symt, read("(id 123)")), ~Num(123.0));
		// should fail: assert_eq!(eval(&mut symt, read("(1 2 3)")), ~List(~[Num(1.0), Num(2.0), Num(3.0)]));
	}
}<commit_msg>begin stubbing in apply support, add BIFs, add ugly Eq impl for LispValue<commit_after>extern mod std;
use std::hashmap::HashMap;
use sexpr;

// A very simple LISP-like language
// Globally scoped, no closures

/// Our value types
#[deriving(Clone)]
pub enum LispValue {
	List(~[LispValue]),
	Atom(~str),
	Str(~str),
	Num(float),
	Fn(~[~str], ~LispValue), // args, body
	BIF(~str, ~[~str], extern fn(~[~LispValue])->~LispValue) // built-in function (args, closure)
}

// XXX: this is ugly but it won't automatically derive Eq because of the extern fn
impl Eq for LispValue {
	fn eq(&self, other: &LispValue) -> bool {
		match (self.clone(), other.clone()) {
			(BIF(ref x, _, _), BIF(ref y, _, _)) if *x == *y => true,
			(Str(ref x), Str(ref y)) if *x == *y => true,
			(Num(ref x), Num(ref y)) if *x == *y => true,
			(Atom(ref x), Atom(ref y)) if *x == *y => true,
			(List(ref x), List(ref y)) if *x == *y => true,
			(Fn(ref x, ref x2), Fn(ref y, ref y2)) if *x == *y && *x2 == *y2 => true,
			_ => false
		}
	}
}

fn from_sexpr(sexpr: &sexpr::Value) -> ~LispValue {
	match *sexpr {
		sexpr::List(ref v) => ~List(v.map(|x| *from_sexpr(x))),
		sexpr::Num(v) => ~Num(v),
		sexpr::Str(ref v) => ~Str(v.clone()),
		sexpr::Atom(ref v) => ~Atom(v.clone())
	}
}

/// The type of the global symbol table (string to a value mapping).
type SymbolTable = HashMap<~str, ~LispValue>;

/// Creates a new symbol table and returns it
pub fn new_symt() -> SymbolTable {
	HashMap::new()
}

/// Binds a symbol in the symbol table. Replaces if it already exists.
pub fn bind(symt: &mut SymbolTable, name: ~str, value: ~LispValue) {
	symt.insert(name, value);
}

/// Look up a symbol in the symbol table. Fails if not found.
pub fn lookup(symt: &SymbolTable, name: ~str) -> ~LispValue {
	match symt.find(&name) {
		Some(v) => v.clone(),
		None => fail!("couldn't find symbol: %s", name)
	}
}

fn id_(v: ~[~LispValue]) -> ~LispValue { v[0] }

/// Initializes standard library functions
pub fn init_std(symt: &mut SymbolTable) {
	bind(symt, ~"id", ~BIF(~"id", ~[~"x"], id_));
}

fn apply(symt: &mut SymbolTable, f: ~LispValue, args: ~[~LispValue]) -> ~LispValue {
	fail!("stub: apply")
}

/// Evaluates an s-expression and returns a value.
pub fn eval(symt: &mut SymbolTable, input: sexpr::Value) -> ~LispValue {
	match input {
		sexpr::List(v) => {
			if(v.len() == 0) {
				fail!("eval given empty list")
			}

			// XXX: If we don't clone, the `match` partially moves v,
			// so we can't use it in the match arms.
			let v_ = v.clone();

			// evaluate a list as a function call
			match v[0] {
				sexpr::Atom(sym) => {
					let f = lookup(symt, sym);
					let args = v_.slice(1, v_.len());
					let xargs = args.map(|x| eval(symt, x.clone())); // eval'd args
					apply(symt, f, xargs)
				}
				_ => fail!("function calls take an atom"),
			}

		}
		_ => from_sexpr(&input) // return non-list values as they are
	}
}

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

	fn read(input: &str) -> sexpr::Value {
		from_str(input).unwrap()
	}

	#[test]
	fn test_eval() {
		let mut symt = new_symt();
		init_std(&mut symt);
		assert_eq!(eval(&mut symt, read("123")), ~Num(123.0));
		assert_eq!(eval(&mut symt, read("(id 123)")), ~Num(123.0));
		// should fail: assert_eq!(eval(&mut symt, read("(1 2 3)")), ~List(~[Num(1.0), Num(2.0), Num(3.0)]));
	}
}<|endoftext|>


<commit_before>extern crate zoom;
extern crate rand;

use super::bot::*;
use super::Vec3;

const BOTS_RADIUS_MULTIPLIER: f32 = 5.0;
const RADIUS_STATIC: f32 = 5.0;
const ENERGY_RATIO: f64 = 0.002;
const ENERGY_VARIATION: f64 = 0.1;
pub const ENERGY_THRESHOLD: i64 = 500000;
const ENERGY_FULL_COST: i64 = 5000;
const PHYSICS_RADIUS: f64 = 1.0;

const EDGE_FOOD_BENEFIT: f64 = 1.0;
const EDGE_DIFFUSION_COEFFICIENT: f64 = 0.01;

const DRAG: f64 = 0.1;

#[derive(Clone)]
pub struct RadParticle {
    pub p: zoom::BasicParticle<Vec3, f64>,
}

impl zoom::Position<Vec3> for RadParticle {
    fn position(&self) -> Vec3 {
        self.p.position()
    }
}

impl zoom::Velocity<Vec3> for RadParticle {
    fn velocity(&self) -> Vec3 {
        self.p.velocity()
    }
}

impl zoom::Particle<Vec3, f64> for RadParticle {
    fn impulse(&self, v: &Vec3) {
        self.p.impulse(v);
    }

    fn advance(&mut self, time: f64) {
        self.p.advance(time);
    }
}

impl zoom::Inertia<f64> for RadParticle {
    fn inertia(&self) -> f64 {
        self.p.inertia()
    }
}

impl zoom::Quanta<f64> for RadParticle {
    fn quanta(&self) -> f64 {
        self.p.quanta()
    }
}

impl zoom::PhysicsParticle<Vec3, f64> for RadParticle {

}

impl zoom::Ball<f64> for RadParticle {
    fn radius(&self) -> f64 {
        PHYSICS_RADIUS
    }
}

pub struct Node {
    pub particle: RadParticle,
    pub energy: i64,
    pub bots: Vec<Box<Bot>>,
    pub moved_bots: Vec<Box<Bot>>,
    pub deaths: i64,
    pub moves: i64,
    pub connections: i64,
    pub pull: i64,
    pub diffuse: i64,
}

impl Node {
    pub fn new(energy: i64, particle: zoom::BasicParticle<Vec3, f64>) -> Self {
        Node{
            energy: energy,
            particle: RadParticle{p: particle},
            bots: Vec::new(),
            moved_bots: Vec::new(),
            deaths: 0,
            moves: 0,
            connections: 0,
            pull: 0,
            diffuse: 0,
        }
    }

    pub fn diffuse(&mut self) {
        self.diffuse = self.connections * (self.energy as f64 * EDGE_DIFFUSION_COEFFICIENT) as i64;
        self.energy -= self.diffuse;
    }

    pub fn grow(&mut self, full: bool, rng: &mut rand::Isaac64Rng) {
        use rand::Rng;
        if full {
            if self.bots.is_empty() {
                self.energy = self.energy.saturating_sub((ENERGY_FULL_COST as f64 *
                    (1.0 + rng.gen_range(-ENERGY_VARIATION, ENERGY_VARIATION))) as i64);
            }
        } else {
            self.energy = self.energy.saturating_add((self.energy as f64 * ENERGY_RATIO *
                //Create rate differential
                (1.0 + rng.gen_range(-ENERGY_VARIATION, ENERGY_VARIATION) +
                    //Add food for having more connections
                    EDGE_FOOD_BENEFIT * self.connections as f64)
                ) as i64);
        }
    }

    pub fn advance(&mut self) {
        use zoom::{Particle, PhysicsParticle};
        self.particle.drag(DRAG);
        self.particle.advance(1.0);
    }

    pub fn should_split(&self) -> bool {
        self.energy >= ENERGY_THRESHOLD
    }
    pub fn should_obliterate(&self) -> bool {
        use std::num::FpCategory;
        use zoom::Position;
        let clos = |x: f64| {
            match x.classify() {
                FpCategory::Nan | FpCategory::Infinite => true,
                _ => false,
            }
        };
        self.energy <= 0 || match self.particle.position() {
            Vec3{x, y, z} => {clos(x) || clos(y) || clos(z)}
        }
    }

    pub fn color(&self) -> [f32; 4] {
        [
            1.0 - self.energy as f32 / ENERGY_THRESHOLD as f32,
            self.energy as f32 / ENERGY_THRESHOLD as f32,
            if self.bots.len() == 0 {
                0.0
            } else {
                self.moves as f32 / self.bots.len() as f32
            },
            1.0,
        ]
    }
    pub fn radius(&self) -> f32 {
        RADIUS_STATIC + BOTS_RADIUS_MULTIPLIER * (self.bots.len() as f32)
    }
}
<commit_msg>bots now influence radius by sqrt(bots)<commit_after>extern crate zoom;
extern crate rand;

use super::bot::*;
use super::Vec3;

const BOTS_RADIUS_MULTIPLIER: f32 = 5.0;
const RADIUS_STATIC: f32 = 5.0;
const ENERGY_RATIO: f64 = 0.002;
const ENERGY_VARIATION: f64 = 0.1;
pub const ENERGY_THRESHOLD: i64 = 500000;
const ENERGY_FULL_COST: i64 = 5000;
const PHYSICS_RADIUS: f64 = 1.0;

const EDGE_FOOD_BENEFIT: f64 = 1.0;
const EDGE_DIFFUSION_COEFFICIENT: f64 = 0.01;

const DRAG: f64 = 0.1;

#[derive(Clone)]
pub struct RadParticle {
    pub p: zoom::BasicParticle<Vec3, f64>,
}

impl zoom::Position<Vec3> for RadParticle {
    fn position(&self) -> Vec3 {
        self.p.position()
    }
}

impl zoom::Velocity<Vec3> for RadParticle {
    fn velocity(&self) -> Vec3 {
        self.p.velocity()
    }
}

impl zoom::Particle<Vec3, f64> for RadParticle {
    fn impulse(&self, v: &Vec3) {
        self.p.impulse(v);
    }

    fn advance(&mut self, time: f64) {
        self.p.advance(time);
    }
}

impl zoom::Inertia<f64> for RadParticle {
    fn inertia(&self) -> f64 {
        self.p.inertia()
    }
}

impl zoom::Quanta<f64> for RadParticle {
    fn quanta(&self) -> f64 {
        self.p.quanta()
    }
}

impl zoom::PhysicsParticle<Vec3, f64> for RadParticle {
}

impl zoom::Ball<f64> for RadParticle {
    fn radius(&self) -> f64 {
        PHYSICS_RADIUS
    }
}

pub struct Node {
    pub particle: RadParticle,
    pub energy: i64,
    pub bots: Vec<Box<Bot>>,
    pub moved_bots: Vec<Box<Bot>>,
    pub deaths: i64,
    pub moves: i64,
    pub connections: i64,
    pub pull: i64,
    pub diffuse: i64,
}

impl Node {
    pub fn new(energy: i64, particle: zoom::BasicParticle<Vec3, f64>) -> Self {
        Node{
            energy: energy,
            particle: RadParticle{p: particle},
            bots: Vec::new(),
            moved_bots: Vec::new(),
            deaths: 0,
            moves: 0,
            connections: 0,
            pull: 0,
            diffuse: 0,
        }
    }

    pub fn diffuse(&mut self) {
        self.diffuse = self.connections * (self.energy as f64 * EDGE_DIFFUSION_COEFFICIENT) as i64;
        self.energy -= self.diffuse;
    }

    pub fn grow(&mut self, full: bool, rng: &mut rand::Isaac64Rng) {
        use rand::Rng;
        if full {
            if self.bots.is_empty() {
                self.energy = self.energy.saturating_sub((ENERGY_FULL_COST as f64 *
                    (1.0 + rng.gen_range(-ENERGY_VARIATION, ENERGY_VARIATION))) as i64);
            }
        } else {
            self.energy = self.energy.saturating_add((self.energy as f64 * ENERGY_RATIO *
                //Create rate differential
                (1.0 + rng.gen_range(-ENERGY_VARIATION, ENERGY_VARIATION) +
                    //Add food for having more connections
                    EDGE_FOOD_BENEFIT * self.connections as f64)
                ) as i64);
        }
    }

    pub fn advance(&mut self) {
        use zoom::{Particle, PhysicsParticle};
        self.particle.drag(DRAG);
        self.particle.advance(1.0);
    }

    pub fn should_split(&self) -> bool {
        self.energy >= ENERGY_THRESHOLD
    }
    pub fn should_obliterate(&self) -> bool {
        use std::num::FpCategory;
        use zoom::Position;
        let clos = |x: f64| {
            match x.classify() {
                FpCategory::Nan | FpCategory::Infinite => true,
                _ => false,
            }
        };
        self.energy <= 0 || match self.particle.position() {
            Vec3{x, y, z} => {clos(x) || clos(y) || clos(z)}
        }
    }

    pub fn color(&self) -> [f32; 4] {
        [
            1.0 - self.energy as f32 / ENERGY_THRESHOLD as f32,
            self.energy as f32 / ENERGY_THRESHOLD as f32,
            if self.bots.len() == 0 {
                0.0
            } else {
                self.moves as f32 / self.bots.len() as f32
            },
            1.0,
        ]
    }
    pub fn radius(&self) -> f32 {
        RADIUS_STATIC + BOTS_RADIUS_MULTIPLIER * (self.bots.len() as f32).sqrt()
    }
}
<|endoftext|>


<commit_before>use super::NodeId;
use super::MutableNode;

///
/// A `Node` builder that provides more control over how a `Node` is created.
///
pub struct NodeBuilder<T> {
    data: T,
    child_capacity: usize,
}

impl<T> NodeBuilder<T> {

    ///
    /// Creates a new `NodeBuilder` with the required data.
    ///
    /// ```
    /// use id_tree::NodeBuilder;
    ///
    /// let _node_builder = NodeBuilder::new(5);
    /// ```
    ///
    pub fn new(data: T) -> NodeBuilder<T> {
        NodeBuilder {
            data: data,
            child_capacity: 0,
        }
    }

    ///
    /// Set the child capacity of the `NodeBuilder`.
    ///
    /// As `Node`s are added to a `Tree`, parent and child references must be maintained. To do this,
    /// an allocation must be made every time a child is added to a `Node`.  Using this setting
    /// allows the `Node` to pre-allocate space for its children so that the allocations aren't made
    /// as children are added.
    ///
    /// _Use of this setting is recommended if you know the **maximum number** of children (not
    /// including grandchildren, great-grandchildren, etc.) that a `Node` will have **at any given
    /// time**_.
    ///
    /// ```
    /// use id_tree::NodeBuilder;
    ///
    /// let _node_builder = NodeBuilder::new(5).with_child_capacity(3);
    /// ```
    ///
    pub fn with_child_capacity(mut self, child_capacity: usize) -> NodeBuilder<T> {
        self.child_capacity = child_capacity;
        self
    }

    ///
    /// Build a `Node` based upon the current settings in the `NodeBuilder`.
    ///
    /// ```
    /// use id_tree::NodeBuilder;
    /// use id_tree::Node;
    ///
    /// let node: Node<i32> = NodeBuilder::new(5)
    ///         .with_child_capacity(3)
    ///         .build();
    ///
    /// assert_eq!(node.data(), &5);
    /// assert_eq!(node.children().capacity(), 3);
    /// ```
    ///
    pub fn build(self) -> Node<T> {
        Node {
            data: self.data,
            parent: None,
            children: Vec::with_capacity(self.child_capacity),
        }
    }
}

///
/// A container that wraps data in a given `Tree`.
///
pub struct Node<T> {
    data: T,
    parent: Option<NodeId>,
    children: Vec<NodeId>,
}

impl<T> Node<T> {
    ///
    /// Creates a new `Node` with the data provided.
    ///
    /// ```
    /// use id_tree::Node;
    ///
    /// let _one: Node<i32> = Node::new(1);
    /// ```
    ///
    pub fn new(data: T) -> Node<T> {
        NodeBuilder::new(data).build()
    }

    ///
    /// Returns an immutable reference to the data contained within the `Node`.
    ///
    /// ```
    /// use id_tree::Node;
    ///
    /// let node_three: Node<i32> = Node::new(3);
    /// let three = 3;
    ///
    /// assert_eq!(node_three.data(), &three);
    /// ```
    ///
    pub fn data(&self) -> &T {
        &self.data
    }

    ///
    /// Returns a mutable reference to the data contained within the `Node`.
    ///
    /// ```
    /// use id_tree::Node;
    ///
    /// let mut node_four: Node<i32> = Node::new(4);
    /// let mut four = 4;
    ///
    /// assert_eq!(node_four.data_mut(), &mut four);
    /// ```
    ///
    pub fn data_mut(&mut self) -> &mut T {
        &mut self.data
    }

    ///
    /// Replaces this `Node`s data with the data provided.
    ///
    /// Returns the old value of data.
    ///
    /// ```
    /// use id_tree::Node;
    ///
    /// let mut node_four: Node<i32> = Node::new(3);
    ///
    /// // ops! lets correct this
    /// let three = node_four.replace_data(4);
    ///
    /// assert_eq!(node_four.data(), &4);
    /// assert_eq!(three, 3);
    /// ```
    ///
    pub fn replace_data(&mut self, mut data: T) -> T {
        ::std::mem::swap(&mut data, self.data_mut());
        data
    }

    ///
    /// Returns a `Some` value containing the `NodeId` of this `Node`'s parent if it exists; returns `None` if it does not.
    ///
    /// **Note:** A `Node` cannot have a parent until after it has been inserted into a `Tree`.
    ///
    /// ```
    /// use id_tree::Node;
    ///
    /// let five: Node<i32> = Node::new(5);
    ///
    /// assert!(five.parent().is_none());
    /// ```
    ///
    pub fn parent(&self) -> Option<&NodeId> {
        self.parent.as_ref()
    }

    ///
    /// Returns an immutable reference to a `Vec` containing the `NodeId`s of this `Node`'s children.
    ///
    /// **Note:** A `Node` cannot have any children until after it has been inserted into a `Tree`.
    ///
    /// ```
    /// use id_tree::Node;
    ///
    /// let six: Node<i32> = Node::new(6);
    ///
    /// assert_eq!(six.children().len(), 0);
    /// ```
    ///
    pub fn children(&self) -> &Vec<NodeId> {
        &self.children
    }
}

impl<T> MutableNode for Node<T> {
    fn set_parent(&mut self, parent: Option<NodeId>) {
        self.parent = parent;
    }

    fn add_child(&mut self, child: NodeId) {
        self.children.push(child);
    }

    fn replace_child(&mut self, old: NodeId, new: NodeId) {
        let index = self.children()
                        .iter()
                        .enumerate()
                        .find(|&(_, id)| id == &old)
                        .unwrap().0;

        let children = self.children_mut();
        children.push(new);
        children.swap_remove(index);
    }

    fn children_mut(&mut self) -> &mut Vec<NodeId> {
        &mut self.children
    }

    fn set_children(&mut self, children: Vec<NodeId>) {
        self.children = children;
    }

    fn take_children(&mut self) -> Vec<NodeId> {
        use std::mem;

        let mut empty = Vec::with_capacity(0);
        mem::swap(&mut self.children, &mut empty);
        empty //not so empty anymore
    }
}

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

    #[test]
    fn test_new() {
        let five = 5;
        let node = NodeBuilder::new(5).build();
        assert_eq!(node.data(), &five);
        assert_eq!(node.children.capacity(), 0);
    }

    #[test]
    fn test_with_child_capacity() {
        let five = 5;
        let node = NodeBuilder::new(5).with_child_capacity(10).build();
        assert_eq!(node.data(), &five);
        assert_eq!(node.children.capacity(), 10);
    }
}

#[cfg(test)]
mod node_tests {
    use super::Node;
    use super::super::NodeId;
    use super::super::snowflake::ProcessUniqueId;
    use super::super::MutableNode;

    #[test]
    fn test_new() {
        let node = Node::new(5);
        assert_eq!(node.children.capacity(), 0);
    }

    #[test]
    fn test_data() {
        let five = 5;
        let node = Node::new(five);
        assert_eq!(node.data(), &five);
    }

    #[test]
    fn test_data_mut() {
        let mut five = 5;
        let mut node = Node::new(five);
        assert_eq!(node.data_mut(), &mut five);
    }

    #[test]
    fn test_parent() {
        let mut node = Node::new(5);
        assert!(node.parent().is_none());

        let parent_id: NodeId = NodeId {
            tree_id: ProcessUniqueId::new(),
            index: 0,
        };

        node.set_parent(Some(parent_id.clone()));
        assert!(node.parent().is_some());

        assert_eq!(node.parent().unwrap().clone(), parent_id);
    }

    #[test]
    fn test_children() {
        let mut node = Node::new(5);
        assert_eq!(node.children().len(), 0);

        let child_id: NodeId = NodeId {
            tree_id: ProcessUniqueId::new(),
            index: 0,
        };
        node.add_child(child_id.clone());

        assert_eq!(node.children().len(), 1);
        assert_eq!(node.children().get(0).unwrap(), &child_id);

        let mut node = Node::new(5);
        assert_eq!(node.children().len(), 0);

        let child_id: NodeId = NodeId {
            tree_id: ProcessUniqueId::new(),
            index: 0,
        };
        node.children_mut().push(child_id.clone());

        assert_eq!(node.children().len(), 1);
        assert_eq!(node.children().get(0).unwrap(), &child_id);
    }
}
<commit_msg>fix a typo<commit_after>use super::NodeId;
use super::MutableNode;

///
/// A `Node` builder that provides more control over how a `Node` is created.
///
pub struct NodeBuilder<T> {
    data: T,
    child_capacity: usize,
}

impl<T> NodeBuilder<T> {

    ///
    /// Creates a new `NodeBuilder` with the required data.
    ///
    /// ```
    /// use id_tree::NodeBuilder;
    ///
    /// let _node_builder = NodeBuilder::new(5);
    /// ```
    ///
    pub fn new(data: T) -> NodeBuilder<T> {
        NodeBuilder {
            data: data,
            child_capacity: 0,
        }
    }

    ///
    /// Set the child capacity of the `NodeBuilder`.
    ///
    /// As `Node`s are added to a `Tree`, parent and child references must be maintained. To do this,
    /// an allocation must be made every time a child is added to a `Node`.  Using this setting
    /// allows the `Node` to pre-allocate space for its children so that the allocations aren't made
    /// as children are added.
    ///
    /// _Use of this setting is recommended if you know the **maximum number** of children (not
    /// including grandchildren, great-grandchildren, etc.) that a `Node` will have **at any given
    /// time**_.
    ///
    /// ```
    /// use id_tree::NodeBuilder;
    ///
    /// let _node_builder = NodeBuilder::new(5).with_child_capacity(3);
    /// ```
    ///
    pub fn with_child_capacity(mut self, child_capacity: usize) -> NodeBuilder<T> {
        self.child_capacity = child_capacity;
        self
    }

    ///
    /// Build a `Node` based upon the current settings in the `NodeBuilder`.
    ///
    /// ```
    /// use id_tree::NodeBuilder;
    /// use id_tree::Node;
    ///
    /// let node: Node<i32> = NodeBuilder::new(5)
    ///         .with_child_capacity(3)
    ///         .build();
    ///
    /// assert_eq!(node.data(), &5);
    /// assert_eq!(node.children().capacity(), 3);
    /// ```
    ///
    pub fn build(self) -> Node<T> {
        Node {
            data: self.data,
            parent: None,
            children: Vec::with_capacity(self.child_capacity),
        }
    }
}

///
/// A container that wraps data in a given `Tree`.
///
pub struct Node<T> {
    data: T,
    parent: Option<NodeId>,
    children: Vec<NodeId>,
}

impl<T> Node<T> {
    ///
    /// Creates a new `Node` with the data provided.
    ///
    /// ```
    /// use id_tree::Node;
    ///
    /// let _one: Node<i32> = Node::new(1);
    /// ```
    ///
    pub fn new(data: T) -> Node<T> {
        NodeBuilder::new(data).build()
    }

    ///
    /// Returns an immutable reference to the data contained within the `Node`.
    ///
    /// ```
    /// use id_tree::Node;
    ///
    /// let node_three: Node<i32> = Node::new(3);
    /// let three = 3;
    ///
    /// assert_eq!(node_three.data(), &three);
    /// ```
    ///
    pub fn data(&self) -> &T {
        &self.data
    }

    ///
    /// Returns a mutable reference to the data contained within the `Node`.
    ///
    /// ```
    /// use id_tree::Node;
    ///
    /// let mut node_four: Node<i32> = Node::new(4);
    /// let mut four = 4;
    ///
    /// assert_eq!(node_four.data_mut(), &mut four);
    /// ```
    ///
    pub fn data_mut(&mut self) -> &mut T {
        &mut self.data
    }

    ///
    /// Replaces this `Node`s data with the data provided.
    ///
    /// Returns the old value of data.
    ///
    /// ```
    /// use id_tree::Node;
    ///
    /// let mut node_four: Node<i32> = Node::new(3);
    ///
    /// // ops! lets correct this
    /// let three = node_four.replace_data(4);
    ///
    /// assert_eq!(node_four.data(), &4);
    /// assert_eq!(three, 3);
    /// ```
    ///
    pub fn replace_data(&mut self, mut data: T) -> T {
        ::std::mem::swap(&mut data, self.data_mut());
        data
    }

    ///
    /// Returns a `Some` value containing the `NodeId` of this `Node`'s parent if it exists; returns `None` if it does not.
    ///
    /// **Note:** A `Node` cannot have a parent until after it has been inserted into a `Tree`.
    ///
    /// ```
    /// use id_tree::Node;
    ///
    /// let five: Node<i32> = Node::new(5);
    ///
    /// assert!(five.parent().is_none());
    /// ```
    ///
    pub fn parent(&self) -> Option<&NodeId> {
        self.parent.as_ref()
    }

    ///
    /// Returns an immutable reference to a `Vec` containing the `NodeId`s of this `Node`'s children.
    ///
    /// **Note:** A `Node` cannot have any children until after it has been inserted into a `Tree`.
    ///
    /// ```
    /// use id_tree::Node;
    ///
    /// let six: Node<i32> = Node::new(6);
    ///
    /// assert_eq!(six.children().len(), 0);
    /// ```
    ///
    pub fn children(&self) -> &Vec<NodeId> {
        &self.children
    }
}

impl<T> MutableNode for Node<T> {
    fn set_parent(&mut self, parent: Option<NodeId>) {
        self.parent = parent;
    }

    fn add_child(&mut self, child: NodeId) {
        self.children.push(child);
    }

    fn replace_child(&mut self, old: NodeId, new: NodeId) {
        let index = self.children()
                        .iter()
                        .enumerate()
                        .find(|&(_, id)| id == &old)
                        .unwrap().0;

        let children = self.children_mut();
        children.push(new);
        children.swap_remove(index);
    }

    fn children_mut(&mut self) -> &mut Vec<NodeId> {
        &mut self.children
    }

    fn set_children(&mut self, children: Vec<NodeId>) {
        self.children = children;
    }

    fn take_children(&mut self) -> Vec<NodeId> {
        use std::mem;

        let mut empty = Vec::with_capacity(0);
        mem::swap(&mut self.children, &mut empty);
        empty //not so empty anymore
    }
}

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

    #[test]
    fn test_new() {
        let five = 5;
        let node = NodeBuilder::new(5).build();
        assert_eq!(node.data(), &five);
        assert_eq!(node.children.capacity(), 0);
    }

    #[test]
    fn test_with_child_capacity() {
        let five = 5;
        let node = NodeBuilder::new(5).with_child_capacity(10).build();
        assert_eq!(node.data(), &five);
        assert_eq!(node.children.capacity(), 10);
    }
}

#[cfg(test)]
mod node_tests {
    use super::Node;
    use super::super::NodeId;
    use super::super::snowflake::ProcessUniqueId;
    use super::super::MutableNode;

    #[test]
    fn test_new() {
        let node = Node::new(5);
        assert_eq!(node.children.capacity(), 0);
    }

    #[test]
    fn test_data() {
        let five = 5;
        let node = Node::new(five);
        assert_eq!(node.data(), &five);
    }

    #[test]
    fn test_data_mut() {
        let mut five = 5;
        let mut node = Node::new(five);
        assert_eq!(node.data_mut(), &mut five);
    }

    #[test]
    fn test_parent() {
        let mut node = Node::new(5);
        assert!(node.parent().is_none());

        let parent_id: NodeId = NodeId {
            tree_id: ProcessUniqueId::new(),
            index: 0,
        };

        node.set_parent(Some(parent_id.clone()));
        assert!(node.parent().is_some());

        assert_eq!(node.parent().unwrap().clone(), parent_id);
    }

    #[test]
    fn test_children() {
        let mut node = Node::new(5);
        assert_eq!(node.children().len(), 0);

        let child_id: NodeId = NodeId {
            tree_id: ProcessUniqueId::new(),
            index: 0,
        };
        node.add_child(child_id.clone());

        assert_eq!(node.children().len(), 1);
        assert_eq!(node.children().get(0).unwrap(), &child_id);

        let mut node = Node::new(5);
        assert_eq!(node.children().len(), 0);

        let child_id: NodeId = NodeId {
            tree_id: ProcessUniqueId::new(),
            index: 0,
        };
        node.children_mut().push(child_id.clone());

        assert_eq!(node.children().len(), 1);
        assert_eq!(node.children().get(0).unwrap(), &child_id);
    }
}
<|endoftext|>


<commit_before>
use ffi;
use super::plan::Plan;
use super::{R2R_KIND, FLAG, SIGN, c64};
use super::util::FFTW_MUTEX;

use num_traits::Zero;
use std::slice::from_raw_parts_mut;
use std::ops::{Deref, DerefMut};
use std::os::raw::c_void;

/// Field and Coefficient pair
///
/// - This struct is a wrapper of `Plan`
/// - This struct uses fftw_malloc to enable SIMD optimization in FFTW.
pub struct Pair<'a, 'b, A, B>
    where A: 'a,
          B: 'b
{
    plan: Plan<'a, 'b, A, B>,
}

impl<'a, 'b, A, B> Drop for Pair<'a, 'b, A, B> {
    fn drop(&mut self) {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe {
            ffi::fftw_free(self.plan.field.as_mut_ptr() as *mut c_void);
            ffi::fftw_free(self.plan.coef.as_mut_ptr() as *mut c_void);
        }
        drop(lock);
    }
}

impl<'a, 'b, A, B> Deref for Pair<'a, 'b, A, B> {
    type Target = Plan<'a, 'b, A, B>;
    fn deref(&self) -> &Self::Target { &self.plan }
}

impl<'a, 'b, A, B> DerefMut for Pair<'a, 'b, A, B> {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.plan }
}

fn alloc_real<'a>(n: usize) -> &'a mut [f64] {
    let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
    let slice = unsafe {
        let ptr = ffi::fftw_alloc_real(n);
        from_raw_parts_mut(ptr, n)
    };
    drop(lock);
    for val in slice.iter_mut() {
        *val = 0.0;
    }
    slice
}

fn alloc_complex<'a>(n: usize) -> &'a mut [c64] {
    let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
    let slice = unsafe {
        let ptr = ffi::fftw_alloc_complex(n) as *mut c64;
        from_raw_parts_mut(ptr, n)
    };
    drop(lock);
    for val in slice.iter_mut() {
        *val = c64::zero();
    }
    slice
}

impl<'a, 'b> Pair<'a, 'b, f64, f64> {
    pub fn r2r_1d(n: usize, kind: R2R_KIND, flag: FLAG) -> Self {
        let field = alloc_real(n);
        let coef = alloc_real(n);
        let plan = Plan::r2r_1d(field, coef, kind, flag);
        Pair { plan: plan }
    }
}

impl<'a, 'b> Pair<'a, 'b, f64, c64> {
    pub fn r2c_1d(n: usize, flag: FLAG) -> Self {
        let field = alloc_real(n);
        let coef = alloc_complex(n / 2 + 1);
        let plan = Plan::r2c_1d(field, coef, flag);
        Pair { plan: plan }
    }
}

impl<'a, 'b> Pair<'a, 'b, c64, c64> {
    pub fn c2c_1d(n: usize, sign: SIGN, flag: FLAG) -> Self {
        let field = alloc_complex(n);
        let coef = alloc_complex(n);
        let plan = Plan::c2c_1d(field, coef, sign, flag);
        Pair { plan: plan }
    }
}
<commit_msg>Rewrite Pair<commit_after>
use super::complex::c64;
use super::raw_vec::RawVec;
use super::plan::Plan;
use super::enums::*;
use super::r2r::*;

/// Field and Coefficient pair
///
/// - This struct is a wrapper of `Plan`
/// - This struct uses fftw_malloc to enable SIMD optimization in FFTW.
pub struct Pair<A, B> {
    pub field: RawVec<A>,
    pub coef: RawVec<B>,
    logical_size: usize,
    forward: Plan,
    backward: Plan,
}

impl<A, B> Pair<A, B> {
    pub fn forward(&mut self) {
        unsafe {
            self.forward.execute();
        }
    }

    pub fn backward(&mut self) {
        unsafe {
            self.backward.execute();
        }
    }
}

impl Pair<f64, f64> {
    pub fn r2r_1d(n: usize, kind: R2R_KIND, flag: FLAG) -> Self {
        let mut field = RawVec::<f64>::new(n);
        let mut coef = RawVec::<f64>::new(n);
        let forward = Plan::r2r_1d(n, &mut field, &mut coef, forward(kind), flag);
        let backward = Plan::r2r_1d(n, &mut coef, &mut field, backward(kind), flag);
        Pair {
            field: field,
            coef: coef,
            logical_size: logical_size(n, kind),
            forward: forward,
            backward: backward,
        }
    }
}

impl Pair<f64, c64> {
    pub fn r2c_1d(n: usize, flag: FLAG) -> Self {
        let mut field = RawVec::<f64>::new(n);
        let mut coef = RawVec::<c64>::new(n);
        let forward = Plan::r2c_1d(n, &mut field, &mut coef, flag);
        let backward = Plan::c2r_1d(n, &mut coef, &mut field, flag);
        Pair {
            field: field,
            coef: coef,
            logical_size: n,
            forward: forward,
            backward: backward,
        }
    }
}

impl Pair<c64, c64> {
    pub fn c2c_1d(n: usize, sign: SIGN, flag: FLAG) -> Self {
        let mut field = RawVec::<c64>::new(n);
        let mut coef = RawVec::<c64>::new(n);
        let forward = Plan::c2c_1d(n, &mut field, &mut coef, sign, flag);
        let backward = Plan::c2c_1d(n, &mut coef, &mut field, -sign, flag);
        Pair {
            field: field,
            coef: coef,
            logical_size: n,
            forward: forward,
            backward: backward,
        }
    }
}
<|endoftext|>


<commit_before>//!
//! Desync pipes provide a way to generate and process streams via a `Desync` object
//!

use super::desync::*;

use futures::*;
use futures::executor;
use futures::executor::Spawn;

use std::mem;
use std::sync::*;
use std::thread;
use std::thread::JoinHandle;
use std::result::Result;
use std::collections::{HashMap, HashSet};

lazy_static! {
    /// The shared poll thread that's used to schedule events from pipe streams
    static ref POLL_THREAD: PollThread = PollThread::new();
}

///
/// Pipes a stream into a desync object. Whenever an item becomes available on the stream, the
/// processing function is called asynchronously with the item that was received.
///
/// Piping a stream to a `Desync` like this will cause it to start executing: ie, this is
/// similar to calling `executor::spawn(stream)`, except that the stream will immediately
/// start draining into the `Desync` object.
///
pub fn pipe_in<Core, S, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn)
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> () {

    // Need a mutable version of the stream
    let mut stream = stream;

    // Wrap the process fn up so we can call it asynchronously
    // (it doesn't really need to be in a mutex as it's only called by our object but we need to make it pass Rust's checks and we don't have a way to specify this at the moment)
    let process = Arc::new(Mutex::new(process));

    // Poll the stream on the poll thread
    POLL_THREAD.monitor(move || {
        loop {
            // Read the current status of the stream
            let process     = Arc::clone(&process);
            let next        = stream.poll();

            match next {
                // Just wait if the stream is not ready
                Ok(Async::NotReady) => { return Ok(Async::NotReady); },

                // Stream returned a value
                Ok(Async::Ready(Some(next))) => {
                    // Process the value on the stream
                    desync.async(move |core| {
                        let mut process = process.lock().unwrap();
                        let process     = &mut *process;
                        process(core, Ok(next));
                    });
                },

                // Stream returned an error
                Err(e) => {
                    // Process the error on the stream
                    desync.async(move |core| {
                        let mut process = process.lock().unwrap();
                        let process     = &mut *process;
                        process(core, Err(e));
                    });
                },

                // Stream finished
                Ok(Async::Ready(None)) => { return Ok(Async::Ready(())); }
            }
        }
    });
}

/*
///
/// Pipes a stream into this object. Whenever an item becomes available on the strema, the
/// processing function is called asynchronously with the item that was received. The
/// return value is placed onto the output stream.
///
pub fn pipe<Core, S, Output, OutputErr, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn) -> Box<dyn Stream<Item=Output, Error=OutputErr>>
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        Output:     Send,
        OutputErr:  Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> Result<Output, OutputErr> {
    unimplemented!()
}
*/

///
/// In order to implement the polling functions, we need a thread that runs the executor
/// for any streams that we're currently piping (calling pipe_in or pipe will effectively
/// need to spawn the relevant stream).
///
/// This represents that thread. There's a bit of a limitation in that the `poll` methods
/// for the various streams will block the thread so this may start to bottleneck at times of
/// high load or with streams with poll methods that take significant time to execute.
///
struct PollThread {
    /// The poll functions that are being monitored by this thread
    notifications: Arc<Mutex<PollNotifications>>,

    /// The function that should be called for every notification ID
    poll_functions: Arc<Mutex<HashMap<u32, Spawn<Box<Future<Item=(), Error=()>+Send>>>>>,

    /// The joinhandle of the running thread
    thread: Arc<JoinHandle<()>>
}

///
/// Stores things being monitored
///
struct PollNotifications {
    /// Next available ID for a polling function
    next_id: u32,

    /// Poll functions where the notify handle has been set
    notified_ids: HashSet<u32>
}

///
/// Provides the 'Notify' interface for a polling function with a particular ID
///
struct PollNotify {
    /// The ID that should be marked as notified when the callback is made
    id: u32,

    /// The structure where the notifications are stored
    notifications: Arc<Mutex<PollNotifications>>,

    /// The thread that should be notified when this notification occurs
    thread: thread::Thread
}

impl PollThread {
    ///
    /// Creates a new poll thread
    ///
    pub fn new() -> PollThread {
        // Create the monitors for the new thread
        let notifications = PollNotifications {
            next_id:        0,
            notified_ids:   HashSet::new()
        };
        let notifications = Arc::new(Mutex::new(notifications));

        // Create the set of polling functions
        let poll_functions = Arc::new(Mutex::new(HashMap::new()));

        // Run the thread with the monitors
        let thread = Self::run(Arc::clone(&notifications), Arc::clone(&poll_functions));
        let thread = Arc::new(thread);

        // Generate the thread object
        let thread = PollThread {
            notifications:  notifications,
            poll_functions: poll_functions,
            thread:         thread
        };

        thread
    }

    ///
    /// Starts the poll thread running (poll threads cannot currently be stopped)
    ///
    fn run(notifications: Arc<Mutex<PollNotifications>>, functions: Arc<Mutex<HashMap<u32, Spawn<Box<Future<Item=(), Error=()>+Send>>>>>) -> JoinHandle<()> {
        thread::spawn(move || {
            loop {
                // Park the thread until there is something to do
                thread::park();

                // Fetch the list of notified functions we should call
                let to_notify = {
                    let mut notifications   = notifications.lock().unwrap();
                    let mut to_notify       = HashSet::new();

                    mem::swap(&mut to_notify, &mut notifications.notified_ids);

                    to_notify
                };

                // Notify each function in turn
                let mut functions   = functions.lock().unwrap();
                let thread          = thread::current();

                for function_id in to_notify {
                    // Fetch the function. If it returns false, we need to remove it from the list
                    let finished_polling = functions.get_mut(&function_id)
                        .map(|poll_function| {
                            // Create the notification structure
                            let notify = PollNotify {
                                id:             function_id,
                                notifications:  Arc::clone(&notifications),
                                thread:         thread.clone()
                            };

                            // Call the polling function
                            poll_function.poll_future_notify(&Arc::new(notify), 0)
                        })
                        .unwrap_or(Ok(Async::Ready(())));

                    // If the polling function completes, then remove the function
                    if finished_polling == Ok(Async::Ready(())) {
                        functions.remove(&function_id);
                    }
                }
            }
        })
    }

    ///
    /// Adds a polling function to the current thread. It will be called using the futures
    /// notification system (ie, can call things like the stream poll function)
    ///
    pub fn monitor<PollFn>(&self, poll_fn: PollFn)
    where PollFn: 'static+Send+FnMut() -> Poll<(), ()> {
        let mut functions       = self.poll_functions.lock().unwrap();
        let mut notifications   = self.notifications.lock().unwrap();

        // Get an ID for this monitor
        let id = notifications.next_id;
        notifications.next_id += 1;

        // Turn the polling function into a future
        let poll_fn: Box<dyn Future<Item=(), Error=()>+Send> = Box::new(future::poll_fn(poll_fn));
        let poll_fn = executor::spawn(poll_fn);

        functions.insert(id, poll_fn);

        // Mark it as notified
        notifications.notified_ids.insert(id);

        // Wake the thread
        self.thread.thread().unpark();
    }
}

impl executor::Notify for PollNotify {
    fn notify(&self, _id: usize) {
        // Add our ID to the notification list
        let mut notifications = self.notifications.lock().unwrap();
        notifications.notified_ids.insert(self.id);

        // Wake the thread
        self.thread.unpark();
    }
}
<commit_msg>Fix typo<commit_after>//!
//! Desync pipes provide a way to generate and process streams via a `Desync` object
//!

use super::desync::*;

use futures::*;
use futures::executor;
use futures::executor::Spawn;

use std::mem;
use std::sync::*;
use std::thread;
use std::thread::JoinHandle;
use std::result::Result;
use std::collections::{HashMap, HashSet};

lazy_static! {
    /// The shared poll thread that's used to schedule events from pipe streams
    static ref POLL_THREAD: PollThread = PollThread::new();
}

///
/// Pipes a stream into a desync object. Whenever an item becomes available on the stream, the
/// processing function is called asynchronously with the item that was received.
///
/// Piping a stream to a `Desync` like this will cause it to start executing: ie, this is
/// similar to calling `executor::spawn(stream)`, except that the stream will immediately
/// start draining into the `Desync` object.
///
pub fn pipe_in<Core, S, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn)
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> () {

    // Need a mutable version of the stream
    let mut stream = stream;

    // Wrap the process fn up so we can call it asynchronously
    // (it doesn't really need to be in a mutex as it's only called by our object but we need to make it pass Rust's checks and we don't have a way to specify this at the moment)
    let process = Arc::new(Mutex::new(process));

    // Poll the stream on the poll thread
    POLL_THREAD.monitor(move || {
        loop {
            // Read the current status of the stream
            let process     = Arc::clone(&process);
            let next        = stream.poll();

            match next {
                // Just wait if the stream is not ready
                Ok(Async::NotReady) => { return Ok(Async::NotReady); },

                // Stream returned a value
                Ok(Async::Ready(Some(next))) => {
                    // Process the value on the stream
                    desync.async(move |core| {
                        let mut process = process.lock().unwrap();
                        let process     = &mut *process;
                        process(core, Ok(next));
                    });
                },

                // Stream returned an error
                Err(e) => {
                    // Process the error on the stream
                    desync.async(move |core| {
                        let mut process = process.lock().unwrap();
                        let process     = &mut *process;
                        process(core, Err(e));
                    });
                },

                // Stream finished
                Ok(Async::Ready(None)) => { return Ok(Async::Ready(())); }
            }
        }
    });
}

/*
///
/// Pipes a stream into this object. Whenever an item becomes available on the stream, the
/// processing function is called asynchronously with the item that was received. The
/// return value is placed onto the output stream.
///
pub fn pipe<Core, S, Output, OutputErr, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn) -> Box<dyn Stream<Item=Output, Error=OutputErr>>
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        Output:     Send,
        OutputErr:  Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> Result<Output, OutputErr> {
    unimplemented!()
}
*/

///
/// In order to implement the polling functions, we need a thread that runs the executor
/// for any streams that we're currently piping (calling pipe_in or pipe will effectively
/// need to spawn the relevant stream).
///
/// This represents that thread. There's a bit of a limitation in that the `poll` methods
/// for the various streams will block the thread so this may start to bottleneck at times of
/// high load or with streams with poll methods that take significant time to execute.
///
struct PollThread {
    /// The poll functions that are being monitored by this thread
    notifications: Arc<Mutex<PollNotifications>>,

    /// The function that should be called for every notification ID
    poll_functions: Arc<Mutex<HashMap<u32, Spawn<Box<Future<Item=(), Error=()>+Send>>>>>,

    /// The joinhandle of the running thread
    thread: Arc<JoinHandle<()>>
}

///
/// Stores things being monitored
///
struct PollNotifications {
    /// Next available ID for a polling function
    next_id: u32,

    /// Poll functions where the notify handle has been set
    notified_ids: HashSet<u32>
}

///
/// Provides the 'Notify' interface for a polling function with a particular ID
///
struct PollNotify {
    /// The ID that should be marked as notified when the callback is made
    id: u32,

    /// The structure where the notifications are stored
    notifications: Arc<Mutex<PollNotifications>>,

    /// The thread that should be notified when this notification occurs
    thread: thread::Thread
}

impl PollThread {
    ///
    /// Creates a new poll thread
    ///
    pub fn new() -> PollThread {
        // Create the monitors for the new thread
        let notifications = PollNotifications {
            next_id:        0,
            notified_ids:   HashSet::new()
        };
        let notifications = Arc::new(Mutex::new(notifications));

        // Create the set of polling functions
        let poll_functions = Arc::new(Mutex::new(HashMap::new()));

        // Run the thread with the monitors
        let thread = Self::run(Arc::clone(&notifications), Arc::clone(&poll_functions));
        let thread = Arc::new(thread);

        // Generate the thread object
        let thread = PollThread {
            notifications:  notifications,
            poll_functions: poll_functions,
            thread:         thread
        };

        thread
    }

    ///
    /// Starts the poll thread running (poll threads cannot currently be stopped)
    ///
    fn run(notifications: Arc<Mutex<PollNotifications>>, functions: Arc<Mutex<HashMap<u32, Spawn<Box<Future<Item=(), Error=()>+Send>>>>>) -> JoinHandle<()> {
        thread::spawn(move || {
            loop {
                // Park the thread until there is something to do
                thread::park();

                // Fetch the list of notified functions we should call
                let to_notify = {
                    let mut notifications   = notifications.lock().unwrap();
                    let mut to_notify       = HashSet::new();

                    mem::swap(&mut to_notify, &mut notifications.notified_ids);

                    to_notify
                };

                // Notify each function in turn
                let mut functions   = functions.lock().unwrap();
                let thread          = thread::current();

                for function_id in to_notify {
                    // Fetch the function. If it returns false, we need to remove it from the list
                    let finished_polling = functions.get_mut(&function_id)
                        .map(|poll_function| {
                            // Create the notification structure
                            let notify = PollNotify {
                                id:             function_id,
                                notifications:  Arc::clone(&notifications),
                                thread:         thread.clone()
                            };

                            // Call the polling function
                            poll_function.poll_future_notify(&Arc::new(notify), 0)
                        })
                        .unwrap_or(Ok(Async::Ready(())));

                    // If the polling function completes, then remove the function
                    if finished_polling == Ok(Async::Ready(())) {
                        functions.remove(&function_id);
                    }
                }
            }
        })
    }

    ///
    /// Adds a polling function to the current thread. It will be called using the futures
    /// notification system (ie, can call things like the stream poll function)
    ///
    pub fn monitor<PollFn>(&self, poll_fn: PollFn)
    where PollFn: 'static+Send+FnMut() -> Poll<(), ()> {
        let mut functions       = self.poll_functions.lock().unwrap();
        let mut notifications   = self.notifications.lock().unwrap();

        // Get an ID for this monitor
        let id = notifications.next_id;
        notifications.next_id += 1;

        // Turn the polling function into a future
        let poll_fn: Box<dyn Future<Item=(), Error=()>+Send> = Box::new(future::poll_fn(poll_fn));
        let poll_fn = executor::spawn(poll_fn);

        functions.insert(id, poll_fn);

        // Mark it as notified
        notifications.notified_ids.insert(id);

        // Wake the thread
        self.thread.thread().unpark();
    }
}

impl executor::Notify for PollNotify {
    fn notify(&self, _id: usize) {
        // Add our ID to the notification list
        let mut notifications = self.notifications.lock().unwrap();
        notifications.notified_ids.insert(self.id);

        // Wake the thread
        self.thread.unpark();
    }
}
<|endoftext|>


<commit_before>use flow::{Flow, Observer};
use std::collections::HashMap;
use std::sync::{Arc, Mutex, RwLock, Weak};

type SharedFlow = Arc<RwLock<Flow>>;

type LinkPointer<T> = Weak<Mutex<T>>;

struct TimeLinkNode {
    key: String,
    prev: Option<LinkPointer<TimeLinkNode>>,
    next: Option<LinkPointer<TimeLinkNode>>,
}

struct Entry {
    flow: SharedFlow,
    timelink: Arc<Mutex<TimeLinkNode>>,
}

pub struct Pool {
    weakref: Weak<RwLock<Pool>>,
    bucket: HashMap<String, Entry>,
    timelink_head: Option<LinkPointer<TimeLinkNode>>,
    timelink_tail: Option<LinkPointer<TimeLinkNode>>,
}

impl Entry {
    fn new(flow_id: &str, flow_ptr: SharedFlow) -> Self {
        Entry {
            flow: flow_ptr,
            timelink: Arc::new(Mutex::new(TimeLinkNode {
                                              key: flow_id.to_owned(),
                                              prev: Some(Weak::new()),
                                              next: Some(Weak::new()),
                                          })),
        }
    }
}

impl TimeLinkNode {
    fn push(timelink: &Arc<Mutex<TimeLinkNode>>, pool: &mut Pool) {
        let mut link = timelink.lock().unwrap();
        link.prev = None;
        link.next = pool.timelink_head.clone();
        let link_ptr = Arc::downgrade(timelink);
        if let Some(ref head) = pool.timelink_head {
            let head = head.upgrade().unwrap();
            head.lock().unwrap().prev = Some(link_ptr.clone());
        }
        pool.timelink_head = Some(link_ptr);
    }

    fn unlink(timelink: &Arc<Mutex<TimeLinkNode>>, pool: &mut Pool) {
        let mut link = timelink.lock().unwrap();
        if let Some(ref prev) = link.prev {
            // Upgrade should always success.
            let prev = prev.upgrade().unwrap();
            prev.lock().unwrap().next = link.next.clone();
        } else {
            pool.timelink_head = link.next.clone();
        }
        if let Some(ref next) = link.next {
            // Upgrade should always success.
            let next = next.upgrade().unwrap();
            next.lock().unwrap().prev = link.prev.clone();
        } else {
            pool.timelink_tail = link.prev.clone();
        }
        link.prev = Some(Weak::new());
        link.next = Some(Weak::new());
    }
}

impl Pool {
    pub fn new() -> Arc<RwLock<Self>> {
        let pool = Pool {
            weakref: Weak::new(),
            bucket: HashMap::new(),
            timelink_head: None,
            timelink_tail: None,
        };
        let pool_ptr = Arc::new(RwLock::new(pool));
        pool_ptr.write().unwrap().weakref = Arc::downgrade(&pool_ptr);
        pool_ptr
    }

    pub fn insert(&mut self, flow_ptr: SharedFlow) {
        // Occupy the flow to prevent from race condition.
        let mut flow = flow_ptr.write().unwrap();
        let timelink = {
            self.bucket
                .entry(flow.id.to_owned())
                .or_insert(Entry::new(&flow.id, flow_ptr.clone()))
                .timelink
                .clone()
        };
        flow.observe(self.weakref.clone());
        TimeLinkNode::push(&timelink, self);
    }

    pub fn get(&self, flow_id: &str) -> Option<SharedFlow> {
        self.bucket.get(flow_id).map(|entry| entry.flow.clone())
    }

    pub fn remove(&mut self, flow_id: &str) -> Result<(), ()> {
        self.bucket
            .remove(flow_id)
            .ok_or(())
            .and_then(|entry| {
                TimeLinkNode::unlink(&entry.timelink, self);
                Ok(())
            })
    }
}

impl Observer for Weak<RwLock<Pool>> {
    fn on_active(&self, flow: &Flow) {
        if let Some(pool_ptr) = self.upgrade() {
            // TODO minimize the pool write lock.
            let mut pool = pool_ptr.write().unwrap();
            let timelink = match pool.bucket.get(&flow.id) {
                Some(entry) => entry.timelink.clone(),
                None => return,
            };
            TimeLinkNode::unlink(&timelink, &mut pool);
            TimeLinkNode::push(&timelink, &mut pool);
        }
    }

    fn on_close(&self, flow: &Flow) {
        if let Some(pool_ptr) = self.upgrade() {
            let mut pool = pool_ptr.write().unwrap();
            // Try to remove the flow.
            pool.remove(&flow.id).is_ok();
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use flow::Flow;
    use std::sync::Arc;
    use tokio::reactor::Core;

    #[test]
    fn basic_operations() {
        let ptr = Pool::new();
        let flow_a = Flow::new(None);
        let flow_b = Flow::new(None);
        let flow_c = Flow::new(None);

        let (flowa_id, flowb_id, flowc_id) = {
            (flow_a.read().unwrap().id.to_owned(),
             flow_b.read().unwrap().id.to_owned(),
             flow_c.read().unwrap().id.to_owned())
        };

        {
            let mut pool = ptr.write().unwrap();
            pool.insert(flow_a.clone());
            pool.insert(flow_b.clone());
            pool.insert(flow_c.clone());
        }

        {
            let pool = ptr.read().unwrap();
            assert!(Arc::ptr_eq(&pool.get(&flowa_id).unwrap(), &flow_a));
            assert!(Arc::ptr_eq(&pool.get(&flowb_id).unwrap(), &flow_b));
            assert!(!Arc::ptr_eq(&pool.get(&flowa_id).unwrap(), &flow_b));
            assert!(!Arc::ptr_eq(&pool.get(&flowb_id).unwrap(), &flow_a));
            assert!(!pool.get("C").is_some());
        }

        {
            let mut pool = ptr.write().unwrap();
            assert_eq!(pool.remove(&flowb_id), Ok(()));
            assert_eq!(pool.remove(&flowa_id), Ok(()));
            assert_eq!(pool.remove(&flowc_id), Ok(()));
        }
    }

    #[test]
    fn close_recycle() {
        let mut core = Core::new().unwrap();
        let ptr = Pool::new();
        let flow = Flow::new(None);

        let flow_id = {
            flow.read().unwrap().id.to_owned()
        };

        {
            let mut pool = ptr.write().unwrap();
            pool.insert(flow.clone());
            assert!(Arc::ptr_eq(&pool.get(&flow_id).unwrap(), &flow));
        }

        {
            let fut = flow.write().unwrap().close();
            core.run(fut).is_ok();
        }

        {
            let fut = flow.read().unwrap().pull(0, Some(0));
            core.run(fut).is_err();
        }

        {
            let pool = ptr.read().unwrap();
            assert!(!pool.get(&flow_id).is_some());
        }
    }
}
<commit_msg>Improve tests<commit_after>use flow::{Flow, Observer};
use std::collections::HashMap;
use std::sync::{Arc, Mutex, RwLock, Weak};

type SharedFlow = Arc<RwLock<Flow>>;

type LinkPointer<T> = Weak<Mutex<T>>;

struct TimeLinkNode {
    key: String,
    prev: Option<LinkPointer<TimeLinkNode>>,
    next: Option<LinkPointer<TimeLinkNode>>,
}

struct Entry {
    flow: SharedFlow,
    timelink: Arc<Mutex<TimeLinkNode>>,
}

pub struct Pool {
    weakref: Weak<RwLock<Pool>>,
    bucket: HashMap<String, Entry>,
    timelink_head: Option<LinkPointer<TimeLinkNode>>,
    timelink_tail: Option<LinkPointer<TimeLinkNode>>,
}

impl Entry {
    fn new(flow_id: &str, flow_ptr: SharedFlow) -> Self {
        Entry {
            flow: flow_ptr,
            timelink: Arc::new(Mutex::new(TimeLinkNode {
                                              key: flow_id.to_owned(),
                                              prev: Some(Weak::new()),
                                              next: Some(Weak::new()),
                                          })),
        }
    }
}

impl TimeLinkNode {
    fn push(timelink: &Arc<Mutex<TimeLinkNode>>, pool: &mut Pool) {
        let mut link = timelink.lock().unwrap();
        link.prev = None;
        link.next = pool.timelink_head.clone();
        let link_ptr = Arc::downgrade(timelink);
        if let Some(ref head) = pool.timelink_head {
            let head = head.upgrade().unwrap();
            head.lock().unwrap().prev = Some(link_ptr.clone());
        }
        pool.timelink_head = Some(link_ptr);
    }

    fn unlink(timelink: &Arc<Mutex<TimeLinkNode>>, pool: &mut Pool) {
        let mut link = timelink.lock().unwrap();
        if let Some(ref prev) = link.prev {
            // Upgrade should always success.
            let prev = prev.upgrade().unwrap();
            prev.lock().unwrap().next = link.next.clone();
        } else {
            pool.timelink_head = link.next.clone();
        }
        if let Some(ref next) = link.next {
            // Upgrade should always success.
            let next = next.upgrade().unwrap();
            next.lock().unwrap().prev = link.prev.clone();
        } else {
            pool.timelink_tail = link.prev.clone();
        }
        link.prev = Some(Weak::new());
        link.next = Some(Weak::new());
    }
}

impl Pool {
    pub fn new() -> Arc<RwLock<Self>> {
        let pool = Pool {
            weakref: Weak::new(),
            bucket: HashMap::new(),
            timelink_head: None,
            timelink_tail: None,
        };
        let pool_ptr = Arc::new(RwLock::new(pool));
        pool_ptr.write().unwrap().weakref = Arc::downgrade(&pool_ptr);
        pool_ptr
    }

    pub fn insert(&mut self, flow_ptr: SharedFlow) {
        // Occupy the flow to prevent from race condition.
        let mut flow = flow_ptr.write().unwrap();
        let timelink = {
            self.bucket
                .entry(flow.id.to_owned())
                .or_insert(Entry::new(&flow.id, flow_ptr.clone()))
                .timelink
                .clone()
        };
        flow.observe(self.weakref.clone());
        TimeLinkNode::push(&timelink, self);
    }

    pub fn get(&self, flow_id: &str) -> Option<SharedFlow> {
        self.bucket.get(flow_id).map(|entry| entry.flow.clone())
    }

    pub fn remove(&mut self, flow_id: &str) -> Result<(), ()> {
        self.bucket
            .remove(flow_id)
            .ok_or(())
            .and_then(|entry| {
                TimeLinkNode::unlink(&entry.timelink, self);
                Ok(())
            })
    }
}

impl Observer for Weak<RwLock<Pool>> {
    fn on_active(&self, flow: &Flow) {
        if let Some(pool_ptr) = self.upgrade() {
            // TODO minimize the pool write lock.
            let mut pool = pool_ptr.write().unwrap();
            let timelink = match pool.bucket.get(&flow.id) {
                Some(entry) => entry.timelink.clone(),
                None => return,
            };
            TimeLinkNode::unlink(&timelink, &mut pool);
            TimeLinkNode::push(&timelink, &mut pool);
        }
    }

    fn on_close(&self, flow: &Flow) {
        if let Some(pool_ptr) = self.upgrade() {
            let mut pool = pool_ptr.write().unwrap();
            // Try to remove the flow.
            pool.remove(&flow.id).is_ok();
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use flow::{self, Flow};
    use std::sync::Arc;
    use tokio::reactor::Core;

    #[test]
    fn basic_operations() {
        let ptr = Pool::new();
        let flow_a = Flow::new(None);
        let flow_b = Flow::new(None);
        let flow_c = Flow::new(None);

        let (flowa_id, flowb_id, flowc_id) = {
            (flow_a.read().unwrap().id.to_owned(),
             flow_b.read().unwrap().id.to_owned(),
             flow_c.read().unwrap().id.to_owned())
        };

        {
            let mut pool = ptr.write().unwrap();
            pool.insert(flow_a.clone());
            pool.insert(flow_b.clone());
            pool.insert(flow_c.clone());
        }

        {
            let pool = ptr.read().unwrap();
            assert!(Arc::ptr_eq(&pool.get(&flowa_id).unwrap(), &flow_a));
            assert!(Arc::ptr_eq(&pool.get(&flowb_id).unwrap(), &flow_b));
            assert!(!Arc::ptr_eq(&pool.get(&flowa_id).unwrap(), &flow_b));
            assert!(!Arc::ptr_eq(&pool.get(&flowb_id).unwrap(), &flow_a));
            assert!(pool.get("C").is_none());
        }

        {
            let mut pool = ptr.write().unwrap();
            assert_eq!(pool.remove(&flowb_id), Ok(()));
            assert_eq!(pool.remove(&flowa_id), Ok(()));
            assert_eq!(pool.remove(&flowc_id), Ok(()));
        }

        {
            let pool = ptr.read().unwrap();
            assert!(pool.get(&flowa_id).is_none());
            assert!(pool.get(&flowb_id).is_none());
            assert!(pool.get(&flowc_id).is_none());
        }
    }

    #[test]
    fn close_recycle() {
        let mut core = Core::new().unwrap();
        let ptr = Pool::new();
        let flow = Flow::new(None);

        let flow_id = {
            flow.read().unwrap().id.to_owned()
        };

        {
            let mut pool = ptr.write().unwrap();
            pool.insert(flow.clone());
            assert!(Arc::ptr_eq(&pool.get(&flow_id).unwrap(), &flow));
        }

        {
            let fut = flow.write().unwrap().close();
            core.run(fut).unwrap();
        }

        {
            let fut = flow.read().unwrap().pull(0, Some(0));
            core.run(fut).is_err();
        }

        {
            let pool = ptr.read().unwrap();
            assert!(pool.get(&flow_id).is_none());
        }
    }

    #[test]
    fn dropped() {
        let mut core = Core::new().unwrap();
        let flow = Flow::new(None);

        {
            let ptr = Pool::new();

            let flow_id = {
                flow.read().unwrap().id.to_owned()
            };

            {
                let mut pool = ptr.write().unwrap();
                pool.insert(flow.clone());
                pool.remove(&flow_id).unwrap();
            }

            {
                let pool = ptr.read().unwrap();
                assert!(pool.get(&flow_id).is_none());
            }

            {
                let fut = flow.write().unwrap().close();
                core.run(fut).unwrap();
            }
        }

        {
            let fut = flow.read().unwrap().pull(0, Some(0));
            assert_eq!(core.run(fut), Err(flow::Error::Eof));
        }
    }
}
<|endoftext|>