<commit_before>//! Free functions to create `&[T]` and `&mut [T]`.

use crate::array;
use crate::ptr;

/// Forms a slice from a pointer and a length.
///
/// The `len` argument is the number of **elements**, not the number of bytes.
///
/// # Safety
///
/// Behavior is undefined if any of the following conditions are violated:
///
/// * `data` must be [valid] for reads for `len * mem::size_of::<T>()` many bytes,
///   and it must be properly aligned. This means in particular:
///
///     * The entire memory range of this slice must be contained within a single allocated object!
///       Slices can never span across multiple allocated objects. See [below](#incorrect-usage)
///       for an example incorrectly not taking this into account.
///     * `data` must be non-null and aligned even for zero-length slices. One
///       reason for this is that enum layout optimizations may rely on references
///       (including slices of any length) being aligned and non-null to distinguish
///       them from other data. You can obtain a pointer that is usable as `data`
///       for zero-length slices using [`NonNull::dangling()`].
///
/// * `data` must point to `len` consecutive properly initialized values of type `T`.
///
/// * The memory referenced by the returned slice must not be mutated for the duration
///   of lifetime `'a`, except inside an `UnsafeCell`.
///
/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
///   See the safety documentation of [`pointer::offset`].
///
/// # Caveat
///
/// The lifetime for the returned slice is inferred from its usage. To
/// prevent accidental misuse, it's suggested to tie the lifetime to whichever
/// source lifetime is safe in the context, such as by providing a helper
/// function taking the lifetime of a host value for the slice, or by explicit
/// annotation.
///
/// # Examples
///
/// ```
/// use std::slice;
///
/// // manifest a slice for a single element
/// let x = 42;
/// let ptr = &x as *const _;
/// let slice = unsafe { slice::from_raw_parts(ptr, 1) };
/// assert_eq!(slice[0], 42);
/// ```
///
/// ### Incorrect usage
///
/// The following `join_slices` function is **unsound** ⚠
///
/// ```rust,no_run
/// use std::slice;
///
/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] {
///     let fst_end = fst.as_ptr().wrapping_add(fst.len());
///     let snd_start = snd.as_ptr();
///     assert_eq!(fst_end, snd_start, "Slices must be contiguous!");
///     unsafe {
///         // The assertion above ensures `fst` and `snd` are contiguous, but they might
///         // still be contained within _different allocated objects_, in which case
///         // creating this slice is undefined behavior.
///         slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len())
///     }
/// }
///
/// fn main() {
///     // `a` and `b` are different allocated objects...
///     let a = 42;
///     let b = 27;
///     // ... which may nevertheless be laid out contiguously in memory: | a | b |
///     let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB
/// }
/// ```
///
/// [valid]: ptr#safety
/// [`NonNull::dangling()`]: ptr::NonNull::dangling
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "none")]
pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
    debug_check_data_len(data, len);

    // SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
    unsafe { &*ptr::slice_from_raw_parts(data, len) }
}

/// Performs the same functionality as [`from_raw_parts`], except that a
/// mutable slice is returned.
///
/// # Safety
///
/// Behavior is undefined if any of the following conditions are violated:
///
/// * `data` must be [valid] for both reads and writes for `len * mem::size_of::<T>()` many bytes,
///   and it must be properly aligned. This means in particular:
///
///     * The entire memory range of this slice must be contained within a single allocated object!
///       Slices can never span across multiple allocated objects.
///     * `data` must be non-null and aligned even for zero-length slices. One
///       reason for this is that enum layout optimizations may rely on references
///       (including slices of any length) being aligned and non-null to distinguish
///       them from other data. You can obtain a pointer that is usable as `data`
///       for zero-length slices using [`NonNull::dangling()`].
///
/// * `data` must point to `len` consecutive properly initialized values of type `T`.
///
/// * The memory referenced by the returned slice must not be accessed through any other pointer
///   (not derived from the return value) for the duration of lifetime `'a`.
///   Both read and write accesses are forbidden.
///
/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
///   See the safety documentation of [`pointer::offset`].
///
/// [valid]: ptr#safety
/// [`NonNull::dangling()`]: ptr::NonNull::dangling
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "none")]
pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
    debug_check_data_len(data as _, len);

    // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
    unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) }
}

// In debug builds checks that `data` pointer is aligned and non-null and that slice with given `len` would cover less than half the address space
#[cfg(all(not(bootstrap), debug_assertions))]
#[unstable(feature = "const_slice_from_raw_parts", issue = "none")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "none")]
const fn debug_check_data_len<T>(data: *const T, len: usize) {
    fn rt_check<T>(data: *const T) {
        use crate::intrinsics::is_aligned_and_not_null;

        assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
    }

    const fn ctfe_check<T>(_data: *const T) {
        // It's impossible to check alignment in const fn.
        //
        // CTFE engine checks that the pointer is aligned and not null.
    }

    // SAFETY:
    // - `calling from_raw_parts[_mut]` with arguments that fail to fulfil checks made here is UB, so unless UB is already triggered this is noop
    // - CTFE makes the same checks as `rt_check`, so behavior change is not observable due to compilation error
    unsafe {
        crate::intrinsics::const_eval_select((data,), ctfe_check, rt_check);
    }

    assert!(
        crate::mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
        "attempt to create slice covering at least half the address space"
    );
}

#[cfg(not(all(not(bootstrap), debug_assertions)))]
const fn debug_check_data_len<T>(_data: *const T, _len: usize) {}

/// Converts a reference to T into a slice of length 1 (without copying).
#[stable(feature = "from_ref", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
pub const fn from_ref<T>(s: &T) -> &[T] {
    array::from_ref(s)
}

/// Converts a reference to T into a slice of length 1 (without copying).
#[stable(feature = "from_ref", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
pub const fn from_mut<T>(s: &mut T) -> &mut [T] {
    array::from_mut(s)
}
<commit_msg>Use proper issue number for `feature(const_slice_from_raw_parts)`<commit_after>//! Free functions to create `&[T]` and `&mut [T]`.

use crate::array;
use crate::ptr;

/// Forms a slice from a pointer and a length.
///
/// The `len` argument is the number of **elements**, not the number of bytes.
///
/// # Safety
///
/// Behavior is undefined if any of the following conditions are violated:
///
/// * `data` must be [valid] for reads for `len * mem::size_of::<T>()` many bytes,
///   and it must be properly aligned. This means in particular:
///
///     * The entire memory range of this slice must be contained within a single allocated object!
///       Slices can never span across multiple allocated objects. See [below](#incorrect-usage)
///       for an example incorrectly not taking this into account.
///     * `data` must be non-null and aligned even for zero-length slices. One
///       reason for this is that enum layout optimizations may rely on references
///       (including slices of any length) being aligned and non-null to distinguish
///       them from other data. You can obtain a pointer that is usable as `data`
///       for zero-length slices using [`NonNull::dangling()`].
///
/// * `data` must point to `len` consecutive properly initialized values of type `T`.
///
/// * The memory referenced by the returned slice must not be mutated for the duration
///   of lifetime `'a`, except inside an `UnsafeCell`.
///
/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
///   See the safety documentation of [`pointer::offset`].
///
/// # Caveat
///
/// The lifetime for the returned slice is inferred from its usage. To
/// prevent accidental misuse, it's suggested to tie the lifetime to whichever
/// source lifetime is safe in the context, such as by providing a helper
/// function taking the lifetime of a host value for the slice, or by explicit
/// annotation.
///
/// # Examples
///
/// ```
/// use std::slice;
///
/// // manifest a slice for a single element
/// let x = 42;
/// let ptr = &x as *const _;
/// let slice = unsafe { slice::from_raw_parts(ptr, 1) };
/// assert_eq!(slice[0], 42);
/// ```
///
/// ### Incorrect usage
///
/// The following `join_slices` function is **unsound** ⚠
///
/// ```rust,no_run
/// use std::slice;
///
/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] {
///     let fst_end = fst.as_ptr().wrapping_add(fst.len());
///     let snd_start = snd.as_ptr();
///     assert_eq!(fst_end, snd_start, "Slices must be contiguous!");
///     unsafe {
///         // The assertion above ensures `fst` and `snd` are contiguous, but they might
///         // still be contained within _different allocated objects_, in which case
///         // creating this slice is undefined behavior.
///         slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len())
///     }
/// }
///
/// fn main() {
///     // `a` and `b` are different allocated objects...
///     let a = 42;
///     let b = 27;
///     // ... which may nevertheless be laid out contiguously in memory: | a | b |
///     let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB
/// }
/// ```
///
/// [valid]: ptr#safety
/// [`NonNull::dangling()`]: ptr::NonNull::dangling
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
    debug_check_data_len(data, len);

    // SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
    unsafe { &*ptr::slice_from_raw_parts(data, len) }
}

/// Performs the same functionality as [`from_raw_parts`], except that a
/// mutable slice is returned.
///
/// # Safety
///
/// Behavior is undefined if any of the following conditions are violated:
///
/// * `data` must be [valid] for both reads and writes for `len * mem::size_of::<T>()` many bytes,
///   and it must be properly aligned. This means in particular:
///
///     * The entire memory range of this slice must be contained within a single allocated object!
///       Slices can never span across multiple allocated objects.
///     * `data` must be non-null and aligned even for zero-length slices. One
///       reason for this is that enum layout optimizations may rely on references
///       (including slices of any length) being aligned and non-null to distinguish
///       them from other data. You can obtain a pointer that is usable as `data`
///       for zero-length slices using [`NonNull::dangling()`].
///
/// * `data` must point to `len` consecutive properly initialized values of type `T`.
///
/// * The memory referenced by the returned slice must not be accessed through any other pointer
///   (not derived from the return value) for the duration of lifetime `'a`.
///   Both read and write accesses are forbidden.
///
/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
///   See the safety documentation of [`pointer::offset`].
///
/// [valid]: ptr#safety
/// [`NonNull::dangling()`]: ptr::NonNull::dangling
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
    debug_check_data_len(data as _, len);

    // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
    unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) }
}

