<commit_before>use crate::num::Bounded;
use std::mem;

#[cfg(feature = "dim3")]
use na::Point2;
use na::{self, Real};

use crate::bounding_volume::AABB;
use crate::shape::{FeatureId, Segment};
use crate::math::{Isometry, Vector, Point};
use crate::query::{Ray, RayCast, RayIntersection};

impl<N: Real> RayCast<N> for AABB<N> {
    fn toi_with_ray(&self, m: &Isometry<N>, ray: &Ray<N>, solid: bool) -> Option<N> {
        let ls_ray = ray.inverse_transform_by(m);

        let mut tmin: N = na::zero();
        let mut tmax: N = Bounded::max_value();

        for i in 0usize..na::dimension::<Vector<N>>() {
            if ls_ray.dir[i].is_zero() {
                if ls_ray.origin[i] < self.mins()[i] || ls_ray.origin[i] > self.maxs()[i] {
                    return None;
                }
            } else {
                let _1: N = na::one();
                let denom = _1 / ls_ray.dir[i];
                let mut inter_with_near_plane = (self.mins()[i] - ls_ray.origin[i]) * denom;
                let mut inter_with_far_plane = (self.maxs()[i] - ls_ray.origin[i]) * denom;

                if inter_with_near_plane > inter_with_far_plane {
                    mem::swap(&mut inter_with_near_plane, &mut inter_with_far_plane)
                }

                tmin = tmin.max(inter_with_near_plane);
                tmax = tmax.min(inter_with_far_plane);

                if tmin > tmax {
                    // This covers the case where tmax is negative because tmin is
                    // initialized at zero.
                    return None;
                }
            }
        }

        if tmin.is_zero() && !solid {
            Some(tmax)
        } else {
            Some(tmin)
        }
    }

    #[inline]
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        let ls_ray = ray.inverse_transform_by(m);

        ray_aabb(self, &ls_ray, solid).map(|(t, n, i)| {
            let feature = if i < 0 {
                FeatureId::Face(-i as usize - 1 + 3)
            } else {
                FeatureId::Face(i as usize - 1)
            };

            RayIntersection::new(t, m * n, feature)
        })
    }

    #[cfg(feature = "dim3")]
    fn toi_and_normal_and_uv_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        do_toi_and_normal_and_uv_with_ray(m, self, ray, solid)
    }
}

impl<N: Real> AABB<N> {
    /// Computes the parameters of the two intersection points between a line and this AABB.
    ///
    /// The parameters are such that the point are given by `orig + dir * parameter`.
    /// Returns `None` if there is no intersection.
    #[inline]
    pub fn clip_line_parameters(&self, orig: &Point<N>, dir: &Vector<N>) -> Option<(N, N)> {
        clip_line(self, orig, dir).map(|clip| ((clip.0).0, (clip.1).0))
    }

    /// Computes the intersection segment between a line and this AABB.
    ///
    /// Returns `None` if there is no intersection.
    #[inline]
    pub fn clip_line(&self, orig: &Point<N>, dir: &Vector<N>) -> Option<Segment<N>> {
        clip_line(self, orig, dir).map(|clip| {
            Segment::new(orig + dir * (clip.0).0, orig + dir * (clip.1).0)
        })
    }

    /// Computes the parameters of the two intersection points between a ray and this AABB.
    ///
    /// The parameters are such that the point are given by `ray.orig + ray.dir * parameter`.
    /// Returns `None` if there is no intersection.
    #[inline]
    pub fn clip_ray_parameters(&self, ray: &Ray<N>) -> Option<(N, N)> {
        match self.clip_line_parameters(&ray.origin, &ray.dir) {
            Some(clip) => {
                let t0 = clip.0;
                let t1 = clip.1;

                if t1 < N::zero() {
                    None
                } else {
                    Some((na::sup(&t0, &N::zero()), t1))
                }
            }
            None => None
        }
    }

    /// Computes the intersection segment between a ray and this AABB.
    ///
    /// Returns `None` if there is no intersection.
    #[inline]
    pub fn clip_ray(&self, ray: &Ray<N>) -> Option<Segment<N>> {
        self.clip_ray_parameters(ray).map(|clip| {
            Segment::new(ray.point_at(clip.0), ray.point_at(clip.1))
        })
    }
}

#[cfg(feature = "dim3")]
fn do_toi_and_normal_and_uv_with_ray<N: Real>(
    m: &Isometry<N>,
    aabb: &AABB<N>,
    ray: &Ray<N>,
    solid: bool,
) -> Option<RayIntersection<N>>
{
    if na::dimension::<Vector<N>>() != 3 {
        aabb.toi_and_normal_with_ray(m, ray, solid)
    } else {
        let ls_ray = ray.inverse_transform_by(m);

        ray_aabb(aabb, &ls_ray, solid).map(|(t, n, s)| {
            let pt = ls_ray.origin + ls_ray.dir * t;
            let dpt = pt - *aabb.mins();
            let scale = *aabb.maxs() - *aabb.mins();
            let id = s.abs();
            let gs_n = m * n;
            let feature = if s < 0 {
                FeatureId::Face(id as usize - 1 + 3)
            } else {
                FeatureId::Face(id as usize - 1)
            };

            if id == 1 {
                RayIntersection::new_with_uvs(
                    t,
                    gs_n,
                    feature,
                    Some(Point2::new(dpt[1] / scale[1], dpt[2] / scale[2])),
                )
            } else if id == 2 {
                RayIntersection::new_with_uvs(
                    t,
                    gs_n,
                    feature,
                    Some(Point2::new(dpt[2] / scale[2], dpt[0] / scale[0])),
                )
            } else {
                RayIntersection::new_with_uvs(
                    t,
                    gs_n,
                    feature,
                    Some(Point2::new(dpt[0] / scale[0], dpt[1] / scale[1])),
                )
            }
        })
    }
}

fn clip_line<N: Real>(aabb: &AABB<N>, origin: &Point<N>, dir: &Vector<N>) -> Option<((N, Vector<N>, isize), (N, Vector<N>, isize))> {
    let mut tmax: N = Bounded::max_value();
    let mut tmin: N = -tmax;
    let mut near_side = 0;
    let mut far_side = 0;
    let mut near_diag = false;
    let mut far_diag = false;

    for i in 0usize..na::dimension::<Vector<N>>() {
        if dir[i].is_zero() {
            if origin[i] < aabb.mins()[i] || origin[i] > aabb.maxs()[i] {
                return None;
            }
        } else {
            let _1: N = na::one();
            let denom = _1 / dir[i];
            let flip_sides;
            let mut inter_with_near_plane = (aabb.mins()[i] - origin[i]) * denom;
            let mut inter_with_far_plane = (aabb.maxs()[i] - origin[i]) * denom;

            if inter_with_near_plane > inter_with_far_plane {
                flip_sides = true;
                mem::swap(&mut inter_with_near_plane, &mut inter_with_far_plane)
            } else {
                flip_sides = false;
            }

            if inter_with_near_plane > tmin {
                tmin = inter_with_near_plane;
                near_side = if flip_sides {
                    -(i as isize + 1)
                } else {
                    i as isize + 1
                };
                near_diag = false;
            } else if inter_with_near_plane == tmin {
                near_diag = true;
            }

            if inter_with_far_plane < tmax {
                tmax = inter_with_far_plane;
                far_side = if !flip_sides {
                    -(i as isize + 1)
                } else {
                    i as isize + 1
                };
                far_diag = false;
            } else if inter_with_far_plane == tmax {
                far_diag = true;
            }

            if tmin > tmax {
                return None;
            }
        }
    }

    let near = if near_diag {
        (tmin, -dir.normalize(), near_side)
    } else {
        let mut normal = Vector::zeros();

        if near_side < 0 {
            normal[(-near_side - 1) as usize] = N::one();
        } else {
            normal[(near_side - 1) as usize] = -N::one();
        }

        (tmin, normal, near_side)
    };

    let far = if far_diag {
        (tmax, -dir.normalize(), far_side)
    } else {
        let mut normal = Vector::zeros();

        if far_side < 0 {
            normal[(-far_side - 1) as usize] = -N::one();
        } else {
            normal[(far_side - 1) as usize] = N::one();
        }

        (tmax, normal, far_side)
    };

    Some((near, far))
}

fn ray_aabb<N: Real>(aabb: &AABB<N>, ray: &Ray<N>, solid: bool) -> Option<(N, Vector<N>, isize)> {
    if let Some((near, far)) = clip_line(aabb, &ray.origin, &ray.dir) {
        if near.0 < N::zero() {
            if solid {
                Some((na::zero(), na::zero(), far.2))
            } else {
                Some(far)
            }
        } else {
            Some(near)
        }
    } else {
        None
    }
}<commit_msg>Fix ray-cast on AABB bug due to erroneous merge<commit_after>use crate::num::Bounded;
use std::mem;

#[cfg(feature = "dim3")]
use na::Point2;
use na::{self, Real};

use crate::bounding_volume::AABB;
use crate::shape::{FeatureId, Segment};
use crate::math::{Isometry, Vector, Point};
use crate::query::{Ray, RayCast, RayIntersection};

impl<N: Real> RayCast<N> for AABB<N> {
    fn toi_with_ray(&self, m: &Isometry<N>, ray: &Ray<N>, solid: bool) -> Option<N> {
        let ls_ray = ray.inverse_transform_by(m);

        let mut tmin: N = na::zero();
        let mut tmax: N = Bounded::max_value();

        for i in 0usize..na::dimension::<Vector<N>>() {
            if ls_ray.dir[i].is_zero() {
                if ls_ray.origin[i] < self.mins()[i] || ls_ray.origin[i] > self.maxs()[i] {
                    return None;
                }
            } else {
                let _1: N = na::one();
                let denom = _1 / ls_ray.dir[i];
                let mut inter_with_near_plane = (self.mins()[i] - ls_ray.origin[i]) * denom;
                let mut inter_with_far_plane = (self.maxs()[i] - ls_ray.origin[i]) * denom;

                if inter_with_near_plane > inter_with_far_plane {
                    mem::swap(&mut inter_with_near_plane, &mut inter_with_far_plane)
                }

                tmin = tmin.max(inter_with_near_plane);
                tmax = tmax.min(inter_with_far_plane);

                if tmin > tmax {
                    // This covers the case where tmax is negative because tmin is
                    // initialized at zero.
                    return None;
                }
            }
        }

        if tmin.is_zero() && !solid {
            Some(tmax)
        } else {
            Some(tmin)
        }
    }

    #[inline]
    fn toi_and_normal_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        let ls_ray = ray.inverse_transform_by(m);

        ray_aabb(self, &ls_ray, solid).map(|(t, n, i)| {
            let feature = if i < 0 {
                FeatureId::Face(-i as usize - 1 + 3)
            } else {
                FeatureId::Face(i as usize - 1)
            };

            RayIntersection::new(t, m * n, feature)
        })
    }

    #[cfg(feature = "dim3")]
    fn toi_and_normal_and_uv_with_ray(
        &self,
        m: &Isometry<N>,
        ray: &Ray<N>,
        solid: bool,
    ) -> Option<RayIntersection<N>>
    {
        do_toi_and_normal_and_uv_with_ray(m, self, ray, solid)
    }
}

impl<N: Real> AABB<N> {
    /// Computes the parameters of the two intersection points between a line and this AABB.
    ///
    /// The parameters are such that the point are given by `orig + dir * parameter`.
    /// Returns `None` if there is no intersection.
    #[inline]
    pub fn clip_line_parameters(&self, orig: &Point<N>, dir: &Vector<N>) -> Option<(N, N)> {
        clip_line(self, orig, dir).map(|clip| ((clip.0).0, (clip.1).0))
    }

    /// Computes the intersection segment between a line and this AABB.
    ///
    /// Returns `None` if there is no intersection.
    #[inline]
    pub fn clip_line(&self, orig: &Point<N>, dir: &Vector<N>) -> Option<Segment<N>> {
        clip_line(self, orig, dir).map(|clip| {
            Segment::new(orig + dir * (clip.0).0, orig + dir * (clip.1).0)
        })
    }

    /// Computes the parameters of the two intersection points between a ray and this AABB.
    ///
    /// The parameters are such that the point are given by `ray.orig + ray.dir * parameter`.
    /// Returns `None` if there is no intersection.
    #[inline]
    pub fn clip_ray_parameters(&self, ray: &Ray<N>) -> Option<(N, N)> {
        match self.clip_line_parameters(&ray.origin, &ray.dir) {
            Some(clip) => {
                let t0 = clip.0;
                let t1 = clip.1;

                if t1 < N::zero() {
                    None
                } else {
                    Some((na::sup(&t0, &N::zero()), t1))
                }
            }
            None => None
        }
    }

    /// Computes the intersection segment between a ray and this AABB.
    ///
    /// Returns `None` if there is no intersection.
    #[inline]
    pub fn clip_ray(&self, ray: &Ray<N>) -> Option<Segment<N>> {
        self.clip_ray_parameters(ray).map(|clip| {
            Segment::new(ray.point_at(clip.0), ray.point_at(clip.1))
        })
    }
}

#[cfg(feature = "dim3")]
fn do_toi_and_normal_and_uv_with_ray<N: Real>(
    m: &Isometry<N>,
    aabb: &AABB<N>,
    ray: &Ray<N>,
    solid: bool,
) -> Option<RayIntersection<N>>
{
    if na::dimension::<Vector<N>>() != 3 {
        aabb.toi_and_normal_with_ray(m, ray, solid)
    } else {
        let ls_ray = ray.inverse_transform_by(m);

        ray_aabb(aabb, &ls_ray, solid).map(|(t, n, s)| {
            let pt = ls_ray.origin + ls_ray.dir * t;
            let dpt = pt - *aabb.mins();
            let scale = *aabb.maxs() - *aabb.mins();
            let id = s.abs();
            let gs_n = m * n;
            let feature = if s < 0 {
                FeatureId::Face(id as usize - 1 + 3)
            } else {
                FeatureId::Face(id as usize - 1)
            };

            if id == 1 {
                RayIntersection::new_with_uvs(
                    t,
                    gs_n,
                    feature,
                    Some(Point2::new(dpt[1] / scale[1], dpt[2] / scale[2])),
                )
            } else if id == 2 {
                RayIntersection::new_with_uvs(
                    t,
                    gs_n,
                    feature,
                    Some(Point2::new(dpt[2] / scale[2], dpt[0] / scale[0])),
                )
            } else {
                RayIntersection::new_with_uvs(
                    t,
                    gs_n,
                    feature,
                    Some(Point2::new(dpt[0] / scale[0], dpt[1] / scale[1])),
                )
            }
        })
    }
}

fn clip_line<N: Real>(aabb: &AABB<N>, origin: &Point<N>, dir: &Vector<N>) -> Option<((N, Vector<N>, isize), (N, Vector<N>, isize))> {
    // NOTE: we don't start with tmin = 0 so we can return the correct normal
    // when the ray starts exactly on the object contour.

    let mut tmax: N = Bounded::max_value();
    let mut tmin: N = -tmax;
    let mut near_side = 0;
    let mut far_side = 0;
    let mut near_diag = false;
    let mut far_diag = false;

    for i in 0usize..na::dimension::<Vector<N>>() {
        if dir[i].is_zero() {
            if origin[i] < aabb.mins()[i] || origin[i] > aabb.maxs()[i] {
                return None;
            }
        } else {
            let _1: N = na::one();
            let denom = _1 / dir[i];
            let flip_sides;
            let mut inter_with_near_plane = (aabb.mins()[i] - origin[i]) * denom;
            let mut inter_with_far_plane = (aabb.maxs()[i] - origin[i]) * denom;

            if inter_with_near_plane > inter_with_far_plane {
                flip_sides = true;
                mem::swap(&mut inter_with_near_plane, &mut inter_with_far_plane)
            } else {
                flip_sides = false;
            }

            if inter_with_near_plane > tmin {
                tmin = inter_with_near_plane;
                near_side = if flip_sides {
                    -(i as isize + 1)
                } else {
                    i as isize + 1
                };
                near_diag = false;
            } else if inter_with_near_plane == tmin {
                near_diag = true;
            }

            if inter_with_far_plane < tmax {
                tmax = inter_with_far_plane;
                far_side = if !flip_sides {
                    -(i as isize + 1)
                } else {
                    i as isize + 1
                };
                far_diag = false;
            } else if inter_with_far_plane == tmax {
                far_diag = true;
            }

            if tmax < N::zero() || tmin > tmax {
                return None;
            }
        }
    }

    let near = if near_diag {
        (tmin, -dir.normalize(), near_side)
    } else {
        let mut normal = Vector::zeros();

        if near_side < 0 {
            normal[(-near_side - 1) as usize] = N::one();
        } else {
            normal[(near_side - 1) as usize] = -N::one();
        }

        (tmin, normal, near_side)
    };

    let far = if far_diag {
        (tmax, -dir.normalize(), far_side)
    } else {
        let mut normal = Vector::zeros();

        if far_side < 0 {
            normal[(-far_side - 1) as usize] = -N::one();
        } else {
            normal[(far_side - 1) as usize] = N::one();
        }

        (tmax, normal, far_side)
    };

    Some((near, far))
}

fn ray_aabb<N: Real>(aabb: &AABB<N>, ray: &Ray<N>, solid: bool) -> Option<(N, Vector<N>, isize)> {
    if let Some((near, far)) = clip_line(aabb, &ray.origin, &ray.dir) {
        if near.0 < N::zero() {
            if solid {
                Some((na::zero(), na::zero(), far.2))
            } else {
                Some(far)
            }
        } else {
            Some(near)
        }
    } else {
        None
    }
}<|endoftext|>


<commit_before>extern crate num;
extern crate rand;
extern crate bincode;
extern crate rustc_serialize;
extern crate vec_map;
extern crate image;
extern crate euclid;
#[macro_use]
extern crate lazy_static;
extern crate vitral;
extern crate vitral_atlas;
extern crate calx_alg;
extern crate calx_grid;
extern crate calx_color;
#[macro_use]
extern crate calx_ecs;
#[macro_use]
extern crate calx_resource;

use std::collections::HashSet;
use euclid::{Point2D, Rect, Size2D};

mod ability;

mod brush;
pub use brush::{Brush, BrushBuilder, Color, Frame, ImageRef, Splat};

mod command;
pub use command::Command;

mod components;
mod field;
mod flags;
mod form;
mod fov;
pub mod init;
mod item;

mod location;
pub use location::{Location, Portal};

mod location_set;
// TODO: Make private, trigger mapgen internally using higher-level API
pub mod mapgen;
mod mutate;

mod query;
pub use query::Query;

mod spatial;
mod stats;

mod terraform;
pub use terraform::Terraform;
pub use terraform::TerrainQuery;

pub mod terrain;

mod world;
pub use world::{World, Ecs};

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum FovStatus {
    Seen,
    Remembered,
}

/// Return whether the given chart point is on the currently visible screen.
///
/// It is assumed that the chart point 0, 0 is at the center of the screen.
///
/// Since various bits of game logic are tied to the screen boundaries, the screen size is fixed as
/// a constant.
fn on_screen(chart_pos: Point2D<i32>) -> bool {
    const W: i32 = 39;
    const H: i32 = 22;
    let (x, y) = (chart_pos.x, chart_pos.y);

    x <= y + (W + 1) / 2 // east
        && x >= y - (W - 1) / 2 // west
        && x >= -H - y // north
        && x <= H - 1 - y // south
}

pub fn onscreen_locations() -> &'static HashSet<Point2D<i32>> {
    lazy_static! {
        static ref ONSCREEN_LOCATIONS: HashSet<Point2D<i32>> = {
            let mut m = HashSet::new();

            // XXX: Hardcoded limits, tied to W and H in on-screen but expressed differently here.
            for y in -20..21 {
                for x in -20..21 {
                    let point = Point2D::new(x, y);
                    if on_screen(point) {
                        m.insert(point);
                    }
                }
            }
            m
        };
    }

    &*ONSCREEN_LOCATIONS
}
<commit_msg>Fix hardcoded limits to contain whole screen area<commit_after>extern crate num;
extern crate rand;
extern crate bincode;
extern crate rustc_serialize;
extern crate vec_map;
extern crate image;
extern crate euclid;
#[macro_use]
extern crate lazy_static;
extern crate vitral;
extern crate vitral_atlas;
extern crate calx_alg;
extern crate calx_grid;
extern crate calx_color;
#[macro_use]
extern crate calx_ecs;
#[macro_use]
extern crate calx_resource;

use std::collections::HashSet;
use euclid::{Point2D, Rect, Size2D};

mod ability;

mod brush;
pub use brush::{Brush, BrushBuilder, Color, Frame, ImageRef, Splat};

mod command;
pub use command::Command;

mod components;
mod field;
mod flags;
mod form;
mod fov;
pub mod init;
mod item;

mod location;
pub use location::{Location, Portal};