// In debug builds checks that `data` pointer is aligned and non-null and that slice with given `len` would cover less than half the address space
#[cfg(all(not(bootstrap), debug_assertions))]
#[unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
const fn debug_check_data_len<T>(data: *const T, len: usize) {
    fn rt_check<T>(data: *const T) {
        use crate::intrinsics::is_aligned_and_not_null;

        assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
    }

    const fn ctfe_check<T>(_data: *const T) {
        // It's impossible to check alignment in const fn.
        //
        // CTFE engine checks that the pointer is aligned and not null.
    }

    // SAFETY:
    // - `calling from_raw_parts[_mut]` with arguments that fail to fulfil checks made here is UB, so unless UB is already triggered this is noop
    // - CTFE makes the same checks as `rt_check`, so behavior change is not observable due to compilation error
    unsafe {
        crate::intrinsics::const_eval_select((data,), ctfe_check, rt_check);
    }

    assert!(
        crate::mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
        "attempt to create slice covering at least half the address space"
    );
}

#[cfg(not(all(not(bootstrap), debug_assertions)))]
const fn debug_check_data_len<T>(_data: *const T, _len: usize) {}

/// Converts a reference to T into a slice of length 1 (without copying).
#[stable(feature = "from_ref", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
pub const fn from_ref<T>(s: &T) -> &[T] {
    array::from_ref(s)
}

/// Converts a reference to T into a slice of length 1 (without copying).
#[stable(feature = "from_ref", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
pub const fn from_mut<T>(s: &mut T) -> &mut [T] {
    array::from_mut(s)
}
<|endoftext|>


<commit_before><commit_msg>richer set of commands for unix<commit_after><|endoftext|>


<commit_before>use std::collections::HashMap;
use std::iter::FromIterator;
use euclid::{Point2D, Rect};
use calx_grid::{FovValue, HexFov};
use world::{Location, World};
use world::query;

/// Useful general constant for cell dimension ops.
pub static PIXEL_UNIT: f32 = 16.0;

/// Transform from chart space (unit is one map cell) to view space (unit is
/// one pixel).
pub fn chart_to_view(chart_pos: Point2D<i32>) -> Point2D<f32> {
    Point2D::new((chart_pos.x as f32 * PIXEL_UNIT - chart_pos.y as f32 * PIXEL_UNIT),
                 (chart_pos.x as f32 * PIXEL_UNIT / 2.0 + chart_pos.y as f32 * PIXEL_UNIT / 2.0))
}

/// Transform from view space (unit is one pixel) to chart space (unit is one
/// map cell).
pub fn view_to_chart(view_pos: Point2D<f32>) -> Point2D<i32> {
    let c = PIXEL_UNIT / 2.0;
    let column = ((view_pos.x + c) / (c * 2.0)).floor();
    let row = ((view_pos.y - column * c) / (c * 2.0)).floor();
    Point2D::new((column + row) as i32, row as i32)
}

#[derive(Clone)]
struct ScreenFov<'a> {
    w: &'a World,
    screen_area: Rect<f32>,
    origins: Vec<Location>,
}

impl<'a> PartialEq for ScreenFov<'a> {
    fn eq(&self, other: &Self) -> bool {
        self.w as *const World == other.w as *const World &&
        self.screen_area == other.screen_area && self.origins == other.origins
    }
}

impl<'a> Eq for ScreenFov<'a> {}

impl<'a> FovValue for ScreenFov<'a> {
    fn advance(&self, offset: Point2D<i32>) -> Option<Self> {
        if !self.screen_area.contains(&chart_to_view(offset)) {
            return None;
        }

        let loc = self.origins[0] + offset;

        let mut ret = self.clone();
        // Go through a portal if terrain on our side of the portal is a void cell.
        //
        // With non-void terrain on top of the portal, just show our side and stay on the current
        // frame as far as FOV is concerned.
        if let Some(dest) = query::visible_portal(self.w, loc) {
            ret.origins.insert(0, dest - offset);
        }

        Some(ret)
    }
}

/// Return the field of view chart for drawing a screen.
pub fn screen_fov(
    w: &World,
    origin: Location,
    screen_area: Rect<f32>
) -> HashMap<Point2D<i32>, Vec<Location>> {
    let init = ScreenFov {
        w: w,
        screen_area: screen_area,
        origins: vec![origin],
    };

    HashMap::from_iter(HexFov::new(init).map(|(pos, a)| (pos, a.origins)))
}

#[cfg(test)]
mod test {
    use euclid::{Point2D, Rect, Size2D};
    use world::{Location, Portal, World};
    use super::{view_to_chart, screen_fov};

    fn test_world() -> World {
        use world::terrain::{Form, Kind, Tile};
        use calx_resource::ResourceStore;
        use world::Brush;

        Brush::insert_resource("dummy".to_string(), Brush::new(Vec::new()));

        Tile::insert_resource(0, Tile::new("dummy", Kind::Block, Form::Void));
        Tile::insert_resource(1, Tile::new("dummy", Kind::Ground, Form::Gate));
        Tile::insert_resource(2, Tile::new("dummy", Kind::Ground, Form::Floor));
        Tile::insert_resource(3, Tile::new("dummy", Kind::Ground, Form::Floor));

        let mut ret = World::new(1);

        ret.terrain.set(Location::new(10, 10, 0), 2);
        ret.terrain.set(Location::new(11, 11, 0), 2);
        ret.terrain.set(Location::new(9, 9, 0), 2);
        ret.terrain.set(Location::new(10, 11, 0), 2);
        ret.terrain.set(Location::new(9, 10, 0), 2);
        ret.terrain.set(Location::new(10, 9, 0), 2);

        // Void for the see-through portal.
        ret.terrain.set(Location::new(11, 10, 0), 0);
        ret.set_portal(Location::new(11, 10, 0),
                       Portal::new(Location::new(11, 10, 0), Location::new(31, 10, 0)));
        ret.terrain.set(Location::new(31, 10, 0), 3);

        ret
    }

    #[test]
    fn test_portaling_fov() {
        let world = test_world();
        let fov = screen_fov(&world,
                             Location::new(10, 10, 0),
                             Rect::new(Point2D::new(-48.0, -48.0), Size2D::new(96.0, 96.0)));
        assert_eq!(fov.get(&Point2D::new(0, 0)),
                   Some(&vec![Location::new(10, 10, 0)]));

        assert_eq!(fov.get(&Point2D::new(0, 1)),
                   Some(&vec![Location::new(10, 10, 0)]));

        assert_eq!(fov.get(&Point2D::new(1, 1)),
                   Some(&vec![Location::new(10, 10, 0)]));

        assert_eq!(fov.get(&Point2D::new(-1, -1)),
                   Some(&vec![Location::new(10, 10, 0)]));

        assert_eq!(fov.get(&Point2D::new(1, 0)),
                   Some(&vec![Location::new(30, 10, 0), Location::new(10, 10, 0)]));
    }

    #[test]
    fn test_corner_visibility() {
        let world = test_world();
        let fov = screen_fov(&world,
                             Location::new(10, 10, 0),
                             Rect::new(Point2D::new(-200.0, -200.0), Size2D::new(400.0, 400.0)));
        let upper_left_chart = view_to_chart(Point2D::new(-180.0, -180.0));
        assert!(fov.get(&upper_left_chart).is_some());
    }
}
<commit_msg>More thorough screen_fov test<commit_after>use std::collections::HashMap;
use std::iter::FromIterator;
use euclid::{Point2D, Rect};
use calx_grid::{FovValue, HexFov};
use world::{Location, World};
use world::query;

/// Useful general constant for cell dimension ops.
pub static PIXEL_UNIT: f32 = 16.0;

/// Transform from chart space (unit is one map cell) to view space (unit is
/// one pixel).
pub fn chart_to_view(chart_pos: Point2D<i32>) -> Point2D<f32> {
    Point2D::new((chart_pos.x as f32 * PIXEL_UNIT - chart_pos.y as f32 * PIXEL_UNIT),
                 (chart_pos.x as f32 * PIXEL_UNIT / 2.0 + chart_pos.y as f32 * PIXEL_UNIT / 2.0))
}

/// Transform from view space (unit is one pixel) to chart space (unit is one
/// map cell).
pub fn view_to_chart(view_pos: Point2D<f32>) -> Point2D<i32> {
    let c = PIXEL_UNIT / 2.0;
    let column = ((view_pos.x + c) / (c * 2.0)).floor();
    let row = ((view_pos.y - column * c) / (c * 2.0)).floor();
    Point2D::new((column + row) as i32, row as i32)
}

#[derive(Clone)]
struct ScreenFov<'a> {
    w: &'a World,
    screen_area: Rect<f32>,
    origins: Vec<Location>,
}

impl<'a> PartialEq for ScreenFov<'a> {
    fn eq(&self, other: &Self) -> bool {
        self.w as *const World == other.w as *const World &&
        self.screen_area == other.screen_area && self.origins == other.origins
    }
}

impl<'a> Eq for ScreenFov<'a> {}

impl<'a> FovValue for ScreenFov<'a> {
    fn advance(&self, offset: Point2D<i32>) -> Option<Self> {
        if !self.screen_area.contains(&chart_to_view(offset)) {
            return None;
        }

        let loc = self.origins[0] + offset;

        let mut ret = self.clone();
        // Go through a portal if terrain on our side of the portal is a void cell.
        //
        // With non-void terrain on top of the portal, just show our side and stay on the current
        // frame as far as FOV is concerned.
        if let Some(dest) = query::visible_portal(self.w, loc) {
            ret.origins.insert(0, dest - offset);
        }

        Some(ret)
    }
}