mod location_set;
// TODO: Make private, trigger mapgen internally using higher-level API
pub mod mapgen;
mod mutate;

mod query;
pub use query::Query;

mod spatial;
mod stats;

mod terraform;
pub use terraform::Terraform;
pub use terraform::TerrainQuery;

pub mod terrain;

mod world;
pub use world::{World, Ecs};

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum FovStatus {
    Seen,
    Remembered,
}

/// Return whether the given chart point is on the currently visible screen.
///
/// It is assumed that the chart point 0, 0 is at the center of the screen.
///
/// Since various bits of game logic are tied to the screen boundaries, the screen size is fixed as
/// a constant.
fn on_screen(chart_pos: Point2D<i32>) -> bool {
    const W: i32 = 39;
    const H: i32 = 22;
    let (x, y) = (chart_pos.x, chart_pos.y);

    x <= y + (W + 1) / 2 // east
        && x >= y - (W - 1) / 2 // west
        && x >= -H - y // north
        && x <= H - 1 - y // south
}

pub fn onscreen_locations() -> &'static HashSet<Point2D<i32>> {
    lazy_static! {
        static ref ONSCREEN_LOCATIONS: HashSet<Point2D<i32>> = {
            let mut m = HashSet::new();

            // XXX: Hardcoded limits, tied to W and H in on-screen but expressed differently here.
            for y in -21..21 {
                for x in -21..21 {
                    let point = Point2D::new(x, y);
                    if on_screen(point) {
                        m.insert(point);
                    }
                }
            }
            m
        };
    }

    &*ONSCREEN_LOCATIONS
}
<|endoftext|>


<commit_before>// Copyright 2015-2018 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Worker for performing corpus imports, when served as "init" tasks by the `CorTeX` dispatcher

extern crate pericortex;
extern crate rand;
extern crate zmq;

use std::fs::File;
use std::path::Path;
use std::thread;
use std::time::Duration;
use zmq::{Context, Error, Message, SNDMORE};

use backend;
use backend::DEFAULT_DB_ADDRESS;
use importer::Importer;
use models::{Corpus, NewCorpus, Task};
use pericortex::worker::Worker;

/// `Worker` for initializing/importing a new corpus into `CorTeX`
pub struct InitWorker {
  /// name of the service ("init")
  pub service: String,
  /// version, as usual
  pub version: f32,
  /// message size, as usual
  pub message_size: usize,
  /// full URL (including port) to task source/dispatcher
  pub source: String,
  /// full URL (including port) to task sink/receiver
  pub sink: String,
  /// address to the Task store backend
  /// (special case, only for the init service, third-party workers can't access the Task store
  /// directly)
  pub backend_address: String,
}
impl Default for InitWorker {
  fn default() -> InitWorker {
    InitWorker {
      service: "init".to_string(),
      version: 0.1,
      message_size: 100_000,
      source: "tcp://localhost:5555".to_string(),
      sink: "tcp://localhost:5556".to_string(),
      backend_address: DEFAULT_DB_ADDRESS.to_string(),
    }
  }
}
impl Worker for InitWorker {
  fn service(&self) -> String { self.service.clone() }
  fn source(&self) -> String { self.source.clone() }
  fn sink(&self) -> String { self.sink.clone() }
  fn message_size(&self) -> usize { self.message_size }

  fn convert(&self, path: &Path) -> Option<File> {
    let path_str = path.to_str().unwrap().to_string();
    let backend = backend::from_address(&self.backend_address);
    let corpus = NewCorpus {
      path: path_str.clone(),
      name: path_str.clone(),
      complex: true,
      description: String::new(),
    };
    // Add the new corpus.
    backend.add(&corpus).expect("Failed to create new corpus.");
    let registered_corpus =
      Corpus::find_by_name(&path_str, &backend.connection).expect("Failed to create new corpus.");

    // Create an importer for the corpus, and then process all entries to populate CorTeX tasks
    let importer = Importer {
      corpus: registered_corpus,
      backend: backend::from_address(&self.backend_address),
      cwd: Importer::cwd(),
    };

    importer.process().unwrap();
    // TODO: Stopgap, we should do the error-reporting well
    None
  }

  fn start(&self, limit: Option<usize>) -> Result<(), Error> {
    let mut work_counter = 0;
    // Connect to a task ventilator
    let context_source = Context::new();
    let source = context_source.socket(zmq::DEALER).unwrap();
    let identity: String = (0..10).map(|_| rand::random::<u8>() as char).collect();
    source.set_identity(identity.as_bytes()).unwrap();

    assert!(source.connect(&self.source()).is_ok());
    // Connect to a task sink
    let context_sink = Context::new();
    let sink = context_sink.socket(zmq::PUSH).unwrap();
    assert!(sink.connect(&self.sink()).is_ok());
    let backend = backend::from_address(&self.backend_address);
    // Work in perpetuity
    loop {
      let mut taskid_msg = Message::new().unwrap();
      let mut recv_msg = Message::new().unwrap();

      source.send_str(&self.service(), 0).unwrap();
      source.recv(&mut taskid_msg, 0).unwrap();
      let taskid = taskid_msg.as_str().unwrap();

      // Terminating with an empty message in place of a payload (INIT is special)
      source.recv(&mut recv_msg, 0).unwrap();

      let task_result = Task::find(taskid.parse::<i64>().unwrap(), &backend.connection);
      let task = match task_result {
        Ok(t) => t,
        _ => {
          // If there was nothing to do, retry a minute later
          thread::sleep(Duration::new(60, 0));
          continue;
        },
      };

      self.convert(Path::new(&task.entry));

      sink.send_str(&self.service(), SNDMORE).unwrap();
      sink.send_str(taskid, SNDMORE).unwrap();
      sink.send(&[], 0).unwrap();

      work_counter += 1;
      if let Some(upper_bound) = limit {
        if work_counter >= upper_bound {
          // Give enough time to complete the Final job.
          thread::sleep(Duration::from_millis(500));
          break;
        }
      };
    }
    Ok(())
  }
}
<commit_msg>try to guess a reasonable corpus name on import<commit_after>// Copyright 2015-2018 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Worker for performing corpus imports, when served as "init" tasks by the `CorTeX` dispatcher

extern crate pericortex;
extern crate rand;
extern crate zmq;

use std::fs::File;
use std::path::Path;
use std::thread;
use std::time::Duration;
use zmq::{Context, Error, Message, SNDMORE};

use backend;
use backend::DEFAULT_DB_ADDRESS;
use importer::Importer;
use models::{Corpus, NewCorpus, Task};
use pericortex::worker::Worker;

/// `Worker` for initializing/importing a new corpus into `CorTeX`
pub struct InitWorker {
  /// name of the service ("init")
  pub service: String,
  /// version, as usual
  pub version: f32,
  /// message size, as usual
  pub message_size: usize,
  /// full URL (including port) to task source/dispatcher
  pub source: String,
  /// full URL (including port) to task sink/receiver
  pub sink: String,
  /// address to the Task store backend
  /// (special case, only for the init service, third-party workers can't access the Task store
  /// directly)
  pub backend_address: String,
}
impl Default for InitWorker {
  fn default() -> InitWorker {
    InitWorker {
      service: "init".to_string(),
      version: 0.1,
      message_size: 100_000,
      source: "tcp://localhost:5555".to_string(),
      sink: "tcp://localhost:5556".to_string(),
      backend_address: DEFAULT_DB_ADDRESS.to_string(),
    }
  }
}
impl Worker for InitWorker {
  fn service(&self) -> String { self.service.clone() }
  fn source(&self) -> String { self.source.clone() }
  fn sink(&self) -> String { self.sink.clone() }
  fn message_size(&self) -> usize { self.message_size }

  fn convert(&self, path_opt: &Path) -> Option<File> {
    let path = path_opt.to_str().unwrap().to_string();
    let name = path.rsplitn(1, "/").next().unwrap_or(&path).to_lowercase(); // TODO: this is Unix path only
    let backend = backend::from_address(&self.backend_address);
    let corpus = NewCorpus {
      path: path.clone(),
      name: name.clone(),
      complex: true,
      description: String::new(),
    };
    // Add the new corpus.
    backend.add(&corpus).expect("Failed to create new corpus.");
    let registered_corpus =
      Corpus::find_by_name(&path, &backend.connection).expect("Failed to create new corpus.");

    // Create an importer for the corpus, and then process all entries to populate CorTeX tasks
    let importer = Importer {
      corpus: registered_corpus,
      backend: backend::from_address(&self.backend_address),
      cwd: Importer::cwd(),
    };

    importer.process().unwrap();
    // TODO: Stopgap, we should do the error-reporting well
    None
  }

  fn start(&self, limit: Option<usize>) -> Result<(), Error> {
    let mut work_counter = 0;
    // Connect to a task ventilator
    let context_source = Context::new();
    let source = context_source.socket(zmq::DEALER).unwrap();
    let identity: String = (0..10).map(|_| rand::random::<u8>() as char).collect();
    source.set_identity(identity.as_bytes()).unwrap();

    assert!(source.connect(&self.source()).is_ok());
    // Connect to a task sink
    let context_sink = Context::new();
    let sink = context_sink.socket(zmq::PUSH).unwrap();
    assert!(sink.connect(&self.sink()).is_ok());
    let backend = backend::from_address(&self.backend_address);
    // Work in perpetuity
    loop {
      let mut taskid_msg = Message::new().unwrap();
      let mut recv_msg = Message::new().unwrap();

      source.send_str(&self.service(), 0).unwrap();
      source.recv(&mut taskid_msg, 0).unwrap();
      let taskid = taskid_msg.as_str().unwrap();

      // Terminating with an empty message in place of a payload (INIT is special)
      source.recv(&mut recv_msg, 0).unwrap();

      let task_result = Task::find(taskid.parse::<i64>().unwrap(), &backend.connection);
      let task = match task_result {
        Ok(t) => t,
        _ => {
          // If there was nothing to do, retry a minute later
          thread::sleep(Duration::new(60, 0));
          continue;
        },
      };

      self.convert(Path::new(&task.entry));

      sink.send_str(&self.service(), SNDMORE).unwrap();
      sink.send_str(taskid, SNDMORE).unwrap();
      sink.send(&[], 0).unwrap();

      work_counter += 1;
      if let Some(upper_bound) = limit {
        if work_counter >= upper_bound {
          // Give enough time to complete the Final job.
          thread::sleep(Duration::from_millis(500));
          break;
        }
      };
    }
    Ok(())
  }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
//! Module for tracking the current thread, and wrapping non-`Send` objects in
//! guards that perform runtime thread checks.

use std::sync::Arc;
use std::fmt::{self, Debug};
use std::ptr;
use std::mem;
use std::cell::Cell;

/// A permanent identifier for a single thread, which will not be reused.
#[derive(Clone)]
pub struct ThreadId(Arc<()>);

impl PartialEq for ThreadId {
    fn eq(&self, other: &Self) -> bool {
        (&*self.0 as *const ()) == (&*other.0 as *const ())
    }
}
impl Eq for ThreadId {}

impl Debug for ThreadId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "thread({:?})", &*self.0 as *const ())
    }
}