/// Return the field of view chart for drawing a screen.
pub fn screen_fov(
    w: &World,
    origin: Location,
    screen_area: Rect<f32>
) -> HashMap<Point2D<i32>, Vec<Location>> {
    let init = ScreenFov {
        w: w,
        screen_area: screen_area,
        origins: vec![origin],
    };

    HashMap::from_iter(HexFov::new(init).map(|(pos, a)| (pos, a.origins)))
}

#[cfg(test)]
mod test {
    use euclid::{Point2D, Rect, Size2D};
    use world::{Location, Portal, World};
    use super::{screen_fov, view_to_chart};

    fn test_world() -> World {
        use world::terrain::{Form, Kind, Tile};
        use calx_resource::ResourceStore;
        use world::Brush;

        Brush::insert_resource("dummy".to_string(), Brush::new(Vec::new()));

        Tile::insert_resource(0, Tile::new("dummy", Kind::Block, Form::Void));
        Tile::insert_resource(1, Tile::new("dummy", Kind::Ground, Form::Gate));
        Tile::insert_resource(2, Tile::new("dummy", Kind::Ground, Form::Floor));
        Tile::insert_resource(3, Tile::new("dummy", Kind::Ground, Form::Floor));

        let mut ret = World::new(1);

        ret.terrain.set(Location::new(10, 10, 0), 2);
        ret.terrain.set(Location::new(11, 11, 0), 2);
        ret.terrain.set(Location::new(9, 9, 0), 2);
        ret.terrain.set(Location::new(10, 11, 0), 2);
        ret.terrain.set(Location::new(9, 10, 0), 2);
        ret.terrain.set(Location::new(10, 9, 0), 2);

        // Void for the see-through portal.
        ret.terrain.set(Location::new(11, 10, 0), 0);
        ret.set_portal(Location::new(11, 10, 0),
                       Portal::new(Location::new(11, 10, 0), Location::new(31, 10, 0)));
        ret.terrain.set(Location::new(31, 10, 0), 3);

        ret
    }

    #[test]
    fn test_portaling_fov() {
        let world = test_world();
        let fov = screen_fov(&world,
                             Location::new(10, 10, 0),
                             Rect::new(Point2D::new(-48.0, -48.0), Size2D::new(96.0, 96.0)));
        assert_eq!(fov.get(&Point2D::new(0, 0)),
                   Some(&vec![Location::new(10, 10, 0)]));

        assert_eq!(fov.get(&Point2D::new(0, 1)),
                   Some(&vec![Location::new(10, 10, 0)]));

        assert_eq!(fov.get(&Point2D::new(1, 1)),
                   Some(&vec![Location::new(10, 10, 0)]));

        assert_eq!(fov.get(&Point2D::new(-1, -1)),
                   Some(&vec![Location::new(10, 10, 0)]));

        assert_eq!(fov.get(&Point2D::new(1, 0)),
                   Some(&vec![Location::new(30, 10, 0), Location::new(10, 10, 0)]));
    }

    #[test]
    fn test_corner_visibility() {
        let world = test_world();
        let screen_rect = Rect::new(Point2D::new(-200.0, -200.0), Size2D::new(400.0, 400.0));
        let fov = screen_fov(&world, Location::new(10, 10, 0), screen_rect);

        // Check that the fov is bounded close to the given rectangle.

        let inside_screen = screen_rect.inflate(-40.0, -40.0);
        assert!(fov.get(&view_to_chart(inside_screen.origin)).is_some());
        assert!(fov.get(&view_to_chart(inside_screen.bottom_left())).is_some());
        assert!(fov.get(&view_to_chart(inside_screen.top_right())).is_some());
        assert!(fov.get(&view_to_chart(inside_screen.bottom_right())).is_some());

        let outside_screen = screen_rect.inflate(40.0, 40.0);
        assert!(fov.get(&view_to_chart(outside_screen.origin)).is_none());
        assert!(fov.get(&view_to_chart(outside_screen.bottom_left())).is_none());
        assert!(fov.get(&view_to_chart(outside_screen.top_right())).is_none());
        assert!(fov.get(&view_to_chart(outside_screen.bottom_right())).is_none());
    }
}
<|endoftext|>


<commit_before><commit_msg>wrote minimal structs and trait for word creation<commit_after>use config::*;
use rand::Rng;
use rand::distributions::{Weighted, WeightedChoice, IndependentSample};

pub struct Word {
    pub syllables : String,
    pub graphemes : String,
    pub syllable_rewrite_history : Vec<(String, String)>,
    pub grapheme_rewrite_history : Vec<(String, String)>,
    pub syllable_rejects : Vec<String>,
    pub grapheme_rejects : Vec<String>,
}

pub struct WordFactory {
    first_syllable_list : Vec<Weighted<String>>,
    last_syllable_list : Vec<Weighted<String>>,
    normal_syllable_list : Vec<Weighted<String>>,

    graphemes : Vec<(String, Vec<Weighted<String>>)>,

    syllable_rewrites : Vec<Rewrite>,
    grapheme_rewrites : Vec<Rewrite>,

    syllable_rejects : Vec<String>,
    grapheme_rejects : Vec<String>,

    settings : GenerateSettings,
}

trait WordGenerator {
    fn new(
        &mut self,
        first_syllables : &Vec<Weighted<String>>,
        last_syllables : &Vec<Weighted<String>>,
        normal_syllables : &Vec<Weighted<String>>,
        graphemes : &Vec<(String, Vec<Weighted<String>>)>,
        settings: &GenerateSettings);
    fn generate_syllables(&mut self, word: &mut Word);
    fn generate_graphemes(&mut self, word: &mut Word);
    fn rewrite_syllables(&mut self, word: &mut Word);
    fn rewrite_graphemes(&mut self, word: &mut Word);
    fn mark_syllable_rejects(&mut self, word: &mut Word);
    fn mark_grapheme_rejects(&mut self, word: &mut Word);
}
<|endoftext|>


<commit_before>use std::marker;
use std::cell::UnsafeCell;
use std::fmt;
use std::mem;
use std::ptr;
use std::ops::{Deref, DerefMut};

// For now, treat this as an arch-independent constant.
const CACHE_LINE: usize = 32;

#[cfg_attr(feature = "nightly",
           repr(simd))]
#[derive(Debug)]
struct Padding(u64, u64, u64, u64);

/// Pad `T` to the length of a cacheline.
///
/// Sometimes concurrent programming requires a piece of data to be padded out
/// to the size of a cacheline to avoid "false sharing": cachelines being
/// invalidated due to unrelated concurrent activity. Use the `CachePadded` type
/// when you want to *avoid* cache locality.
///
/// At the moment, cache lines are assumed to be 32 * sizeof(usize) on all
/// architectures.
///
/// **Warning**: the wrapped data is never dropped; move out using `ptr::read`
/// if you need to run dtors.
pub struct CachePadded<T> {
    data: UnsafeCell<[usize; CACHE_LINE]>,
    _marker: ([Padding; 0], marker::PhantomData<T>),
}

impl<T> fmt::Debug for CachePadded<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "CachePadded {{ ... }}")
    }
}

unsafe impl<T: Send> Send for CachePadded<T> {}
unsafe impl<T: Sync> Sync for CachePadded<T> {}

/// Types for which mem::zeroed() is safe.
///
/// If a type `T: ZerosValid`, then a sequence of zeros the size of `T` must be
/// a valid member of the type `T`.
#[cfg(not(feature = "nightly"))]
pub unsafe trait ZerosValid {}

/// Types for which mem::zeroed() is safe.
///
/// If a type `T: ZerosValid`, then a sequence of zeros the size of `T` must be
/// a valid member of the type `T`.
#[cfg(feature = "nightly")]
pub unsafe auto trait ZerosValid {}

macro_rules! zeros_valid { ($( $T:ty )*) => ($(
    unsafe impl ZerosValid for $T {}
)*)}

zeros_valid!(u8 u16 u32 u64 usize);
zeros_valid!(i8 i16 i32 i64 isize);

unsafe impl ZerosValid for ::std::sync::atomic::AtomicUsize {}
unsafe impl<T> ZerosValid for ::std::sync::atomic::AtomicPtr<T> {}

impl<T: ZerosValid> CachePadded<T> {
    /// A const fn equivalent to mem::zeroed().
    #[cfg(not(feature = "nightly"))]
    pub fn zeroed() -> CachePadded<T> {
        CachePadded {
            data: UnsafeCell::new(([0; CACHE_LINE])),
            _marker: ([], marker::PhantomData),
        }
    }

    /// A const fn equivalent to mem::zeroed().
    #[cfg(feature = "nightly")]
    pub const fn zeroed() -> CachePadded<T> {
        CachePadded {
            data: UnsafeCell::new(([0; CACHE_LINE])),
            _marker: ([], marker::PhantomData),
        }
    }
}

#[inline]
/// Assert that the size and alignment of `T` are consistent with `CachePadded<T>`.
fn assert_valid<T>() {
    assert!(mem::size_of::<T>() <= mem::size_of::<CachePadded<T>>());
    assert!(mem::align_of::<T>() <= mem::align_of::<CachePadded<T>>());
}

impl<T> CachePadded<T> {
    /// Wrap `t` with cacheline padding.
    ///
    /// **Warning**: the wrapped data is never dropped; move out using
    /// `ptr:read` if you need to run dtors.
    pub fn new(t: T) -> CachePadded<T> {
        assert_valid::<T>();
        let ret = CachePadded {
            data: UnsafeCell::new(([0; CACHE_LINE])),
            _marker: ([], marker::PhantomData),
        };
        unsafe {
            let p: *mut T = mem::transmute(&ret.data);
            ptr::write(p, t);
        }
        ret
    }
}

impl<T> Deref for CachePadded<T> {
    type Target = T;
    fn deref(&self) -> &T {
        assert_valid::<T>();
        unsafe { mem::transmute(&self.data) }
    }
}

impl<T> DerefMut for CachePadded<T> {
    fn deref_mut(&mut self) -> &mut T {
        assert_valid::<T>();
        unsafe { mem::transmute(&mut self.data) }
    }
}

// FIXME: support Drop by pulling out a version usable for statics
/*
impl<T> Drop for CachePadded<T> {
    fn drop(&mut self) {
        assert_valid::<T>();
        let p: *mut T = mem::transmute(&self.data);
        mem::drop(ptr::read(p));
    }
}
*/

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

    #[test]
    fn cache_padded_store_u64() {
        let x: CachePadded<u64> = CachePadded::new(17);
        assert_eq!(*x, 17);
    }

    #[test]
    fn cache_padded_store_pair() {
        let x: CachePadded<(u64, u64)> = CachePadded::new((17, 37));
        assert_eq!(x.0, 17);
        assert_eq!(x.1, 37);
    }
}
<commit_msg>Fix compilation error on old Rust versions<commit_after>use std::marker;
use std::cell::UnsafeCell;
use std::fmt;
use std::mem;
use std::ptr;
use std::ops::{Deref, DerefMut};

// For now, treat this as an arch-independent constant.
const CACHE_LINE: usize = 32;

#[cfg_attr(feature = "nightly",
           repr(simd))]
#[derive(Debug)]
struct Padding(u64, u64, u64, u64);

/// Pad `T` to the length of a cacheline.
///
/// Sometimes concurrent programming requires a piece of data to be padded out
/// to the size of a cacheline to avoid "false sharing": cachelines being
/// invalidated due to unrelated concurrent activity. Use the `CachePadded` type
/// when you want to *avoid* cache locality.
///
/// At the moment, cache lines are assumed to be 32 * sizeof(usize) on all
/// architectures.
///
/// **Warning**: the wrapped data is never dropped; move out using `ptr::read`
/// if you need to run dtors.
pub struct CachePadded<T> {
    data: UnsafeCell<[usize; CACHE_LINE]>,
    _marker: ([Padding; 0], marker::PhantomData<T>),
}

impl<T> fmt::Debug for CachePadded<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "CachePadded {{ ... }}")
    }
}

unsafe impl<T: Send> Send for CachePadded<T> {}
unsafe impl<T: Sync> Sync for CachePadded<T> {}

#[cfg(not(feature = "nightly"))]
macro_rules! declare_zeros_valid {
    () => {
        /// Types for which mem::zeroed() is safe.
        ///
        /// If a type `T: ZerosValid`, then a sequence of zeros the size of `T` must be
        /// a valid member of the type `T`.
        pub unsafe trait ZerosValid {}
    }
}

#[cfg(feature = "nightly")]
macro_rules! declare_zeros_valid {
    () => {
        /// Types for which mem::zeroed() is safe.
        ///
        /// If a type `T: ZerosValid`, then a sequence of zeros the size of `T` must be
        /// a valid member of the type `T`.
        pub unsafe auto trait ZerosValid {}
    }
}

declare_zeros_valid!();

macro_rules! zeros_valid { ($( $T:ty )*) => ($(
    unsafe impl ZerosValid for $T {}
)*)}

zeros_valid!(u8 u16 u32 u64 usize);
zeros_valid!(i8 i16 i32 i64 isize);

unsafe impl ZerosValid for ::std::sync::atomic::AtomicUsize {}
unsafe impl<T> ZerosValid for ::std::sync::atomic::AtomicPtr<T> {}

impl<T: ZerosValid> CachePadded<T> {
    /// A const fn equivalent to mem::zeroed().
    #[cfg(not(feature = "nightly"))]
    pub fn zeroed() -> CachePadded<T> {
        CachePadded {
            data: UnsafeCell::new(([0; CACHE_LINE])),
            _marker: ([], marker::PhantomData),
        }
    }

    /// A const fn equivalent to mem::zeroed().
    #[cfg(feature = "nightly")]
    pub const fn zeroed() -> CachePadded<T> {
        CachePadded {
            data: UnsafeCell::new(([0; CACHE_LINE])),
            _marker: ([], marker::PhantomData),
        }
    }
}

#[inline]
/// Assert that the size and alignment of `T` are consistent with `CachePadded<T>`.
fn assert_valid<T>() {
    assert!(mem::size_of::<T>() <= mem::size_of::<CachePadded<T>>());
    assert!(mem::align_of::<T>() <= mem::align_of::<CachePadded<T>>());
}

impl<T> CachePadded<T> {
    /// Wrap `t` with cacheline padding.
    ///
    /// **Warning**: the wrapped data is never dropped; move out using
    /// `ptr:read` if you need to run dtors.
    pub fn new(t: T) -> CachePadded<T> {
        assert_valid::<T>();
        let ret = CachePadded {
            data: UnsafeCell::new(([0; CACHE_LINE])),
            _marker: ([], marker::PhantomData),
        };
        unsafe {
            let p: *mut T = mem::transmute(&ret.data);
            ptr::write(p, t);
        }
        ret
    }
}

impl<T> Deref for CachePadded<T> {
    type Target = T;
    fn deref(&self) -> &T {
        assert_valid::<T>();
        unsafe { mem::transmute(&self.data) }
    }
}

impl<T> DerefMut for CachePadded<T> {
    fn deref_mut(&mut self) -> &mut T {
        assert_valid::<T>();
        unsafe { mem::transmute(&mut self.data) }
    }
}

// FIXME: support Drop by pulling out a version usable for statics
/*
impl<T> Drop for CachePadded<T> {
    fn drop(&mut self) {
        assert_valid::<T>();
        let p: *mut T = mem::transmute(&self.data);
        mem::drop(ptr::read(p));
    }
}
*/

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

    #[test]
    fn cache_padded_store_u64() {
        let x: CachePadded<u64> = CachePadded::new(17);
        assert_eq!(*x, 17);
    }

    #[test]
    fn cache_padded_store_pair() {
        let x: CachePadded<(u64, u64)> = CachePadded::new((17, 37));
        assert_eq!(x.0, 17);
        assert_eq!(x.1, 37);
    }
}
<|endoftext|>


<commit_before>#[crate_id(name="echo", vers="1.0.0", author="Derek Chiang")];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Derek Chiang <derekchiang93@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern mod extra;

use std::os;
use std::io::{print, println, stderr};
use std::uint;
use extra::getopts::groups;

static VERSION: &'static str = "1.0.0";

fn print_char(c: char) {
    print!("{}", c);
}

fn to_char(bytes: &[u8], base: uint) -> char {
    uint::parse_bytes(bytes, base).unwrap() as u8 as char
}

fn isxdigit(c: u8) -> bool {
    match c as char {
        '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' |
        '8' | '9' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' => true,
        _ => false
    }
}

fn isodigit(c: u8) -> bool {
    match c as char {
        '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' => true,
        _ => false
    }
}

fn convert_str(string: &str, index: uint, base: uint) -> (char, int) {
    let (max_digits, is_legal_digit) = match base {
        8u => (3, isodigit),
        16u => (2, isxdigit),
        _ => fail!(),
    };

    let mut bytes: ~[u8] = ~[];
    for offset in range(0, max_digits) {
        let c = string[index + offset as uint];
        if is_legal_digit(c) {
            bytes.push(c as u8);
        } else {
            if bytes.len() > 0 {
                return (to_char(bytes, base), offset);
            } else {
                return (' ', offset);
            }
        }
    }
    return (to_char(bytes, base), max_digits)
}