// consider using https://github.com/rust-lang/rust/pull/29447 after it lands,
// or a u64 atomic where available
// is there a lock-free way to increment a 64-bit counter?
thread_local!(static THREAD_NONCE: ThreadId = ThreadId(Arc::new(())));

/// Returns a persistent identifier for the current thread.
pub fn current_thread_id() -> ThreadId {
    THREAD_NONCE.with(|r| r.clone())
}

struct TBListHead {
    // do not move
    owner: ThreadId,
    head: TBHeader,
    destroying: Cell<bool>,
}

/// A container for values which must be accessed within a particular scope in a particular thread.
/// Values may be added using the `bind_value` method, which returns a capability; the capability
/// may freely move between threads, but can only be used in the thread of the binding.  A bound
/// value will be destroyed when the capability is destroyed if that happens in the allowed thread;
/// otherwise it will be destroyed when the list is.
pub struct TBList {
    list: Arc<TBListHead>,
}

struct TBHeader {
    // do not move
    next: Cell<*const TBHeader>,
    prev: Cell<*const TBHeader>,
    free: unsafe fn(*const TBHeader),
}

struct TBVar<T: 'static> {
    // do not move
    value: T,
    header: TBHeader,
}

/// A handle to a value of type `T` which is owned by a specific thread.  Code running on the same
/// thread can freely manipulate the value; attempts to manipulate the value from other threads
/// will panic at runtime.
///
/// Lifetime is subtle.  Since we do not assume `T` can be safely dropped from any thread other
/// than that where it was created, dropping a `ThreadBound<T>` will only immediately drop the
/// wrapped value in the originating thread.  Drops occuring on other threads will leave the value
/// in a thread-local list associated with the originating thread, and the value will live until
/// the originating thread exits, at which point it will be destroyed. Conversely, if the
/// originating thread exits while there are `ThreadBound<T>` capabilities alive in the heap, all
/// of the underlying values will be dropped (this causes the capabilities to become dangling
/// pointers, but that is OK as the only thread that could dereference them is exiting).
pub struct ThreadBound<T: 'static> {
    list: Arc<TBListHead>,
    var: *mut TBVar<T>,
}

unsafe impl<T: 'static> Send for ThreadBound<T> {}
unsafe impl<T: 'static> Sync for ThreadBound<T> {}

unsafe fn unlink_var(header: *const TBHeader) {
    // precondition: the list is being destroyed or the capability has just been
    // dropped
    // (either way there will be no future attempts to access this header)
    // println!("unlink header {:?}", header);
    let prev = (*header).prev.get();
    let next = (*header).next.get();
    (*next).prev.set(prev);
    (*prev).next.set(next);
}

// unsafe fn list_dumper(why: &'static str, lh: &TBListHead) {
//     let pstart = &lh.head as *const TBHeader;
//     let mut p2 = pstart;
//     println!("list dump {}", why);
//     loop {
// println!("header@{:?}, next={next:?}, prev={prev:?}, free={free:?}",
// p2,
// next = (*p2).next.get(), prev = (*p2).prev.get(), free =
// (*p2).free);
//         p2 = (*p2).next.get();
//         if p2 == pstart { break; }
//     }
// }

unsafe fn destroy_var(header: *const TBHeader) {
    // println!("destroy header {:?}", header);
    unlink_var(header);
    ((*header).free)(header);
}

impl Drop for TBList {
    fn drop(&mut self) {
        self.list.destroying.set(true);
        let headp = &self.list.head as *const TBHeader;

        unsafe {
            // list_dumper("A",&*self.list);
            while (*headp).next.get() != headp {
                destroy_var((*headp).next.get());
            }
        }
    }
}

impl<T: 'static> Drop for ThreadBound<T> {
    fn drop(&mut self) {
        if self.list.owner == current_thread_id() && !self.list.destroying.get() {
            unsafe {
                // list_dumper("B", &*self.list);
                destroy_var(&(*self.var).header);
            }
        }
        // otherwise the var leaks and will be cleaned up when the originating thread
        // exits.  we could provide a scrub() function to call from the originating
        // thread, at the cost of extra synchronization.
    }
}

impl TBList {
    fn new() -> Self {
        unsafe fn unreachable(_head: *const TBHeader) {
            panic!("attempt to free TBList header");
        }
        let lheader = Arc::new(TBListHead {
            owner: current_thread_id(),
            destroying: Cell::new(false),
            head: TBHeader {
                next: Cell::new(ptr::null_mut()),
                prev: Cell::new(ptr::null_mut()),
                free: unreachable,
            },
        });
        let headp = &lheader.head as *const TBHeader;
        // println!("insert header {:?}", headp);
        unsafe {
            (*headp).next.set(headp);
            (*headp).prev.set(headp);
            // list_dumper("C", &*lheader);
        }
        TBList { list: lheader }
    }

    /// Creates a new scope for value bindings.  The lifetime of a scope list is forced to be a
    /// dynamic scope so that it will be properly nested with all `with` and `with_mut` borrows.
    pub fn scope<F, R>(f: F) -> R
        where F: FnOnce(&mut Self) -> R
    {
        f(&mut Self::new())
    }

    /// Transfers ownership of a value into a scope, and returns a capability which can be used to
    /// access that value but only within the same thread and during the same scope.
    pub fn bind<T: 'static>(&self, value: T) -> ThreadBound<T> {
        unsafe fn free<T: 'static>(header: *const TBHeader) {
            let offset = &(*(0 as *const TBVar<T>)).header as *const TBHeader as usize;
            let varp = ((header as usize) - offset) as *mut TBVar<T>;
            // println!("free/box {:?}", varp);
            mem::drop(Box::from_raw(varp));
        }

        let new_var: *mut TBVar<T> = Box::into_raw(Box::new(TBVar {
            header: TBHeader {
                next: Cell::new(ptr::null_mut()),
                prev: Cell::new(ptr::null_mut()),
                free: free::<T>,
            },
            value: value,
        }));

        unsafe {
            let new_head = &(*new_var).header as *const TBHeader;
            let list_head = &self.list.head as *const TBHeader;

            (*new_head).next.set(list_head);
            (*new_head).prev.set((*list_head).prev.get());
            (*(*list_head).prev.get()).next.set(new_head);
            (*list_head).prev.set(new_head);
            // list_dumper("D", &*self.list);
        }

        ThreadBound {
            var: new_var,
            list: self.list.clone(),
        }
    }
}

thread_local!(static THREAD_LIST_KEY: TBList = TBList::new());

impl<T: 'static> ThreadBound<T> {
    /// Wraps a value of type `T` in a capability bound to the current thread.  This uses a
    /// thread-local instance of `TBList` with the lifetime of the calling thread.
    pub fn new(inner: T) -> Self {
        THREAD_LIST_KEY.with(|tl| tl.bind(inner))
    }

    /// Returns true if this capability can be used without panicking.  This will remain true on
    /// the same thread as long as the thread does not enter the TLS destruction phase.
    pub fn accessible(&self) -> bool {
        return self.list.owner == current_thread_id() && !self.list.destroying.get();
    }

    fn check_access(&self) {
        if self.list.owner != current_thread_id() {
            panic!("Attempt to access ThreadBound from incorrect thread");
        }

        if self.list.destroying.get() {
            panic!("Attempt to access ThreadBound during TLS destruction phase");
        }
    }

    /// Consumes this capability to regain ownership of the underlying value.
    ///
    /// # Panics
    ///
    /// Panics if the capability is not accessible.
    pub fn into_inner(self) -> T {
        self.check_access();
        unsafe {
            unlink_var(&(*self.var).header as *const TBHeader);
            // yes, this is a move, so it invalidates the next/prev
            // println!("from_raw {:?}",self.var);
            let var_guts: TBVar<T> = *Box::from_raw(self.var);
            mem::forget(self); // no double free
            var_guts.value
        }
    }

    /// Temporarily acquires shared access to the guarded value.  It would not be safe to return a
    /// reference as by the standard `Deref` traits, as the lifetime of the capability could be
    /// much longer than the usable life of the referred value.  By only exposing borrowing and
    /// scoping as functions, we force the lifetimes of values and capabilities to be properly
    /// nested with each other in a thread, so a single liveness check at the beginning can
    /// suffice.
    ///
    /// # Panics
    ///
    /// Panics if the capability is not accessible.
    pub fn with<F, R>(&self, fun: F) -> R
        where F: FnOnce(&T) -> R
    {
        self.check_access();
        fun(unsafe { &(*self.var).value })
    }

    /// Temporarily acquires exclusive access to the guarded value.  See safety notes on `with`.
    ///
    /// # Panics
    ///
    /// Panics if the capability is not accessible.
    pub fn with_mut<F, R>(&mut self, fun: F) -> R
        where F: FnOnce(&mut T) -> R
    {
        self.check_access();
        fun(unsafe { &mut (*self.var).value })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::thread;
    use std::mem;
    use std::sync::{Arc, Mutex};

    #[test]
    fn same_thread_id() {
        let id1 = current_thread_id();
        let id2 = current_thread_id();

        assert_eq!(id1, id2);
    }

    #[test]
    fn thread_id_formatting() {
        let strg = format!("{:?}", current_thread_id());
        assert!(strg.starts_with("thread("));
    }

    #[test]
    fn different_thread_id() {
        let id1 = current_thread_id();
        let id2 = thread::spawn(|| current_thread_id()).join().unwrap();

        assert!(id1 != id2);
    }

    #[test]
    fn round_tripping() {
        let y = 42;
        let mut cap = ThreadBound::new(y);

        assert!(cap.accessible());

        cap.with(|r1| assert_eq!(*r1, 42));
        cap.with_mut(|r2| assert_eq!(*r2, 42));
        let r3: i32 = cap.into_inner();
        assert_eq!(r3, 42);
    }

    #[test]
    fn wrong_thread_throws() {
        let mut cap = ThreadBound::new(42);
        let joinh = thread::spawn(move || cap.with_mut(|r| *r = 55));
        let res: Box<&'static str> = joinh.join().err().unwrap().downcast().unwrap();
        assert_eq!(*res, "Attempt to access ThreadBound from incorrect thread")
    }

    #[test]
    fn wrong_thread_inaccessible() {
        let cap = ThreadBound::new(42);
        assert!(!thread::spawn(move || cap.accessible()).join().unwrap());
    }

    struct Trap(Arc<Mutex<bool>>);
    impl Drop for Trap {
        fn drop(&mut self) {
            (*self.0.lock().unwrap()) = true;
        }
    }

    #[test]
    fn inaccessible_after_teardown() {
        let cap = TBList::scope(|list| list.bind(42));
        assert!(!cap.accessible());

        let joinh = thread::spawn(|| {
            let mut cap2 = TBList::scope(|list| list.bind(42));
            cap2.with_mut(|r| *r = 55);
        });
        let error: Box<&'static str> = joinh.join().err().unwrap().downcast().unwrap();

        assert_eq!(*error,
                   "Attempt to access ThreadBound during TLS destruction phase");
    }

    #[test]
    fn sync_drop() {
        let was_dropped = Arc::new(Mutex::new(false));
        let cap = ThreadBound::new(Trap(was_dropped.clone()));
        mem::drop(cap);
        assert!(*was_dropped.lock().unwrap());
    }

    #[test]
    fn async_drop() {
        let was_dropped = Arc::new(Mutex::new(false));
        let was_dropped_2 = was_dropped.clone();
        let early_dropped = Arc::new(Mutex::new(false));
        let early_dropped_2 = early_dropped.clone();
        let thr = thread::spawn(move || {
            let cap = ThreadBound::new(Trap(was_dropped_2.clone()));
            thread::spawn(move || mem::drop(cap)).join().unwrap();
            (*early_dropped_2.lock().unwrap()) = *was_dropped_2.lock().unwrap();
        });
        thr.join().unwrap();
        assert!(!*early_dropped.lock().unwrap());
        assert!(*was_dropped.lock().unwrap());
    }
}
<commit_msg>ThreadId.is_current(), saves two Arc operations over comparing with current_thread_id<commit_after>#![deny(missing_docs)]
//! Module for tracking the current thread, and wrapping non-`Send` objects in
//! guards that perform runtime thread checks.