fn main() {
    let args = os::args();
    let program = args[0].clone();
    let opts = ~[
        groups::optflag("n", "", "do not output the trailing newline"),
        groups::optflag("e", "", "enable interpretation of backslash escapes"),
        groups::optflag("E", "", "disable interpretation of backslash escapes (default)"),
        groups::optflag("h", "help", "display this help and exit"),
        groups::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match groups::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => {
            writeln!(&mut stderr() as &mut Writer,
                "Invalid options\n{}", f.to_err_msg());
            os::set_exit_status(1);
            return
        }
    };

    if matches.opt_present("help") {
        println!("echo {:s} - display a line of text", VERSION);
        println!("");
        println!("Usage:");
        println!("  {0:s} [SHORT-OPTION]... [STRING]...", program);
        println!("  {0:s} LONG-OPTION", program);
        println!("");
        println(groups::usage("Echo the STRING(s) to standard output.", opts));
        println("If -e is in effect, the following sequences are recognized:

\\\\      backslash
\\a      alert (BEL)
\\b      backspace
\\c      produce no further output
\\e      escape
\\f      form feed
\\n      new line
\\r      carriage return
\\t      horizontal tab
\\v      vertical tab
\\0NNN   byte with octal value NNN (1 to 3 digits)
\\xHH    byte with hexadecimal value HH (1 to 2 digits)");
        return;
    }

    if matches.opt_present("version") {
        return println!("echo version: {:s}", VERSION);
    }

    if !matches.free.is_empty() {
        let string = matches.free.connect(" ");
        if matches.opt_present("e") {
            let mut prev_was_slash = false;
            let mut iter = string.chars().enumerate();
            loop {
                match iter.next() {
                    Some((index, c)) => {
                        if !prev_was_slash {
                            if c != '\\' {
                                print_char(c);
                            } else {
                                prev_was_slash = true;
                            }
                        } else {
                            prev_was_slash = false;
                            match c {
                                '\\' => print_char('\\'),
                                'a' => print_char('\x07'),
                                'b' => print_char('\x08'),
                                'c' => break,
                                'e' => print_char('\x1B'),
                                'f' => print_char('\x0C'),
                                'n' => print_char('\n'),
                                'r' => print_char('\r'),
                                't' => print_char('\t'),
                                'v' => print_char('\x0B'),
                                'x' => {
                                    let (c, num_char_used) = convert_str(string, index + 1, 16u);
                                    if num_char_used == 0 {
                                        print_char('\\');
                                        print_char('x');
                                    } else {
                                        print_char(c);
                                        for _ in range(0, num_char_used) {
                                            iter.next(); // consume used characters
                                        }
                                    }
                                },
                                '0' => {
                                    let (c, num_char_used) = convert_str(string, index + 1, 8u);
                                    if num_char_used == 0 {
                                        print_char('\\');
                                        print_char('0');
                                    } else {
                                        print_char(c);
                                        for _ in range(0, num_char_used) {
                                            iter.next(); // consume used characters
                                        }
                                    }
                                }
                                _ => {
                                    print_char('\\');
                                    print_char(c);
                                }
                            }
                        }
                    }
                    None => break
                }
            }
        } else {
            print(string);
        }
    }

    if !matches.opt_present("n") {
        println!("")
    }
}
<commit_msg>use crash! macro in echo<commit_after>#[feature(macro_rules)];
#[crate_id(name="echo", vers="1.0.0", author="Derek Chiang")];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Derek Chiang <derekchiang93@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern mod extra;

use std::os;
use std::io::{print, println};
use std::uint;
use extra::getopts::groups;

static VERSION: &'static str = "1.0.0";

#[macro_export]
macro_rules! crash(
    ($exitcode:expr, $($args:expr),+) => (
        {   ::std::os::set_exit_status($exitcode);
            let _unused = write!(&mut ::std::io::stderr(), $($args),+);
            return;
        }
    )
)

fn print_char(c: char) {
    print!("{}", c);
}

fn to_char(bytes: &[u8], base: uint) -> char {
    uint::parse_bytes(bytes, base).unwrap() as u8 as char
}

fn isxdigit(c: u8) -> bool {
    match c as char {
        '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' |
        '8' | '9' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' => true,
        _ => false
    }
}

fn isodigit(c: u8) -> bool {
    match c as char {
        '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' => true,
        _ => false
    }
}

fn convert_str(string: &str, index: uint, base: uint) -> (char, int) {
    let (max_digits, is_legal_digit) = match base {
        8u => (3, isodigit),
        16u => (2, isxdigit),
        _ => fail!(),
    };

    let mut bytes: ~[u8] = ~[];
    for offset in range(0, max_digits) {
        let c = string[index + offset as uint];
        if is_legal_digit(c) {
            bytes.push(c as u8);
        } else {
            if bytes.len() > 0 {
                return (to_char(bytes, base), offset);
            } else {
                return (' ', offset);
            }
        }
    }
    return (to_char(bytes, base), max_digits)
}

fn main() {
    let args = os::args();
    let program = args[0].clone();
    let opts = ~[
        groups::optflag("n", "", "do not output the trailing newline"),
        groups::optflag("e", "", "enable interpretation of backslash escapes"),
        groups::optflag("E", "", "disable interpretation of backslash escapes (default)"),
        groups::optflag("h", "help", "display this help and exit"),
        groups::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match groups::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => crash!(1, "Invalid options\n{}", f.to_err_msg())
    };

    if matches.opt_present("help") {
        println!("echo {:s} - display a line of text", VERSION);
        println!("");
        println!("Usage:");
        println!("  {0:s} [SHORT-OPTION]... [STRING]...", program);
        println!("  {0:s} LONG-OPTION", program);
        println!("");
        println(groups::usage("Echo the STRING(s) to standard output.", opts));
        println("If -e is in effect, the following sequences are recognized:

\\\\      backslash
\\a      alert (BEL)
\\b      backspace
\\c      produce no further output
\\e      escape
\\f      form feed
\\n      new line
\\r      carriage return
\\t      horizontal tab
\\v      vertical tab
\\0NNN   byte with octal value NNN (1 to 3 digits)
\\xHH    byte with hexadecimal value HH (1 to 2 digits)");
        return;
    }

    if matches.opt_present("version") {
        return println!("echo version: {:s}", VERSION);
    }

    if !matches.free.is_empty() {
        let string = matches.free.connect(" ");
        if matches.opt_present("e") {
            let mut prev_was_slash = false;
            let mut iter = string.chars().enumerate();
            loop {
                match iter.next() {
                    Some((index, c)) => {
                        if !prev_was_slash {
                            if c != '\\' {
                                print_char(c);
                            } else {
                                prev_was_slash = true;
                            }
                        } else {
                            prev_was_slash = false;
                            match c {
                                '\\' => print_char('\\'),
                                'a' => print_char('\x07'),
                                'b' => print_char('\x08'),
                                'c' => break,
                                'e' => print_char('\x1B'),
                                'f' => print_char('\x0C'),
                                'n' => print_char('\n'),
                                'r' => print_char('\r'),
                                't' => print_char('\t'),
                                'v' => print_char('\x0B'),
                                'x' => {
                                    let (c, num_char_used) = convert_str(string, index + 1, 16u);
                                    if num_char_used == 0 {
                                        print_char('\\');
                                        print_char('x');
                                    } else {
                                        print_char(c);
                                        for _ in range(0, num_char_used) {
                                            iter.next(); // consume used characters
                                        }
                                    }
                                },
                                '0' => {
                                    let (c, num_char_used) = convert_str(string, index + 1, 8u);
                                    if num_char_used == 0 {
                                        print_char('\\');
                                        print_char('0');
                                    } else {
                                        print_char(c);
                                        for _ in range(0, num_char_used) {
                                            iter.next(); // consume used characters
                                        }
                                    }
                                }
                                _ => {
                                    print_char('\\');
                                    print_char(c);
                                }
                            }
                        }
                    }
                    None => break
                }
            }
        } else {
            print(string);
        }
    }

    if !matches.opt_present("n") {
        println!("")
    }
}
<|endoftext|>


<commit_before>//!
//! The API for communicating with devices.
//!
//! This API is provided as Traits to be implemented:
//!
//! - by the low-level layers of the FoxBox, including the adapters;
//! - by test suites and tools that need to simulate connected devices.
//!
//! In turn, this API is used to implement:
//!
//! - the public-facing REST and WebSocket API;
//! - the rules API (ThinkerBell).
//!
//!

use devices::*;
use requests::*;
use values::Value;

/// An error produced by one of the APIs in this module.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Error {
    /// There is no such node connected to the Foxbox, even indirectly.
    NoSuchNode(NodeId),

    /// There is no such service connected to the Foxbox, even indirectly.
    NoSuchService(ServiceId),

    /// Attempting to set a value with the wrong type
    TypeError,
}

/// An event during watching.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum WatchEvent {
    /// A new value is available.
    Value {
        /// The service that sent the value.
        from: ServiceId,

        /// The actual value.
        value: Value
    },

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// removed. Payload is the id of the device that was removed.
    InputRemoved(ServiceId),

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// added. Payload is the id of the device that was added.
    InputAdded(ServiceId),
}

/// A handle to the public API.
pub trait API: Send {
    /// Get the metadata on nodes matching some conditions.
    ///
    /// A call to `API::get_nodes(vec![req1, req2, ...])` will return
    /// the metadata on all nodes matching _either_ `req1` or `req2`
    /// or ...
    ///
    /// # REST API
    ///
    /// `GET /api/v1/nodes`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to a `Vec<NodeRequest>`. See
    /// the implementation of `NodeRequest` for details.
    ///
    /// ### Example
    ///
    /// Request all doors in the entrance (tags `door`, `entrance`)
    /// that support output service `OpenClose`
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door"],
    ///   "inputs": [
    ///     {
    ///       "kind": {
    ///         "Exactly": {
    ///           "OpenClose": []
    ///         }
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    ///
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing an array of `Node`. See the implementation
    /// of `Node` for details.
    ///
    /// ### Example
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door", "somevendor"],
    ///   "id: "some-node-id",
    ///   "inputs": [],
    ///   "outputs": [
    ///     "tags": [...],
    ///     "id": "some-service-id",
    ///     "node": "some-node-id",
    ///     "last_seen": "some-date",
    ///     "mechanism": {
    ///       "Output":  {
    ///         "kind": {
    ///           "OnOff": []
    ///         },
    ///         "push": [5000],
    ///         "updated": "some-date",
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    fn get_nodes(&self, &Vec<NodeRequest>) -> Vec<Node>;

    /// Label a set of nodes with a set of tags.
    ///
    /// A call to `API::put_node_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the nodes matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of nodes
    /// matching any of the requests.
    ///
    /// Some of the nodes may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if nodes
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/nodes/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<NodeRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON string representing a number.
    fn put_node_tag(&self, set: &Vec<NodeRequest>, tags: &Vec<String>) -> usize;

    /// Remove a set of tags from a set of nodes.
    ///
    /// A call to `API::delete_node_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the nodes matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of nodes
    /// matching any of the requests.
    ///
    /// Some of the nodes may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if nodes
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/nodes/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<NodeRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn delete_node_tag(&self, set: &Vec<NodeRequest>, tags: String) -> usize;

    /// Get a list of inputs matching some conditions
    ///
    /// # REST API
    ///
    /// `GET /api/v1/services`
    fn get_input_services(&self, &Vec<InputRequest>) -> Vec<Service<Input>>;
    fn get_output_services(&self, &Vec<OutputRequest>) -> Vec<Service<Output>>;