use std::sync::Arc;
use std::fmt::{self, Debug};
use std::ptr;
use std::mem;
use std::cell::Cell;

/// A permanent identifier for a single thread, which will not be reused.
#[derive(Clone)]
pub struct ThreadId(Arc<()>);

impl PartialEq for ThreadId {
    fn eq(&self, other: &Self) -> bool {
        (&*self.0 as *const ()) == (&*other.0 as *const ())
    }
}
impl Eq for ThreadId {}

impl Debug for ThreadId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "thread({:?})", &*self.0 as *const ())
    }
}

impl ThreadId {
    /// Returns true if this `ThreadId` value represents the calling thread.
    pub fn is_current(&self) -> bool {
        THREAD_NONCE.with(|r| r == self)
    }
}

// consider using https://github.com/rust-lang/rust/pull/29447 after it lands,
// or a u64 atomic where available
// is there a lock-free way to increment a 64-bit counter?
thread_local!(static THREAD_NONCE: ThreadId = ThreadId(Arc::new(())));

/// Returns a persistent identifier for the current thread.
pub fn current_thread_id() -> ThreadId {
    THREAD_NONCE.with(|r| r.clone())
}

struct TBListHead {
    // do not move
    owner: ThreadId,
    head: TBHeader,
    destroying: Cell<bool>,
}

/// A container for values which must be accessed within a particular scope in a particular thread.
/// Values may be added using the `bind_value` method, which returns a capability; the capability
/// may freely move between threads, but can only be used in the thread of the binding.  A bound
/// value will be destroyed when the capability is destroyed if that happens in the allowed thread;
/// otherwise it will be destroyed when the list is.
pub struct TBList {
    list: Arc<TBListHead>,
}

struct TBHeader {
    // do not move
    next: Cell<*const TBHeader>,
    prev: Cell<*const TBHeader>,
    free: unsafe fn(*const TBHeader),
}

struct TBVar<T: 'static> {
    // do not move
    value: T,
    header: TBHeader,
}

/// A handle to a value of type `T` which is owned by a specific thread.  Code running on the same
/// thread can freely manipulate the value; attempts to manipulate the value from other threads
/// will panic at runtime.
///
/// Lifetime is subtle.  Since we do not assume `T` can be safely dropped from any thread other
/// than that where it was created, dropping a `ThreadBound<T>` will only immediately drop the
/// wrapped value in the originating thread.  Drops occuring on other threads will leave the value
/// in a thread-local list associated with the originating thread, and the value will live until
/// the originating thread exits, at which point it will be destroyed. Conversely, if the
/// originating thread exits while there are `ThreadBound<T>` capabilities alive in the heap, all
/// of the underlying values will be dropped (this causes the capabilities to become dangling
/// pointers, but that is OK as the only thread that could dereference them is exiting).
pub struct ThreadBound<T: 'static> {
    list: Arc<TBListHead>,
    var: *mut TBVar<T>,
}

unsafe impl<T: 'static> Send for ThreadBound<T> {}
unsafe impl<T: 'static> Sync for ThreadBound<T> {}

unsafe fn unlink_var(header: *const TBHeader) {
    // precondition: the list is being destroyed or the capability has just been
    // dropped
    // (either way there will be no future attempts to access this header)
    // println!("unlink header {:?}", header);
    let prev = (*header).prev.get();
    let next = (*header).next.get();
    (*next).prev.set(prev);
    (*prev).next.set(next);
}

// unsafe fn list_dumper(why: &'static str, lh: &TBListHead) {
//     let pstart = &lh.head as *const TBHeader;
//     let mut p2 = pstart;
//     println!("list dump {}", why);
//     loop {
// println!("header@{:?}, next={next:?}, prev={prev:?}, free={free:?}",
// p2,
// next = (*p2).next.get(), prev = (*p2).prev.get(), free =
// (*p2).free);
//         p2 = (*p2).next.get();
//         if p2 == pstart { break; }
//     }
// }

unsafe fn destroy_var(header: *const TBHeader) {
    // println!("destroy header {:?}", header);
    unlink_var(header);
    ((*header).free)(header);
}

impl Drop for TBList {
    fn drop(&mut self) {
        self.list.destroying.set(true);
        let headp = &self.list.head as *const TBHeader;

        unsafe {
            // list_dumper("A",&*self.list);
            while (*headp).next.get() != headp {
                destroy_var((*headp).next.get());
            }
        }
    }
}

impl<T: 'static> Drop for ThreadBound<T> {
    fn drop(&mut self) {
        if self.list.owner.is_current() && !self.list.destroying.get() {
            unsafe {
                // list_dumper("B", &*self.list);
                destroy_var(&(*self.var).header);
            }
        }
        // otherwise the var leaks and will be cleaned up when the originating thread
        // exits.  we could provide a scrub() function to call from the originating
        // thread, at the cost of extra synchronization.
    }
}

impl TBList {
    fn new() -> Self {
        unsafe fn unreachable(_head: *const TBHeader) {
            panic!("attempt to free TBList header");
        }
        let lheader = Arc::new(TBListHead {
            owner: current_thread_id(),
            destroying: Cell::new(false),
            head: TBHeader {
                next: Cell::new(ptr::null_mut()),
                prev: Cell::new(ptr::null_mut()),
                free: unreachable,
            },
        });
        let headp = &lheader.head as *const TBHeader;
        // println!("insert header {:?}", headp);
        unsafe {
            (*headp).next.set(headp);
            (*headp).prev.set(headp);
            // list_dumper("C", &*lheader);
        }
        TBList { list: lheader }
    }

    /// Creates a new scope for value bindings.  The lifetime of a scope list is forced to be a
    /// dynamic scope so that it will be properly nested with all `with` and `with_mut` borrows.
    pub fn scope<F, R>(f: F) -> R
        where F: FnOnce(&mut Self) -> R
    {
        f(&mut Self::new())
    }

    /// Transfers ownership of a value into a scope, and returns a capability which can be used to
    /// access that value but only within the same thread and during the same scope.
    pub fn bind<T: 'static>(&self, value: T) -> ThreadBound<T> {
        unsafe fn free<T: 'static>(header: *const TBHeader) {
            let offset = &(*(0 as *const TBVar<T>)).header as *const TBHeader as usize;
            let varp = ((header as usize) - offset) as *mut TBVar<T>;
            // println!("free/box {:?}", varp);
            mem::drop(Box::from_raw(varp));
        }

        let new_var: *mut TBVar<T> = Box::into_raw(Box::new(TBVar {
            header: TBHeader {
                next: Cell::new(ptr::null_mut()),
                prev: Cell::new(ptr::null_mut()),
                free: free::<T>,
            },
            value: value,
        }));

        unsafe {
            let new_head = &(*new_var).header as *const TBHeader;
            let list_head = &self.list.head as *const TBHeader;

            (*new_head).next.set(list_head);
            (*new_head).prev.set((*list_head).prev.get());
            (*(*list_head).prev.get()).next.set(new_head);
            (*list_head).prev.set(new_head);
            // list_dumper("D", &*self.list);
        }

        ThreadBound {
            var: new_var,
            list: self.list.clone(),
        }
    }
}

thread_local!(static THREAD_LIST_KEY: TBList = TBList::new());

impl<T: 'static> ThreadBound<T> {
    /// Wraps a value of type `T` in a capability bound to the current thread.  This uses a
    /// thread-local instance of `TBList` with the lifetime of the calling thread.
    pub fn new(inner: T) -> Self {
        THREAD_LIST_KEY.with(|tl| tl.bind(inner))
    }

    /// Returns true if this capability can be used without panicking.  This will remain true on
    /// the same thread as long as the thread does not enter the TLS destruction phase.
    pub fn accessible(&self) -> bool {
        return self.list.owner.is_current() && !self.list.destroying.get();
    }

    fn check_access(&self) {
        if !self.list.owner.is_current() {
            panic!("Attempt to access ThreadBound from incorrect thread");
        }

        if self.list.destroying.get() {
            panic!("Attempt to access ThreadBound during TLS destruction phase");
        }
    }

    /// Consumes this capability to regain ownership of the underlying value.
    ///
    /// # Panics
    ///
    /// Panics if the capability is not accessible.
    pub fn into_inner(self) -> T {
        self.check_access();
        unsafe {
            unlink_var(&(*self.var).header as *const TBHeader);
            // yes, this is a move, so it invalidates the next/prev
            // println!("from_raw {:?}",self.var);
            let var_guts: TBVar<T> = *Box::from_raw(self.var);
            mem::forget(self); // no double free
            var_guts.value
        }
    }

    /// Temporarily acquires shared access to the guarded value.  It would not be safe to return a
    /// reference as by the standard `Deref` traits, as the lifetime of the capability could be
    /// much longer than the usable life of the referred value.  By only exposing borrowing and
    /// scoping as functions, we force the lifetimes of values and capabilities to be properly
    /// nested with each other in a thread, so a single liveness check at the beginning can
    /// suffice.
    ///
    /// # Panics
    ///
    /// Panics if the capability is not accessible.
    pub fn with<F, R>(&self, fun: F) -> R
        where F: FnOnce(&T) -> R
    {
        self.check_access();
        fun(unsafe { &(*self.var).value })
    }

    /// Temporarily acquires exclusive access to the guarded value.  See safety notes on `with`.
    ///
    /// # Panics
    ///
    /// Panics if the capability is not accessible.
    pub fn with_mut<F, R>(&mut self, fun: F) -> R
        where F: FnOnce(&mut T) -> R
    {
        self.check_access();
        fun(unsafe { &mut (*self.var).value })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::thread;
    use std::mem;
    use std::sync::{Arc, Mutex};

    #[test]
    fn same_thread_id() {
        let id1 = current_thread_id();
        let id2 = current_thread_id();

        assert_eq!(id1, id2);
        assert!(id1.is_current());
    }

    #[test]
    fn thread_id_formatting() {
        let strg = format!("{:?}", current_thread_id());
        assert!(strg.starts_with("thread("));
    }

    #[test]
    fn different_thread_id() {
        let id1 = current_thread_id();
        let id2 = thread::spawn(|| current_thread_id()).join().unwrap();

        assert!(id1 != id2);
        assert!(!id2.is_current());
    }

    #[test]
    fn round_tripping() {
        let y = 42;
        let mut cap = ThreadBound::new(y);

        assert!(cap.accessible());

        cap.with(|r1| assert_eq!(*r1, 42));
        cap.with_mut(|r2| assert_eq!(*r2, 42));
        let r3: i32 = cap.into_inner();
        assert_eq!(r3, 42);
    }

    #[test]
    fn wrong_thread_throws() {
        let mut cap = ThreadBound::new(42);
        let joinh = thread::spawn(move || cap.with_mut(|r| *r = 55));
        let res: Box<&'static str> = joinh.join().err().unwrap().downcast().unwrap();
        assert_eq!(*res, "Attempt to access ThreadBound from incorrect thread")
    }

    #[test]
    fn wrong_thread_inaccessible() {
        let cap = ThreadBound::new(42);
        assert!(!thread::spawn(move || cap.accessible()).join().unwrap());
    }

    struct Trap(Arc<Mutex<bool>>);
    impl Drop for Trap {
        fn drop(&mut self) {
            (*self.0.lock().unwrap()) = true;
        }
    }

    #[test]
    fn inaccessible_after_teardown() {
        let cap = TBList::scope(|list| list.bind(42));
        assert!(!cap.accessible());

        let joinh = thread::spawn(|| {
            let mut cap2 = TBList::scope(|list| list.bind(42));
            cap2.with_mut(|r| *r = 55);
        });
        let error: Box<&'static str> = joinh.join().err().unwrap().downcast().unwrap();

        assert_eq!(*error,
                   "Attempt to access ThreadBound during TLS destruction phase");
    }

    #[test]
    fn sync_drop() {
        let was_dropped = Arc::new(Mutex::new(false));
        let cap = ThreadBound::new(Trap(was_dropped.clone()));
        mem::drop(cap);
        assert!(*was_dropped.lock().unwrap());
    }

    #[test]
    fn async_drop() {
        let was_dropped = Arc::new(Mutex::new(false));
        let was_dropped_2 = was_dropped.clone();
        let early_dropped = Arc::new(Mutex::new(false));
        let early_dropped_2 = early_dropped.clone();
        let thr = thread::spawn(move || {
            let cap = ThreadBound::new(Trap(was_dropped_2.clone()));
            thread::spawn(move || mem::drop(cap)).join().unwrap();
            (*early_dropped_2.lock().unwrap()) = *was_dropped_2.lock().unwrap();
        });
        thr.join().unwrap();
        assert!(!*early_dropped.lock().unwrap());
        assert!(*was_dropped.lock().unwrap());
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

extern crate chrono;
extern crate futures;
extern crate gtk;
extern crate relm_core;
extern crate tokio_timer;

use std::rc::Rc;
use std::time::Duration;

use chrono::Local;
use futures::Stream;
use gtk::{Button, ButtonExt, ContainerExt, Inhibit, Label, WidgetExt, Window, WindowType};
use gtk::Orientation::Vertical;
use relm_core::{Core, EventStream};
use tokio_timer::Timer;

use self::Msg::*;

struct Widgets {
    clock_label: Label,
    counter_label: Label,
}

#[derive(Clone)]
enum Msg {
    Clock,
    Decrement,
    Increment,
    Quit,
}

fn main() {
    gtk::init().unwrap();

    let vbox = gtk::Box::new(Vertical, 0);

    let clock_label = Label::new(None);
    vbox.add(&clock_label);

    let plus_button = Button::new_with_label("+");
    vbox.add(&plus_button);

    let counter_label = Label::new(Some("0"));
    vbox.add(&counter_label);

    let widgets = Rc::new(Widgets {
        clock_label: clock_label,
        counter_label: counter_label,
    });

    let mut core = Core::new(widgets).unwrap();

    let window = Window::new(WindowType::Toplevel);
    window.add(&vbox);

    {
        let stream = core.stream().clone();
        plus_button.connect_clicked(move |_| {
            stream.emit(Increment);
        });
    }

    let minus_button = Button::new_with_label("-");
    vbox.add(&minus_button);
    {
        let stream = core.stream().clone();
        minus_button.connect_clicked(move |_| {
            stream.emit(Decrement);
        });
    }

    window.show_all();

    {
        let stream = core.stream().clone();
        window.connect_delete_event(move |_, _| {
            stream.emit(Quit);
            Inhibit(false)
        });
    }

    let timer = Timer::default();
    let interval = {
        let interval = timer.interval(Duration::from_millis(1000));
        let stream = core.stream().clone();
        interval.map_err(|_| ()).for_each(move |_| {
            stream.emit(Clock);
            Ok(())
        })
    };

    let event_future = {
        let stream: EventStream<Msg, Rc<Widgets>> = core.stream().clone();
        let quit_future = core.quit_future().clone();
        stream.for_each(move |(event, widgets)| {
            fn adjust(label: &Label, delta: i32) {
                if let Some(text) = label.get_text() {
                    let num: i32 = text.parse().unwrap();
                    let result = num + delta;
                    label.set_text(&result.to_string());
                }
            }

            match event {
                Clock => {
                    let now = Local::now();
                    widgets.clock_label.set_text(&now.format("%H:%M:%S").to_string());
                },
                Decrement => adjust(&widgets.counter_label, -1),
                Increment => adjust(&widgets.counter_label, 1),
                Quit => quit_future.quit(),
            }
            Ok(())
        })
    };

    let handle = core.handle();
    handle.spawn(event_future);
    handle.spawn(interval);

    core.run();
}
<commit_msg>Fixed relm-core example.<commit_after>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

extern crate chrono;
extern crate futures;
extern crate gtk;
extern crate relm_core;
extern crate tokio_timer;

use std::time::Duration;

use chrono::Local;
use futures::Stream;
use gtk::{Button, ButtonExt, ContainerExt, Inhibit, Label, WidgetExt, Window, WindowType};
use gtk::Orientation::Vertical;
use relm_core::{Core, EventStream};
use tokio_timer::Timer;

use self::Msg::*;

struct Widgets {
    clock_label: Label,
    counter_label: Label,
}

#[derive(Clone)]
enum Msg {
    Clock,
    Decrement,
    Increment,
    Quit,
}

fn main() {
    gtk::init().unwrap();

    let vbox = gtk::Box::new(Vertical, 0);

    let clock_label = Label::new(None);
    vbox.add(&clock_label);

    let plus_button = Button::new_with_label("+");
    vbox.add(&plus_button);

    let counter_label = Label::new(Some("0"));
    vbox.add(&counter_label);

    let widgets = Widgets {
        clock_label: clock_label,
        counter_label: counter_label,
    };

    let mut core = Core::new().unwrap();

    let window = Window::new(WindowType::Toplevel);
    window.add(&vbox);

    {
        let stream = core.stream().clone();
        plus_button.connect_clicked(move |_| {
            stream.emit(Increment);
        });
    }

    let minus_button = Button::new_with_label("-");
    vbox.add(&minus_button);
    {
        let stream = core.stream().clone();
        minus_button.connect_clicked(move |_| {
            stream.emit(Decrement);
        });
    }

    window.show_all();

    {
        let stream = core.stream().clone();
        window.connect_delete_event(move |_, _| {
            stream.emit(Quit);
            Inhibit(false)
        });
    }

    let timer = Timer::default();
    let interval = {
        let interval = timer.interval(Duration::from_millis(1000));
        let stream = core.stream().clone();
        interval.map_err(|_| ()).for_each(move |_| {
            stream.emit(Clock);
            Ok(())
        })
    };

    let event_future = {
        let stream: EventStream<Msg> = core.stream().clone();
        let quit_future = core.quit_future().clone();
        stream.for_each(move |event| {
            fn adjust(label: &Label, delta: i32) {
                if let Some(text) = label.get_text() {
                    let num: i32 = text.parse().unwrap();
                    let result = num + delta;
                    label.set_text(&result.to_string());
                }
            }

            match event {
                Clock => {
                    let now = Local::now();
                    widgets.clock_label.set_text(&now.format("%H:%M:%S").to_string());
                },
                Decrement => adjust(&widgets.counter_label, -1),
                Increment => adjust(&widgets.counter_label, 1),
                Quit => quit_future.quit(),
            }
            Ok(())
        })
    };

    let handle = core.handle();
    handle.spawn(event_future);
    handle.spawn(interval);

    core.run();
}
<|endoftext|>


<commit_before>use std::io;
use std::mem;

use bytes::{BufMut, Bytes, BytesMut};
use nom::{self, Needed};
use tokio_util::codec::{Decoder, Encoder};

use imap_proto::types::{Request, RequestId, Response};

#[derive(Default)]
pub struct ImapCodec {
    decode_need_message_bytes: usize,
}

impl<'a> Decoder for ImapCodec {
    type Item = ResponseData;
    type Error = io::Error;
    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, io::Error> {
        if self.decode_need_message_bytes > buf.len() {
            return Ok(None);
        }
        let (response, rsp_len) = match imap_proto::Response::from_bytes(buf) {
            Ok((remaining, response)) => {
                // This SHOULD be acceptable/safe: BytesMut storage memory is
                // allocated on the heap and should not move. It will not be
                // freed as long as we keep a reference alive, which we do
                // by retaining a reference to the split buffer, below.
                let response = unsafe { mem::transmute(response) };
                (response, buf.len() - remaining.len())
            }
            Err(nom::Err::Incomplete(Needed::Size(min))) => {
                self.decode_need_message_bytes = min.get();
                return Ok(None);
            }
            Err(nom::Err::Incomplete(_)) => {
                return Ok(None);
            }
            Err(nom::Err::Error(nom::error::Error { code, .. }))
            | Err(nom::Err::Failure(nom::error::Error { code, .. })) => {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("{:?} during parsing of {:?}", code, buf),
                ));
            }
        };
        let raw = buf.split_to(rsp_len).freeze();
        self.decode_need_message_bytes = 0;
        Ok(Some(ResponseData { raw, response }))
    }
}