    /// Label a set of services with a set of tags.
    ///
    /// A call to `API::put_{input, output}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the services matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of services
    /// matching any of the requests.
    ///
    /// Some of the services may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/services/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<InputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```ignore
    /// {
    ///   set: Vec<OutputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn put_input_tag(&self, &Vec<InputRequest>, &Vec<String>) -> usize;
    fn put_output_tag(&self, &Vec<OutputRequest>, &Vec<String>) -> usize;

    /// Remove a set of tags from a set of services.
    ///
    /// A call to `API::delete_{input, output}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the services matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of services
    /// matching any of the requests.
    ///
    /// Some of the services may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/services/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<InputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```ignore
    /// {
    ///   set: Vec<OutputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn delete_input_tag(&self, &Vec<InputRequest>, &Vec<String>) -> usize;
    fn delete_output_tag(&self, &Vec<InputRequest>, &Vec<String>) -> usize;

    /// Read the latest value from a set of services
    ///
    /// # REST API
    ///
    /// `GET /api/v1/services/value`
    fn get_service_value(&self, &Vec<InputRequest>) -> Vec<(ServiceId, Result<Value, Error>)>;

    /// Send one value to a set of services
    ///
    /// # REST API
    ///
    /// `POST /api/v1/services/value`
    fn put_service_value(&self, &Vec<OutputRequest>, Value) -> Vec<(ServiceId, Result<(), Error>)>;

    /// Watch for any change
    ///
    /// # WebSocket API
    ///
    /// `/api/v1/services/watch`
    fn register_service_watch(&self, Vec<WatchOptions>, cb: Box<FnMut(WatchEvent) + Send + 'static>) -> Self::WatchGuard;

    /// A value that causes a disconnection once it is dropped.
    type WatchGuard;
}

/// Options for watching changes in one or more services.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct WatchOptions {
    /// The set of inputs to watch. Note that the actual inputs in the
    /// set may change over time.
    pub source: InputRequest,

    /// If `true`, watch as new values become available.
    pub should_watch_values: bool,

    /// If `true`, watch as nodes are connected/disconnected.
    pub should_watch_topology: bool,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}

impl WatchOptions {
    pub fn new() -> Self {
        WatchOptions {
            source: InputRequest::new(),
            should_watch_values: false,
            should_watch_topology: false,
            private: (),
        }
    }

    /// Restrict to input services in a given set.
    ///
    /// Also note that the actual input services that are part of the
    /// set may change with time, for instance if devices are added
    /// ore removed.  The request _is live_, i.e. the service watch
    /// will continue watching any input services that match `req`.
    pub fn with_inputs(self, req: InputRequest) -> Self {
        WatchOptions {
            source: self.source.and(req),
            ..self
        }
    }

    pub fn with_watch_values(self, should: bool) -> Self {
        WatchOptions {
            should_watch_values: should,
            ..self
        }
    }

    pub fn with_watch_topology(self, should: bool) -> Self {
        WatchOptions {
            should_watch_topology: should,
            ..self
        }
    }
}
<commit_msg>register_service_watch now takes an Fn instead of an FnMut<commit_after>//!
//! The API for communicating with devices.
//!
//! This API is provided as Traits to be implemented:
//!
//! - by the low-level layers of the FoxBox, including the adapters;
//! - by test suites and tools that need to simulate connected devices.
//!
//! In turn, this API is used to implement:
//!
//! - the public-facing REST and WebSocket API;
//! - the rules API (ThinkerBell).
//!
//!

use devices::*;
use requests::*;
use values::Value;

/// An error produced by one of the APIs in this module.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Error {
    /// There is no such node connected to the Foxbox, even indirectly.
    NoSuchNode(NodeId),

    /// There is no such service connected to the Foxbox, even indirectly.
    NoSuchService(ServiceId),

    /// Attempting to set a value with the wrong type
    TypeError,
}

/// An event during watching.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum WatchEvent {
    /// A new value is available.
    Value {
        /// The service that sent the value.
        from: ServiceId,

        /// The actual value.
        value: Value
    },

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// removed. Payload is the id of the device that was removed.
    InputRemoved(ServiceId),

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// added. Payload is the id of the device that was added.
    InputAdded(ServiceId),
}

/// A handle to the public API.
pub trait API: Send {
    /// Get the metadata on nodes matching some conditions.
    ///
    /// A call to `API::get_nodes(vec![req1, req2, ...])` will return
    /// the metadata on all nodes matching _either_ `req1` or `req2`
    /// or ...
    ///
    /// # REST API
    ///
    /// `GET /api/v1/nodes`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to a `Vec<NodeRequest>`. See
    /// the implementation of `NodeRequest` for details.
    ///
    /// ### Example
    ///
    /// Request all doors in the entrance (tags `door`, `entrance`)
    /// that support output service `OpenClose`
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door"],
    ///   "inputs": [
    ///     {
    ///       "kind": {
    ///         "Exactly": {
    ///           "OpenClose": []
    ///         }
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    ///
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing an array of `Node`. See the implementation
    /// of `Node` for details.
    ///
    /// ### Example
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door", "somevendor"],
    ///   "id: "some-node-id",
    ///   "inputs": [],
    ///   "outputs": [
    ///     "tags": [...],
    ///     "id": "some-service-id",
    ///     "node": "some-node-id",
    ///     "last_seen": "some-date",
    ///     "mechanism": {
    ///       "Output":  {
    ///         "kind": {
    ///           "OnOff": []
    ///         },
    ///         "push": [5000],
    ///         "updated": "some-date",
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    fn get_nodes(&self, &Vec<NodeRequest>) -> Vec<Node>;

    /// Label a set of nodes with a set of tags.
    ///
    /// A call to `API::put_node_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the nodes matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of nodes
    /// matching any of the requests.
    ///
    /// Some of the nodes may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if nodes
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/nodes/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<NodeRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON string representing a number.
    fn put_node_tag(&self, set: &Vec<NodeRequest>, tags: &Vec<String>) -> usize;

    /// Remove a set of tags from a set of nodes.
    ///
    /// A call to `API::delete_node_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the nodes matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of nodes
    /// matching any of the requests.
    ///
    /// Some of the nodes may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if nodes
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/nodes/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<NodeRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn delete_node_tag(&self, set: &Vec<NodeRequest>, tags: String) -> usize;

    /// Get a list of inputs matching some conditions
    ///
    /// # REST API
    ///
    /// `GET /api/v1/services`
    fn get_input_services(&self, &Vec<InputRequest>) -> Vec<Service<Input>>;
    fn get_output_services(&self, &Vec<OutputRequest>) -> Vec<Service<Output>>;

    /// Label a set of services with a set of tags.
    ///
    /// A call to `API::put_{input, output}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the services matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of services
    /// matching any of the requests.
    ///
    /// Some of the services may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `POST /api/v1/services/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<InputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```ignore
    /// {
    ///   set: Vec<OutputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn put_input_tag(&self, &Vec<InputRequest>, &Vec<String>) -> usize;
    fn put_output_tag(&self, &Vec<OutputRequest>, &Vec<String>) -> usize;

    /// Remove a set of tags from a set of services.
    ///
    /// A call to `API::delete_{input, output}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the services matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of services
    /// matching any of the requests.
    ///
    /// Some of the services may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/services/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```ignore
    /// {
    ///   set: Vec<InputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```ignore
    /// {
    ///   set: Vec<OutputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn delete_input_tag(&self, &Vec<InputRequest>, &Vec<String>) -> usize;
    fn delete_output_tag(&self, &Vec<InputRequest>, &Vec<String>) -> usize;

    /// Read the latest value from a set of services
    ///
    /// # REST API
    ///
    /// `GET /api/v1/services/value`
    fn get_service_value(&self, &Vec<InputRequest>) -> Vec<(ServiceId, Result<Value, Error>)>;

    /// Send one value to a set of services
    ///
    /// # REST API
    ///
    /// `POST /api/v1/services/value`
    fn put_service_value(&self, &Vec<OutputRequest>, Value) -> Vec<(ServiceId, Result<(), Error>)>;

    /// Watch for any change
    ///
    /// # WebSocket API
    ///
    /// `/api/v1/services/watch`
    fn register_service_watch(&self, Vec<WatchOptions>, cb: Box<Fn(WatchEvent) + Send + 'static>) -> Self::WatchGuard;

    /// A value that causes a disconnection once it is dropped.
    type WatchGuard;
}

/// Options for watching changes in one or more services.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct WatchOptions {
    /// The set of inputs to watch. Note that the actual inputs in the
    /// set may change over time.
    pub source: InputRequest,

    /// If `true`, watch as new values become available.
    pub should_watch_values: bool,

    /// If `true`, watch as nodes are connected/disconnected.
    pub should_watch_topology: bool,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}

impl WatchOptions {
    pub fn new() -> Self {
        WatchOptions {
            source: InputRequest::new(),
            should_watch_values: false,
            should_watch_topology: false,
            private: (),
        }
    }

    /// Restrict to input services in a given set.
    ///
    /// Also note that the actual input services that are part of the
    /// set may change with time, for instance if devices are added
    /// ore removed.  The request _is live_, i.e. the service watch
    /// will continue watching any input services that match `req`.
    pub fn with_inputs(self, req: InputRequest) -> Self {
        WatchOptions {
            source: self.source.and(req),
            ..self
        }
    }

    pub fn with_watch_values(self, should: bool) -> Self {
        WatchOptions {
            should_watch_values: should,
            ..self
        }
    }

    pub fn with_watch_topology(self, should: bool) -> Self {
        WatchOptions {
            should_watch_topology: should,
            ..self
        }
    }
}
<|endoftext|>