impl<'a> Encoder<&'a Request<'a>> for ImapCodec {
    type Error = io::Error;
    fn encode(&mut self, msg: &Request, dst: &mut BytesMut) -> Result<(), io::Error> {
        dst.put(&*msg.0);
        dst.put_u8(b' ');
        dst.put_slice(&*msg.1);
        dst.put_slice(b"\r\n");
        Ok(())
    }
}

#[derive(Debug)]
pub struct ResponseData {
    raw: Bytes,
    // This reference is really scoped to the lifetime of the `raw`
    // member, but unfortunately Rust does not allow that yet. It
    // is transmuted to `'static` by the `Decoder`, instead, and
    // references returned to callers of `ResponseData` are limited
    // to the lifetime of the `ResponseData` struct.
    //
    // `raw` is never mutated during the lifetime of `ResponseData`,
    // and `Response` does not not implement any specific drop glue.
    response: Response<'static>,
}

impl ResponseData {
    pub fn request_id(&self) -> Option<&RequestId> {
        match self.response {
            Response::Done { ref tag, .. } => Some(tag),
            _ => None,
        }
    }

    #[allow(clippy::needless_lifetimes)]
    pub fn parsed<'a>(&'a self) -> &'a Response<'a> {
        &self.response
    }
}
<commit_msg>Silence warning about unused code<commit_after>use std::io;
use std::mem;

use bytes::{BufMut, Bytes, BytesMut};
use nom::{self, Needed};
use tokio_util::codec::{Decoder, Encoder};

use imap_proto::types::{Request, RequestId, Response};

#[derive(Default)]
pub struct ImapCodec {
    decode_need_message_bytes: usize,
}

impl<'a> Decoder for ImapCodec {
    type Item = ResponseData;
    type Error = io::Error;
    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, io::Error> {
        if self.decode_need_message_bytes > buf.len() {
            return Ok(None);
        }
        let (response, rsp_len) = match imap_proto::Response::from_bytes(buf) {
            Ok((remaining, response)) => {
                // This SHOULD be acceptable/safe: BytesMut storage memory is
                // allocated on the heap and should not move. It will not be
                // freed as long as we keep a reference alive, which we do
                // by retaining a reference to the split buffer, below.
                let response = unsafe { mem::transmute(response) };
                (response, buf.len() - remaining.len())
            }
            Err(nom::Err::Incomplete(Needed::Size(min))) => {
                self.decode_need_message_bytes = min.get();
                return Ok(None);
            }
            Err(nom::Err::Incomplete(_)) => {
                return Ok(None);
            }
            Err(nom::Err::Error(nom::error::Error { code, .. }))
            | Err(nom::Err::Failure(nom::error::Error { code, .. })) => {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("{:?} during parsing of {:?}", code, buf),
                ));
            }
        };
        let raw = buf.split_to(rsp_len).freeze();
        self.decode_need_message_bytes = 0;
        Ok(Some(ResponseData { raw, response }))
    }
}

impl<'a> Encoder<&'a Request<'a>> for ImapCodec {
    type Error = io::Error;
    fn encode(&mut self, msg: &Request, dst: &mut BytesMut) -> Result<(), io::Error> {
        dst.put(&*msg.0);
        dst.put_u8(b' ');
        dst.put_slice(&*msg.1);
        dst.put_slice(b"\r\n");
        Ok(())
    }
}

#[derive(Debug)]
pub struct ResponseData {
    #[allow(dead_code)] // Contains data that `response` borrows
    raw: Bytes,
    // This reference is really scoped to the lifetime of the `raw`
    // member, but unfortunately Rust does not allow that yet. It
    // is transmuted to `'static` by the `Decoder`, instead, and
    // references returned to callers of `ResponseData` are limited
    // to the lifetime of the `ResponseData` struct.
    //
    // `raw` is never mutated during the lifetime of `ResponseData`,
    // and `Response` does not not implement any specific drop glue.
    response: Response<'static>,
}

impl ResponseData {
    pub fn request_id(&self) -> Option<&RequestId> {
        match self.response {
            Response::Done { ref tag, .. } => Some(tag),
            _ => None,
        }
    }