<commit_before>use nom::*;
use std::str;

#[derive(Debug, PartialEq)]
pub struct Paragraph<'a> {
    parts: Vec<Text<'a>>,
}

#[derive(Debug, PartialEq)]
enum Text<'a> {
    Plain(&'a str),
    Bold(Paragraph<'a>),
}

impl<'a> Paragraph<'a> {
    pub fn to_html(&self) -> String {
        self.parts.iter()
            .map(|text| match *text {
                Text::Plain(ref s) => s.to_string(),
                Text::Bold(ref p) => ["", &p.to_html(), ""].concat(),
            })
            .collect::<Vec<_>>()
            .concat()
    }
}

named!(pub parse_paragraph<Paragraph>,
    map!(
        many1!(alt!(plain | bold)),
        |parts| Paragraph {parts: parts}
    )
);

named!(parse_only_paragraph<Paragraph>, complete!(parse_paragraph));

named!(plain<Text>,
    map!(
        map_res!(is_not!("*"), str::from_utf8),
        Text::Plain
    )
);

named!(bold<Text>,
    map_res!(
        delimited!(char!('*'), is_not!("*"), char!('*')),
        |bytes| {
            match parse_only_paragraph(bytes) {
                IResult::Done(_, output) => Ok(Text::Bold(output)),
                IResult::Error(err) => Err(err),
                _ => panic!("Nom complete! macro returned an IResult::Incomplete")
            }
        }
    )
);

#[test]
fn test_plain_parse() {
    if let IResult::Done(input, output) = plain(b"Hello *World*") {
        assert_eq!(input, b"*World*");
        assert_eq!(output, Text::Plain("Hello "));
    } else {
        panic!(r#" Plain parse failed with "Hello *World*" "#);
    }

    match plain(b"*Hello World*") {
        IResult::Error(_) => (),
        _ => panic!(r#" Plain failed with "*Hello World*" "#),
    }
}

#[test]
fn test_bold_parse() {
    if let IResult::Done(input, output) = bold(b"*Hello* World") {
        assert_eq!(input, b" World");
        assert_eq!(output, Text::Bold(Paragraph {
            parts: vec![Text::Plain("Hello")]
        }));
    } else {
        panic!(r#" Bold failed with "*Hello* World" "#);
    }

    match bold(b"Hello World") {
        IResult::Error(_) => (),
        _ => panic!(r#" Bold failed with "Hello World" "#),
    };

    match bold(b"*Hello World") {
        IResult::Incomplete(_) => (),
        _ => panic!(r#" Bold failed with "*Hello World" "#),
    }
}

#[test]
fn test_paragraph_parse() {
    if let IResult::Done(input, output) = parse_paragraph(b"Hello *World*") {
        assert_eq!(input, b"");
        assert_eq!(output.parts, vec![
            Text::Plain("Hello "),
            Text::Bold(Paragraph {parts: vec![Text::Plain("World")]}),
        ]);
    } else {
        panic!(r#" Paragraph parse failed with "Hello *World*" "#);
    }

    if let IResult::Done(input, output) = parse_paragraph(b"*This* *is* *a* *test*") {
        assert_eq!(input, b"");
        assert_eq!(output.parts, vec![
            Text::Bold(Paragraph {parts: vec![Text::Plain("This")]}),
            Text::Plain(" "),
            Text::Bold(Paragraph {parts: vec![Text::Plain("is")]}),
            Text::Plain(" "),
            Text::Bold(Paragraph {parts: vec![Text::Plain("a")]}),
            Text::Plain(" "),
            Text::Bold(Paragraph {parts: vec![Text::Plain("test")]}),
        ]);
    } else {
        panic!(r#" Paragraph parse failed with "Hello *World*" "#);
    }
}

#[test]
fn test_html1() {
    let p = Paragraph { parts: vec![
            Text::Plain("plaintext "),
            Text::Bold(Paragraph { parts: vec![Text::Plain("bold text")]})
    ]};

    assert!(p.to_html() == "plaintext bold text".to_owned());
}
<commit_msg>Add italics parsing<commit_after>use nom::*;
use std::str;

#[derive(Debug, PartialEq)]
pub struct Paragraph<'a> {
    parts: Vec<Text<'a>>,
}

#[derive(Debug, PartialEq)]
enum Text<'a> {
    Plain(&'a str),
    Bold(Paragraph<'a>),
    Italics(Paragraph<'a>),
}

impl<'a> Paragraph<'a> {
    fn new(parts: Vec<Text>) -> Paragraph {
        Paragraph {parts: parts}
    }
    pub fn to_html(&self) -> String {
        self.parts.iter()
            .map(|text| match *text {
                Text::Plain(s)       => s.to_string(),
                Text::Bold(ref p)    => ["", &p.to_html(), ""].concat(),
                Text::Italics(ref p) => ["", &p.to_html(), ""].concat(),
            })
            .collect::<Vec<_>>()
            .concat()
    }
}

named!(pub parse_paragraph<Paragraph>,
    map!(
        many1!(alt!(parse_bold | parse_italics | parse_plain)),
        Paragraph::new
    )
);

named!(parse_only_paragraph<Paragraph>, complete!(parse_paragraph));

named!(parse_plain<Text>,
    map!(
        map_res!(is_not!("_*"), str::from_utf8),
        Text::Plain
    )
);

named!(parse_bold<Text>,
    map_res!(
        delimited!(char!('*'), is_not!("*"), char!('*')),
        |bytes| {
            match parse_only_paragraph(bytes) {
                IResult::Done(_, output) => Ok(Text::Bold(output)),
                IResult::Error(err) => Err(err),
                _ => panic!("Nom complete! macro returned an IResult::Incomplete")
            }
        }
    )
);

named!(parse_italics<Text>,
    map_res!(
        delimited!(char!('_'), is_not!("_"), char!('_')),
        |bytes| {
            match parse_only_paragraph(bytes) {
                IResult::Done(_, output) => Ok(Text::Italics(output)),
                IResult::Error(err) => Err(err),
                _ => panic!("Nom complete! macro returned an IResult::Incomplete")
            }
        }
    )
);

#[test]
fn test_plain_parse() {
    if let IResult::Done(b"*World*", output) = parse_plain(b"Hello *World*") {
        assert_eq!(output, Text::Plain("Hello "));
    } else {
        panic!(r#" Plain parse failed with "Hello *World*" "#);
    }

    match parse_plain(b"*Hello World*") {
        IResult::Error(_) => (),
        _ => panic!(r#" Plain failed with "*Hello World*" "#),
    }
}

#[test]
fn test_bold_parse() {
    if let IResult::Done(b" World", output) = parse_bold(b"*Hello* World") {
        assert_eq!(output, Text::Bold(Paragraph::new(
            vec![Text::Plain("Hello")]
        )));
    } else {
        panic!(r#" Bold failed with "*Hello* World" "#);
    }

    match parse_bold(b"Hello World") {
        IResult::Error(_) => (),
        _ => panic!(r#" Bold failed with "Hello World" "#),
    };

    match parse_bold(b"*Hello World") {
        IResult::Incomplete(_) => (),
        _ => panic!(r#" Bold failed with "*Hello World" "#),
    }
}

#[test]
fn test_paragraph_parse() {
    let data = b"This *is _a_ serious* _test *of* this_ parser";
    if let IResult::Done(remaining, output) = parse_paragraph(data) {
        assert_eq!(remaining, b"");
        println!("{:#?}", output.parts);
        assert_eq!(output.parts, vec![
            Text::Plain("This "),
            Text::Bold(Paragraph::new(vec![
                Text::Plain("is "),
                Text::Italics(Paragraph::new(vec![Text::Plain("a")])),
                Text::Plain(" serious"),
            ])),
            Text::Plain(" "),
            Text::Italics(Paragraph::new(vec![
                Text::Plain("test "),
                Text::Bold(Paragraph::new(vec![Text::Plain("of")])),
                Text::Plain(" this"),
            ])),
            Text::Plain(" parser")
        ]);
    }
}

#[test]
fn test_html1() {
    let p = Paragraph::new(vec![
        Text::Plain("plaintext "),
        Text::Bold(Paragraph::new(vec![Text::Plain("bold text")]))
    ]);

    assert!(p.to_html() == "plaintext bold text".to_owned());
}
<|endoftext|>


<commit_before>use error::*;
use super::Command;

extern crate chrono;
extern crate regex;

use lib::fs::*;
use lib::io::*;
use lib::setting::*;
use self::chrono::offset::TimeZone;
use self::chrono::{Duration, Local};
use self::regex::Regex;
use std::io::Error as IoError;
use std::path::PathBuf;

pub struct Burn;

impl Command for Burn {
    fn validation(&self) -> bool { true }

    fn usage(&self) -> Usage {
        return Usage::new(UsageKind::Burn);
    }

    fn main(&self) -> Result<(), CliError> {
        let moratorium  = try!(Self::read_param_for_burn());
        let target_dirs = try!(Self::search_target_storages(moratorium));
        for dir in &target_dirs {
            try!(delete_dir_all(dir));
        };

        Ok(())
    }
}

impl Burn {
    fn read_param_for_burn() -> Result<Duration, CliError> {
        let config = try!(read_config_file());
        let key    = "burn.after";

        print_with_tag(0, Tag::Execution, format!("Extract \"{}\" parameter", key));

        let after = try!(config.lookup(key).ok_or(ConfigError::new(ConfigErrorKind::NotFoundBurnAfter))).to_string();

        let re = try!(Regex::new(r"(?P<num>\d+)\s*(?P<unit>days?|weeks?)"));
        let (num, unit) = match re.captures(after.as_ref()).map(|caps| (caps.name("num"), caps.name("unit"))) {
            Some((Some(num), Some(unit))) => (num, unit),
            Some((None     , Some(_)   )) => return Err(From::from(ConfigError::new(ConfigErrorKind::NumOfBurnAfter))),
            Some((Some(_)  , None      )) => return Err(From::from(ConfigError::new(ConfigErrorKind::UnitOfBurnAfter))),
            _                             => return Err(From::from(ConfigError::new(ConfigErrorKind::BurnAfter))),
        };
        let num = try!(num.parse::<u32>());

        let duration = match unit {
            "day"  | "days"  => Duration::days(num as i64),
            "week" | "weeks" => Duration::weeks(num as i64),
            _                => return Err(From::from(CannotHappenError)),
        };

        print_with_okay(1);
        Ok(duration)
    }

    fn search_target_storages(moratorium: Duration) -> Result<Vec<PathBuf>, IoError> {
        print_with_tag(0, Tag::Execution, "Search target dusts");

        let path_to_storage = storage_dir();
        let dirs            = try!(ls(&path_to_storage));
        let today           = Local::now();

        let targets = dirs
            .into_iter()
            .filter(|date| match Local.datetime_from_str(format!("{} 00:00:00", date).as_ref(), "%Y-%m-%d %H:%M:%S") {
                Ok(created_date) => created_date + moratorium < today,
                Err(_)           => false,
            })
            .map(|dir| path_to_storage.join(dir))
            .collect::<Vec<PathBuf>>();

        print_with_okay(1);
        Ok(targets)
    }
}
<commit_msg>[Comment] Add a minor comment<commit_after>use error::*;
use super::Command;

extern crate chrono;
extern crate regex;

use lib::fs::*;
use lib::io::*;
use lib::setting::*;
use self::chrono::offset::TimeZone;
use self::chrono::{Duration, Local};
use self::regex::Regex;
use std::io::Error as IoError;
use std::path::PathBuf;

pub struct Burn;

impl Command for Burn {
    fn validation(&self) -> bool { true }

    fn usage(&self) -> Usage {
        return Usage::new(UsageKind::Burn);
    }

    fn main(&self) -> Result<(), CliError> {
        let moratorium  = try!(Self::read_param_for_burn());
        let target_dirs = try!(Self::search_target_storages(moratorium));
        for dir in &target_dirs {
            try!(delete_dir_all(dir));
        };

        Ok(())
    }
}

impl Burn {
    fn read_param_for_burn() -> Result<Duration, CliError> {
        let config = try!(read_config_file());
        let key    = "burn.after";

        print_with_tag(0, Tag::Execution, format!("Extract \"{}\" parameter", key));

        // This to_string() is not documented.
        let after = try!(config.lookup(key).ok_or(ConfigError::new(ConfigErrorKind::NotFoundBurnAfter))).to_string();

        let re = try!(Regex::new(r"(?P<num>\d+)\s*(?P<unit>days?|weeks?)"));
        let (num, unit) = match re.captures(after.as_ref()).map(|caps| (caps.name("num"), caps.name("unit"))) {
            Some((Some(num), Some(unit))) => (num, unit),
            Some((None     , Some(_)   )) => return Err(From::from(ConfigError::new(ConfigErrorKind::NumOfBurnAfter))),
            Some((Some(_)  , None      )) => return Err(From::from(ConfigError::new(ConfigErrorKind::UnitOfBurnAfter))),
            _                             => return Err(From::from(ConfigError::new(ConfigErrorKind::BurnAfter))),
        };
        let num = try!(num.parse::<u32>());

        let duration = match unit {
            "day"  | "days"  => Duration::days(num as i64),
            "week" | "weeks" => Duration::weeks(num as i64),
            _                => return Err(From::from(CannotHappenError)),
        };

        print_with_okay(1);
        Ok(duration)
    }

    fn search_target_storages(moratorium: Duration) -> Result<Vec<PathBuf>, IoError> {
        print_with_tag(0, Tag::Execution, "Search target dusts");

        let path_to_storage = storage_dir();
        let dirs            = try!(ls(&path_to_storage));
        let today           = Local::now();

        let targets = dirs
            .into_iter()
            .filter(|date| match Local.datetime_from_str(format!("{} 00:00:00", date).as_ref(), "%Y-%m-%d %H:%M:%S") {
                Ok(created_date) => created_date + moratorium < today,
                Err(_)           => false,
            })
            .map(|dir| path_to_storage.join(dir))
            .collect::<Vec<PathBuf>>();

        print_with_okay(1);
        Ok(targets)
    }
}
<|endoftext|>


<commit_before>use {Field, Matrix2d, Rectangle};
use {Transform2d};
use {Borrowed, Value};
use vecmath::{translate, multiply, rotate_radians, scale, shear};

/// An ellipse context.
pub struct EllipseContext<'a> {
    /// Base/origin transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
    /// Current rectangle enclosing the ellipse.
    pub rect: Field<'a, Rectangle>,
}

impl<'a> Transform2d<'a> for EllipseContext<'a> {
    #[inline(always)]
    fn trans(&'a self, x: f64, y: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let trans = translate(x, y);
                Value(multiply(&trans, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn rot_rad(&'a self, angle: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let rot = rotate_radians(angle);
                Value(multiply(&rot, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn scale(&'a self, sx: f64, sy: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let scale = scale(sx, sy);
                Value(multiply(&scale, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn shear(&'a self, sx: f64, sy: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let shear = shear(sx, sy);
                Value(multiply(&shear, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }
}

<commit_msg>Implemented AddColor for EllipseContext<commit_after>use {Field, Matrix2d, Rectangle};
use {Transform2d};
use {Borrowed, Value};
use vecmath::{translate, multiply, rotate_radians, scale, shear};
use {AddColor};
use {EllipseColorContext};

/// An ellipse context.
pub struct EllipseContext<'a> {
    /// Base/origin transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
    /// Current rectangle enclosing the ellipse.
    pub rect: Field<'a, Rectangle>,
}

impl<'a> Transform2d<'a> for EllipseContext<'a> {
    #[inline(always)]
    fn trans(&'a self, x: f64, y: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let trans = translate(x, y);
                Value(multiply(&trans, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn rot_rad(&'a self, angle: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let rot = rotate_radians(angle);
                Value(multiply(&rot, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn scale(&'a self, sx: f64, sy: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let scale = scale(sx, sy);
                Value(multiply(&scale, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn shear(&'a self, sx: f64, sy: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let shear = shear(sx, sy);
                Value(multiply(&shear, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }
}

impl<'a> AddColor<'a, EllipseColorContext<'a>> for EllipseContext<'a> {
    #[inline(always)]
    fn rgba(&'a self, r: f32, g: f32, b: f32, a: f32) -> EllipseColorContext<'a> {
        EllipseColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.transform.get()),
            rect: Borrowed(self.rect.get()),
            color: Value([r, g, b, a]),
        }
    }
}

<|endoftext|>


<commit_before>use std::sync::Arc;
use rand::{Rng, XorShiftRng, SeedableRng};
use test::Bencher;
use player::Player;
use zobrist::Zobrist;
use field;
use field::{Pos, Field};

fn random_game(bencher: &mut Bencher, width: u32, height: u32, seed_array: [u32; 4]) {
  let mut rng = XorShiftRng::from_seed(seed_array);
  let mut moves = (field::min_pos(width) .. field::max_pos(width, height) + 1).collect::<Vec<Pos>>();
  rng.shuffle(&mut moves);
  let zobrist = Arc::new(Zobrist::new(field::length(width, height) * 2, &mut rng));
  bencher.iter(|| {
    let mut field = Field::new(width, height, zobrist.clone());
    let mut player = Player::Red;
    for &pos in &moves {
      if field.is_putting_allowed(pos) {
        field.put_point(pos, player);
        player = player.next();
      }
    }
    field
  });
}

#[bench]
fn random_game_1(bencher: &mut Bencher) {
  random_game(bencher, 100, 100, [3, 1, 7, 5]);
}

#[bench]
fn random_game_2(bencher: &mut Bencher) {
  random_game(bencher, 100, 100, [1, 3, 5, 7]);
}

#[bench]
fn random_game_3(bencher: &mut Bencher) {
  random_game(bencher, 100, 100, [7, 1, 3, 5]);
}
<commit_msg>Add undo to benchmarks.<commit_after>use std::sync::Arc;
use rand::{Rng, XorShiftRng, SeedableRng};
use test::Bencher;
use player::Player;
use zobrist::Zobrist;
use field;
use field::{Pos, Field};

fn random_game(bencher: &mut Bencher, width: u32, height: u32, seed_array: [u32; 4]) {
  let mut rng = XorShiftRng::from_seed(seed_array);
  let mut moves = (field::min_pos(width) .. field::max_pos(width, height) + 1).collect::<Vec<Pos>>();
  rng.shuffle(&mut moves);
  let zobrist = Arc::new(Zobrist::new(field::length(width, height) * 2, &mut rng));
  bencher.iter(|| {
    let mut field = Field::new(width, height, zobrist.clone());
    let mut player = Player::Red;
    for &pos in &moves {
      if field.is_putting_allowed(pos) {
        field.put_point(pos, player);
        player = player.next();
      }
    }
    for _ in 0 .. field.moves_count() {
      field.undo();
    }
    field
  });
}

#[bench]
fn random_game_1(bencher: &mut Bencher) {
  random_game(bencher, 100, 100, [3, 1, 7, 5]);
}

#[bench]
fn random_game_2(bencher: &mut Bencher) {
  random_game(bencher, 100, 100, [1, 3, 5, 7]);
}

#[bench]
fn random_game_3(bencher: &mut Bencher) {
  random_game(bencher, 100, 100, [7, 1, 3, 5]);
}
<|endoftext|>