    #[allow(clippy::needless_lifetimes)]
    pub fn parsed<'a>(&'a self) -> &'a Response<'a> {
        &self.response
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, edef <edef@edef.eu>
// See the LICENSE file included in this distribution.
extern crate std;
use core::prelude::*;
use self::std::io::Error as IoError;
use stack;
mod sys;

pub struct StackSource;

unsafe impl Send for StackSource {}
unsafe impl Sync for StackSource {}

#[allow(raw_pointer_derive)]
#[derive(Debug)]
pub struct Stack {
  ptr: *mut u8,
  len: usize
}

unsafe impl Send for Stack {}

impl stack::StackSource for StackSource {
  type Output = Stack;
  type Error = IoError;

  fn get_stack(size: usize) -> Result<Stack, IoError> {
    let page_size = sys::page_size();

    // round the page size up,
    // using the fact that it is a power of two
    let len = (size + page_size - 1) & !(page_size - 1);

    let stack = unsafe {
      let ptr = try!(match sys::map_stack(size) {
        None => Err(IoError::last_os_error()),
        Some(ptr) => Ok(ptr)
      });

      Stack { ptr: ptr as *mut u8, len: len }
    };

    try!(unsafe {
      if sys::protect_stack(stack.ptr) { Ok(()) }
      else { Err(IoError::last_os_error()) }
    });

    Ok(stack)
  }
}

impl stack::Stack for Stack {
  fn top(&mut self) -> *mut u8 {
    unsafe {
      self.ptr.offset(self.len as isize)
    }
  }

  fn limit(&self) -> *const u8 {
    unsafe {
      self.ptr.offset(sys::page_size() as isize)
    }
  }
}

impl Drop for Stack {
  fn drop(&mut self) {
    unsafe {
      if !sys::unmap_stack(self.ptr, self.len) {
        panic!("munmap for stack {:p} of size {} failed: {}",
               self.ptr, self.len, IoError::last_os_error())
      }
    }
  }
}
<commit_msg>document os<commit_after>// Copyright (c) 2015, edef <edef@edef.eu>
// See the LICENSE file included in this distribution.
//! This module provides stacks using the operating system's
//! anonymous memory mapping facility, usually `mmap`.
//! The stacks it provides come with a guard page, which is not included
//! in the stack limit.

extern crate std;
use core::prelude::*;
use self::std::io::Error as IoError;
use stack;
mod sys;

pub struct StackSource;

unsafe impl Send for StackSource {}
unsafe impl Sync for StackSource {}

#[allow(raw_pointer_derive)]
#[derive(Debug)]
pub struct Stack {
  ptr: *mut u8,
  len: usize
}

unsafe impl Send for Stack {}

impl stack::StackSource for StackSource {
  type Output = Stack;
  type Error = IoError;

  fn get_stack(size: usize) -> Result<Stack, IoError> {
    let page_size = sys::page_size();

    // round the page size up,
    // using the fact that it is a power of two
    let len = (size + page_size - 1) & !(page_size - 1);

    let stack = unsafe {
      let ptr = try!(match sys::map_stack(size) {
        None => Err(IoError::last_os_error()),
        Some(ptr) => Ok(ptr)
      });

      Stack { ptr: ptr as *mut u8, len: len }
    };

    try!(unsafe {
      if sys::protect_stack(stack.ptr) { Ok(()) }
      else { Err(IoError::last_os_error()) }
    });

    Ok(stack)
  }
}

impl stack::Stack for Stack {
  fn top(&mut self) -> *mut u8 {
    unsafe {
      self.ptr.offset(self.len as isize)
    }
  }

  fn limit(&self) -> *const u8 {
    unsafe {
      self.ptr.offset(sys::page_size() as isize)
    }
  }
}

impl Drop for Stack {
  fn drop(&mut self) {
    unsafe {
      if !sys::unmap_stack(self.ptr, self.len) {
        panic!("munmap for stack {:p} of size {} failed: {}",
               self.ptr, self.len, IoError::last_os_error())
      }
    }
  }
}
<|endoftext|>


<commit_before>use std::thread;
use std::thread::JoinHandle;
use std::path::Path;
use std::time::Duration;

use websocket::{WebSocketStream, Server};
use websocket::Message as WebMessage;
use websocket::Sender as WebSender;
use websocket::client::Sender as WebClientSender;
use websocket::Receiver as WebReceiver;
use websocket::message::Type as WebMessageType;
use websocket::server::Connection;
use websocket::header::WebSocketProtocol;

use git2::Repository;
use git2::ObjectType;

use payload;
use State;

extern crate fsevent;
use self::fsevent::Event as FsEvent;
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;

use serde_xml as xml;
use yaml_rust::yaml::Hash;
use yaml_rust::{Yaml, YamlEmitter};

#[derive(Debug)]
enum NotifierMessage<'a> {
    WebMessage(WebMessage<'a>),
    FsEvent(FsEvent)
}

pub fn start() {
    let server = Server::bind("127.0.0.1:2794").unwrap();
    thread::spawn(move || {
        for connection in server {
            thread::spawn(move || connect(connection.unwrap()));
        }
    });
}

fn connect(connection: Connection<WebSocketStream, WebSocketStream>) {
    let request = connection.read_request().unwrap();
    let headers = request.headers.clone();
    request.validate().unwrap();
    let mut response = request.accept();
    println!("Connected");

    if let Some(&WebSocketProtocol(ref protocols)) = headers.get() {
        if protocols.contains(&("rust-websocket".to_string())) {
            response.headers.set(WebSocketProtocol(vec!["superconductor".to_string()]));
        }
    }

    let mut client = response.send().unwrap();
    let message = WebMessage::text(payload::generate(None));
    client.send_message(&message).unwrap();

    let (tx, rx) = channel::<NotifierMessage>();
    let (mut sender, mut receiver) = client.split();
    let notifier = thread::spawn(move || start_notifier(rx, sender));
    let txc = tx.clone();
    let monitor = thread::spawn(move || start_monitor(txc));
    for message in receiver.incoming_messages() {
        let message: WebMessage = message.unwrap_or(WebMessage::close());
        match message.opcode {
            WebMessageType::Close => {
                tx.send(NotifierMessage::WebMessage(message));
                break;
            },
            _ => tx.send(NotifierMessage::WebMessage(message))
        };
    }
    monitor.join();
    notifier.join();
}

fn start_monitor(tx: Sender<NotifierMessage>) {
    let (ftx, rx) = channel();
    let observer = thread::spawn(move || {
        println!("Monitoring");
        let fsevent = fsevent::FsEvent::new(ftx);
        fsevent.append_path(".");
        fsevent.observe();
    });
    loop {
        let event = rx.recv().unwrap();
        thread::sleep(Duration::from_millis(500));
        let mut aggregator = vec![];
        while let Ok(agg_event) = rx.try_recv() {
            aggregator.push(agg_event);
        }
        tx.send(NotifierMessage::FsEvent(event));
    }
    observer.join();
}

fn start_notifier(rx: Receiver<NotifierMessage>, mut sender: WebClientSender<WebSocketStream>) {
    let mut last_state: Option<State> = None;
    loop {
        let value = rx.recv().unwrap();
        match value {
            NotifierMessage::WebMessage(message) => {
                match message.opcode {
                    WebMessageType::Close => {
                        break;
                    },
                    WebMessageType::Ping => {
                        let message = WebMessage::pong(message.payload);
                        sender.send_message(&message).unwrap();
                    },
                    _ => {
                        let payload = String::from_utf8_lossy(message.payload.as_ref());
                        println!("{}", payload);
                        let state: State = xml::from_str(&payload).unwrap();
                        println!("{:?}", state);

                        let repo = Repository::discover(".").unwrap();
                        let head = repo.head().unwrap().peel(ObjectType::Commit).unwrap();
                        let mut index = repo.index().unwrap();

                        let to_remove = index.iter().fold(vec![], |mut acc, entry| {
                            let entry_path = String::from_utf8_lossy(entry.path.as_ref());
                            match state.include.iter().find(|i| i.as_ref() == entry_path) {
                                None => acc.push(entry_path.into_owned()),
                                _ => {}
                            };
                            acc
                        });

                        repo.reset_default(Some(&head), to_remove.iter()).unwrap();
                        for change in state.clone().include {
                            let path = Path::new(&change);
                            index.add_path(path).unwrap();
                        }
                        index.write().unwrap();

                        if let Some(event) = state.save_update.clone() {
                            let author = repo.signature().unwrap();
                            let mut yaml = String::new();
                            {
                                // Constructing the properties YAML
                                let mut tasks = Hash::new();
                                let mut properties = Hash::new();
                                let mut emitter = YamlEmitter::new(&mut yaml);
                                for property in state.property {
                                    properties.insert(Yaml::String(property.name), Yaml::String(property.value));
                                }
                                tasks.insert(Yaml::String(String::from("BLBA-1234")), Yaml::Hash(properties));
                                emitter.dump(&Yaml::Hash(tasks)).unwrap();
                            }
                            let message = state.message + "\n" + &yaml;

                            index.read(false);
                            let tree_oid = index.write_tree().unwrap();
                            let tree = repo.find_tree(tree_oid).unwrap();
                            repo.commit(Some("HEAD"), &author, &author, &message, &tree, &[&head.as_commit().unwrap()]);
                            let message = WebMessage::text(payload::generate(None));
                            sender.send_message(&message).unwrap();
                            last_state = None;
                        } else {
                            last_state = Some(state);
                        }
                        let message = WebMessage::text(payload::generate(last_state.clone()));
                        sender.send_message(&message).unwrap();
                    }
                }
            },
            NotifierMessage::FsEvent(event) => {
                let repo = Repository::discover(".").unwrap();
                let message = WebMessage::text(payload::generate(last_state.clone()));
                sender.send_message(&message).unwrap();
            }
        }
    }
}
<commit_msg>Aggregator should send the last-most event received to the notifier.<commit_after>use std::thread;
use std::thread::JoinHandle;
use std::path::Path;
use std::time::Duration;

use websocket::{WebSocketStream, Server};
use websocket::Message as WebMessage;
use websocket::Sender as WebSender;
use websocket::client::Sender as WebClientSender;
use websocket::Receiver as WebReceiver;
use websocket::message::Type as WebMessageType;
use websocket::server::Connection;
use websocket::header::WebSocketProtocol;

use git2::Repository;
use git2::ObjectType;

use payload;
use State;

extern crate fsevent;
use self::fsevent::Event as FsEvent;
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;

use serde_xml as xml;
use yaml_rust::yaml::Hash;
use yaml_rust::{Yaml, YamlEmitter};

#[derive(Debug)]
enum NotifierMessage<'a> {
    WebMessage(WebMessage<'a>),
    FsEvent(FsEvent)
}

pub fn start() {
    let server = Server::bind("127.0.0.1:2794").unwrap();
    thread::spawn(move || {
        for connection in server {
            thread::spawn(move || connect(connection.unwrap()));
        }
    });
}

fn connect(connection: Connection<WebSocketStream, WebSocketStream>) {
    let request = connection.read_request().unwrap();
    let headers = request.headers.clone();
    request.validate().unwrap();
    let mut response = request.accept();
    println!("Connected");

    if let Some(&WebSocketProtocol(ref protocols)) = headers.get() {
        if protocols.contains(&("rust-websocket".to_string())) {
            response.headers.set(WebSocketProtocol(vec!["superconductor".to_string()]));
        }
    }

    let mut client = response.send().unwrap();
    let message = WebMessage::text(payload::generate(None));
    client.send_message(&message).unwrap();

    let (tx, rx) = channel::<NotifierMessage>();
    let (mut sender, mut receiver) = client.split();
    let notifier = thread::spawn(move || start_notifier(rx, sender));
    let txc = tx.clone();
    let monitor = thread::spawn(move || start_monitor(txc));
    for message in receiver.incoming_messages() {
        let message: WebMessage = message.unwrap_or(WebMessage::close());
        match message.opcode {
            WebMessageType::Close => {
                tx.send(NotifierMessage::WebMessage(message));
                break;
            },
            _ => tx.send(NotifierMessage::WebMessage(message))
        };
    }
    monitor.join();
    notifier.join();
}

fn start_monitor(tx: Sender<NotifierMessage>) {
    let (ftx, rx) = channel();
    let observer = thread::spawn(move || {
        println!("Monitoring");
        let fsevent = fsevent::FsEvent::new(ftx);
        fsevent.append_path(".");
        fsevent.observe();
    });
    loop {
        let event = rx.recv().unwrap();
        thread::sleep(Duration::from_millis(500));
        let mut events = vec![];
        events.push(event);
        while let Ok(aggregator) = rx.try_recv() {
            events.push(aggregator);
        }
        tx.send(NotifierMessage::FsEvent(events.pop().unwrap()));
    }
    observer.join();
}

fn start_notifier(rx: Receiver<NotifierMessage>, mut sender: WebClientSender<WebSocketStream>) {
    let mut last_state: Option<State> = None;
    loop {
        let value = rx.recv().unwrap();
        match value {
            NotifierMessage::WebMessage(message) => {
                match message.opcode {
                    WebMessageType::Close => {
                        break;
                    },
                    WebMessageType::Ping => {
                        let message = WebMessage::pong(message.payload);
                        sender.send_message(&message).unwrap();
                    },
                    _ => {
                        let payload = String::from_utf8_lossy(message.payload.as_ref());
                        println!("{}", payload);
                        let state: State = xml::from_str(&payload).unwrap();
                        println!("{:?}", state);

                        let repo = Repository::discover(".").unwrap();
                        let head = repo.head().unwrap().peel(ObjectType::Commit).unwrap();
                        let mut index = repo.index().unwrap();

                        let to_remove = index.iter().fold(vec![], |mut acc, entry| {
                            let entry_path = String::from_utf8_lossy(entry.path.as_ref());
                            match state.include.iter().find(|i| i.as_ref() == entry_path) {
                                None => acc.push(entry_path.into_owned()),
                                _ => {}
                            };
                            acc
                        });

                        repo.reset_default(Some(&head), to_remove.iter()).unwrap();
                        for change in state.clone().include {
                            let path = Path::new(&change);
                            index.add_path(path).unwrap();
                        }
                        index.write().unwrap();

                        if let Some(event) = state.save_update.clone() {
                            let author = repo.signature().unwrap();
                            let mut yaml = String::new();
                            {
                                // Constructing the properties YAML
                                let mut tasks = Hash::new();
                                let mut properties = Hash::new();
                                let mut emitter = YamlEmitter::new(&mut yaml);
                                for property in state.property {
                                    properties.insert(Yaml::String(property.name), Yaml::String(property.value));
                                }
                                tasks.insert(Yaml::String(String::from("BLBA-1234")), Yaml::Hash(properties));
                                emitter.dump(&Yaml::Hash(tasks)).unwrap();
                            }
                            let message = state.message + "\n" + &yaml;

                            index.read(false);
                            let tree_oid = index.write_tree().unwrap();
                            let tree = repo.find_tree(tree_oid).unwrap();
                            repo.commit(Some("HEAD"), &author, &author, &message, &tree, &[&head.as_commit().unwrap()]);
                            let message = WebMessage::text(payload::generate(None));
                            sender.send_message(&message).unwrap();
                            last_state = None;
                        } else {
                            last_state = Some(state);
                        }
                        let message = WebMessage::text(payload::generate(last_state.clone()));
                        sender.send_message(&message).unwrap();
                    }
                }
            },
            NotifierMessage::FsEvent(event) => {
                let repo = Repository::discover(".").unwrap();
                let message = WebMessage::text(payload::generate(last_state.clone()));
                sender.send_message(&message).unwrap();
            }
        }
    }
}
<|endoftext|>