<commit_before>use euclid::{Point2D, Rect};
use calx_resource::Resource;
use scancode::Scancode;
use world::{Location, Portal, World};
use sprite::Sprite;
use vitral;
use backend;
use view;
use render;

enum PaintMode {
    Terrain(u8, u8),
    Portal,
}

/// Top-level application state for gameplay.
pub struct GameView {
    pub world: World,
    mode: PaintMode,
    /// Camera and second camera (for portaling)
    camera: (Location, Location),
    /// Do the two cameras move together?
    camera_lock: bool,
}

impl GameView {
    pub fn new(world: World) -> GameView {
        GameView {
            world: world,
            mode: PaintMode::Terrain(7, 2),
            camera: (Location::new(0, 0, 0), Location::new(0, 8, 0)),
            camera_lock: false,
        }
    }

    pub fn draw(&mut self, context: &mut backend::Context, screen_area: &Rect<f32>) {
        // TODO: Camera logic
        let camera_loc = self.camera.0;

        let center = screen_area.origin + screen_area.size / 2.0;

        // Chart area, center in origin, inflated by tile width in every direction to get the cells
        // partially on screen included.
        let bounds = screen_area.translate(&-(center + screen_area.origin))
                                .inflate(view::PIXEL_UNIT * 2.0, view::PIXEL_UNIT * 2.0);

        context.ui.set_clip_rect(Some(*screen_area));

        let chart = view::screen_fov(&self.world, camera_loc, bounds);

        let mut sprites = Vec::new();

        let cursor_pos = view::view_to_chart(context.ui.mouse_pos() - center);

        for (&chart_pos, origins) in &chart {
            assert!(!origins.is_empty());

            let loc = origins[0] + chart_pos;

            let screen_pos = view::chart_to_view(chart_pos) + center;

            // TODO: Set up dynamic lighting, shade sprites based on angle and local light.
            render::draw_terrain_sprites(&self.world, loc, |layer, _angle, brush, frame_idx| {
                sprites.push(Sprite {
                    layer: layer,
                    offset: [screen_pos.x as i32, screen_pos.y as i32],
                    brush: brush.clone(),
                    frame_idx: frame_idx,
                })
            });
            if self.world.portal(loc).is_some() {
                let screen_pos = screen_pos -
                                 Point2D::new(view::PIXEL_UNIT, view::PIXEL_UNIT);
                sprites.push(Sprite {
                    layer: render::Layer::Decal,
                    offset: [screen_pos.x as i32, screen_pos.y as i32],
                    brush: Resource::new("portal".to_string()).unwrap(),
                    frame_idx: 0,
                });
            }
        }

        if let Some(origins) = chart.get(&cursor_pos) {
            let screen_pos = view::chart_to_view(cursor_pos) + center -
                             Point2D::new(view::PIXEL_UNIT, view::PIXEL_UNIT);
            // Always portal in root coordinates.
            // TODO: It's currently not obvious from UI what the root coordinates are.
            let portal_loc = origins[origins.len() - 1] + cursor_pos;
            let loc = origins[0] + cursor_pos;

            sprites.push(Sprite {
                layer: render::Layer::Decal,
                offset: [screen_pos.x as i32, screen_pos.y as i32],
                brush: Resource::new("cursor".to_string()).unwrap(),
                frame_idx: 0,
            });
            sprites.push(Sprite {
                layer: render::Layer::Effect,
                offset: [screen_pos.x as i32, screen_pos.y as i32],
                brush: Resource::new("cursor_top".to_string()).unwrap(),
                frame_idx: 0,
            });

            match self.mode {
                PaintMode::Terrain(draw, erase) => {
                    if context.ui.is_mouse_pressed(vitral::MouseButton::Left) {
                        self.world.terrain.set(loc, draw);
                    }

                    if context.ui.is_mouse_pressed(vitral::MouseButton::Right) {
                        self.world.terrain.set(loc, erase);
                    }
                }

                PaintMode::Portal => {
                    let (a, b) = self.camera;
                    if a != b && context.ui.is_mouse_pressed(vitral::MouseButton::Left) {
                        self.world.set_portal(portal_loc, Portal::new(a, b));
                    }
                    if context.ui.is_mouse_pressed(vitral::MouseButton::Right) {
                        self.world.remove_portal(portal_loc);
                    }
                }
            }

        }

        sprites.sort();

        for i in &sprites {
            i.draw(&mut context.ui)
        }

        if context.ui.button("draw void") {
            self.mode = PaintMode::Terrain(0, 2);
        }

        if context.ui.button("draw gate") {
            self.mode = PaintMode::Terrain(1, 2);
        }

        if context.ui.button("draw wall") {
            self.mode = PaintMode::Terrain(6, 2);
        }

        if context.ui.button("draw rock") {
            self.mode = PaintMode::Terrain(7, 2);
        }

        if context.ui.button("PORTALS!") {
            self.mode = PaintMode::Portal;
        }

        for (y, origin) in chart.get(&cursor_pos).unwrap_or(&Vec::new()).iter().enumerate() {
            let font = context.ui.default_font();
            let loc = *origin + cursor_pos;
            context.ui.draw_text(font, Point2D::new(400.0, y as f32 * 20.0 + 20.0), [1.0, 1.0, 1.0, 1.0],
                &format!("{:?}", loc));
        }

        context.ui.set_clip_rect(None);

        if let Some(scancode) = context.backend.poll_key().and_then(|k| Scancode::new(k.scancode)) {
            use scancode::Scancode::*;
            match scancode {
                Q => self.move_camera(Point2D::new(-1, 0)),
                W => self.move_camera(Point2D::new(-1, -1)),
                E => self.move_camera(Point2D::new(0, -1)),
                A => self.move_camera(Point2D::new(0, 1)),
                S => self.move_camera(Point2D::new(1, 1)),
                D => self.move_camera(Point2D::new(1, 0)),
                Tab => self.switch_camera(),
                _ => {}
            }
        }
    }

    fn move_camera(&mut self, delta: Point2D<i32>) {
        let second_delta = if self.camera_lock {
            delta
        } else {
            Point2D::new(0, 0)
        };

        let (a, b) = self.camera;
        self.camera = (a + delta, b + second_delta);
    }

    fn switch_camera(&mut self) {
        let (a, b) = self.camera;
        self.camera = (b, a);
    }
}
<commit_msg>Camera z movement in mapedit<commit_after>use std::num::Wrapping;
use euclid::{Point2D, Rect};
use calx_resource::Resource;
use scancode::Scancode;
use world::{Location, Portal, World};
use sprite::Sprite;
use vitral;
use backend;
use view;
use render;

enum PaintMode {
    Terrain(u8, u8),
    Portal,
}

/// Top-level application state for gameplay.
pub struct GameView {
    pub world: World,
    mode: PaintMode,
    /// Camera and second camera (for portaling)
    camera: (Location, Location),
    /// Do the two cameras move together?
    camera_lock: bool,
}

impl GameView {
    pub fn new(world: World) -> GameView {
        GameView {
            world: world,
            mode: PaintMode::Terrain(7, 2),
            camera: (Location::new(0, 0, 0), Location::new(0, 8, 0)),
            camera_lock: false,
        }
    }

    pub fn draw(&mut self, context: &mut backend::Context, screen_area: &Rect<f32>) {
        // TODO: Camera logic
        let camera_loc = self.camera.0;

        let center = screen_area.origin + screen_area.size / 2.0;

        // Chart area, center in origin, inflated by tile width in every direction to get the cells
        // partially on screen included.
        let bounds = screen_area.translate(&-(center + screen_area.origin))
                                .inflate(view::PIXEL_UNIT * 2.0, view::PIXEL_UNIT * 2.0);

        context.ui.set_clip_rect(Some(*screen_area));

        let chart = view::screen_fov(&self.world, camera_loc, bounds);

        let mut sprites = Vec::new();

        let cursor_pos = view::view_to_chart(context.ui.mouse_pos() - center);

        for (&chart_pos, origins) in &chart {
            assert!(!origins.is_empty());

            let loc = origins[0] + chart_pos;

            let screen_pos = view::chart_to_view(chart_pos) + center;

            // TODO: Set up dynamic lighting, shade sprites based on angle and local light.
            render::draw_terrain_sprites(&self.world, loc, |layer, _angle, brush, frame_idx| {
                sprites.push(Sprite {
                    layer: layer,
                    offset: [screen_pos.x as i32, screen_pos.y as i32],
                    brush: brush.clone(),
                    frame_idx: frame_idx,
                })
            });

            for &origin in origins {
                if self.world.portal(origin + chart_pos).is_some() {
                    let screen_pos = screen_pos -
                                     Point2D::new(view::PIXEL_UNIT, view::PIXEL_UNIT);
                    sprites.push(Sprite {
                        layer: render::Layer::Decal,
                        offset: [screen_pos.x as i32, screen_pos.y as i32],
                        brush: Resource::new("portal".to_string()).unwrap(),
                        frame_idx: 0,
                    });
                    break;
                }
            }
        }

        if let Some(origins) = chart.get(&cursor_pos) {
            let screen_pos = view::chart_to_view(cursor_pos) + center -
                             Point2D::new(view::PIXEL_UNIT, view::PIXEL_UNIT);
            // Always portal in root coordinates.
            // TODO: It's currently not obvious from UI what the root coordinates are.
            let portal_loc = origins[origins.len() - 1] + cursor_pos;
            let loc = origins[0] + cursor_pos;

            sprites.push(Sprite {
                layer: render::Layer::Decal,
                offset: [screen_pos.x as i32, screen_pos.y as i32],
                brush: Resource::new("cursor".to_string()).unwrap(),
                frame_idx: 0,
            });
            sprites.push(Sprite {
                layer: render::Layer::Effect,
                offset: [screen_pos.x as i32, screen_pos.y as i32],
                brush: Resource::new("cursor_top".to_string()).unwrap(),
                frame_idx: 0,
            });

            match self.mode {
                PaintMode::Terrain(draw, erase) => {
                    if context.ui.is_mouse_pressed(vitral::MouseButton::Left) {
                        self.world.terrain.set(loc, draw);
                    }

                    if context.ui.is_mouse_pressed(vitral::MouseButton::Right) {
                        self.world.terrain.set(loc, erase);
                    }
                }

                PaintMode::Portal => {
                    let (a, b) = self.camera;
                    if a != b && context.ui.is_mouse_pressed(vitral::MouseButton::Left) {
                        self.world.set_portal(portal_loc, Portal::new(a, b));
                    }
                    if context.ui.is_mouse_pressed(vitral::MouseButton::Right) {
                        self.world.remove_portal(portal_loc);
                    }
                }
            }

        }

        sprites.sort();

        for i in &sprites {
            i.draw(&mut context.ui)
        }

        if context.ui.button("draw void") {
            self.mode = PaintMode::Terrain(0, 2);
        }

        if context.ui.button("draw gate") {
            self.mode = PaintMode::Terrain(1, 2);
        }

        if context.ui.button("draw wall") {
            self.mode = PaintMode::Terrain(6, 2);
        }

        if context.ui.button("draw rock") {
            self.mode = PaintMode::Terrain(7, 2);
        }

        if context.ui.button("PORTALS!") {
            self.mode = PaintMode::Portal;
        }

        for (y, origin) in chart.get(&cursor_pos).unwrap_or(&Vec::new()).iter().enumerate() {
            let font = context.ui.default_font();
            let loc = *origin + cursor_pos;
            context.ui.draw_text(font, Point2D::new(400.0, y as f32 * 20.0 + 20.0), [1.0, 1.0, 1.0, 1.0],
                &format!("{:?}", loc));
        }

        context.ui.set_clip_rect(None);

        if let Some(scancode) = context.backend.poll_key().and_then(|k| Scancode::new(k.scancode)) {
            use scancode::Scancode::*;
            match scancode {
                Q => self.move_camera(Point2D::new(-1, 0), 0),
                W => self.move_camera(Point2D::new(-1, -1), 0),
                E => self.move_camera(Point2D::new(0, -1), 0),
                A => self.move_camera(Point2D::new(0, 1), 0),
                S => self.move_camera(Point2D::new(1, 1), 0),
                D => self.move_camera(Point2D::new(1, 0), 0),
                Tab => self.switch_camera(),
                RightBracket => self.move_camera(Point2D::new(0, 0), 1),
                LeftBracket => self.move_camera(Point2D::new(0, 0), -1),
                _ => {}
            }
        }
    }

    fn move_camera(&mut self, delta: Point2D<i32>, dz: i8) {
        let second_delta = if self.camera_lock {
            delta
        } else {
            Point2D::new(0, 0)
        };

        let (a, b) = self.camera;
        self.camera = (a + delta, b + second_delta);

        let z0 = Wrapping(self.camera.0.z) + Wrapping(dz);
        let z1 = Wrapping(self.camera.1.z) + Wrapping(if self.camera_lock { dz } else { 0 });

        self.camera.0.z = z0.0;
        self.camera.1.z = z1.0;
    }

    fn switch_camera(&mut self) {
        let (a, b) = self.camera;
        self.camera = (b, a);
    }
}
<|endoftext|>


<commit_before>
pub mod opnorm;
pub mod qr;
pub mod svd;

pub use self::opnorm::*;
pub use self::qr::*;
pub use self::svd::*;

pub trait LapackScalar: OperatorNorm_ + QR_ + SVD_ {}
impl<A> LapackScalar for A where A: OperatorNorm_ + QR_ + SVD_ {}
<commit_msg>Add into_result<commit_after>
pub mod opnorm;
pub mod qr;
pub mod svd;

pub use self::opnorm::*;
pub use self::qr::*;
pub use self::svd::*;

use super::error::*;

pub trait LapackScalar: OperatorNorm_ + QR_ + SVD_ {}
impl<A> LapackScalar for A where A: OperatorNorm_ + QR_ + SVD_ {}

pub fn into_result<T>(info: i32, val: T) -> Result<T> {
    if info == 0 {
        Ok(val)
    } else {
        Err(LapackError::new(info).into())
    }
}
<|endoftext|>


<commit_before>//! Intermediate representation for the physical layout of some type.

use super::derive::{CanTriviallyDeriveCopy, CanTriviallyDeriveDebug,
                    CanTriviallyDeriveDefault, CanTriviallyDeriveHash,
                    CanTriviallyDerivePartialEqOrPartialOrd, CanDerive};
use super::ty::{RUST_DERIVE_IN_ARRAY_LIMIT, Type, TypeKind};
use ir::context::BindgenContext;
use clang;
use std::cmp;

/// A type that represents the struct layout of a type.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Layout {
    /// The size (in bytes) of this layout.
    pub size: usize,
    /// The alignment (in bytes) of this layout.
    pub align: usize,
    /// Whether this layout's members are packed or not.
    pub packed: bool,
}

#[test]
fn test_layout_for_size() {
    use std::mem;

    let ptr_size = mem::size_of::<*mut ()>();
    assert_eq!(
        Layout::for_size_internal(ptr_size, ptr_size),
        Layout::new(ptr_size, ptr_size)
    );
    assert_eq!(
        Layout::for_size_internal(ptr_size, 3 * ptr_size),
        Layout::new(3 * ptr_size, ptr_size)
    );
}

impl Layout {
    /// Construct a new `Layout` with the given `size` and `align`. It is not
    /// packed.
    pub fn new(size: usize, align: usize) -> Self {
        Layout {
            size,
            align,
            packed: false,
        }
    }

    fn for_size_internal(ptr_size: usize, size: usize) -> Self {
        let mut next_align = 2;
        while size % next_align == 0 && next_align <= ptr_size {
            next_align *= 2;
        }
        Layout {
            size: size,
            align: next_align / 2,
            packed: false,
        }
    }

    /// Creates a non-packed layout for a given size, trying to use the maximum
    /// alignment possible.
    pub fn for_size(ctx: &BindgenContext, size: usize) -> Self {
        Self::for_size_internal(ctx.target_pointer_size(), size)
    }

    /// Is this a zero-sized layout?
    pub fn is_zero(&self) -> bool {
        self.size == 0 && self.align == 0
    }

    /// Construct a zero-sized layout.
    pub fn zero() -> Self {
        Self::new(0, 0)
    }

    /// Get this layout as an opaque type.
    pub fn opaque(&self) -> Opaque {
        Opaque(*self)
    }
}

/// When we are treating a type as opaque, it is just a blob with a `Layout`.
#[derive(Clone, Debug, PartialEq)]
pub struct Opaque(pub Layout);

impl Opaque {
    /// Construct a new opaque type from the given clang type.
    pub fn from_clang_ty(ty: &clang::Type) -> Type {
        let layout = Layout::new(ty.size(), ty.align());
        let ty_kind = TypeKind::Opaque;
        Type::new(None, Some(layout), ty_kind, false)
    }

    /// Return the known rust type we should use to create a correctly-aligned
    /// field with this layout.
    pub fn known_rust_type_for_array(&self) -> Option<&'static str> {
        Some(match self.0.align {
            8 => "u64",
            4 => "u32",
            2 => "u16",
            1 => "u8",
            _ => return None,
        })
    }

    /// Return the array size that an opaque type for this layout should have if
    /// we know the correct type for it, or `None` otherwise.
    pub fn array_size(&self) -> Option<usize> {
        if self.known_rust_type_for_array().is_some() {
            Some(self.0.size / cmp::max(self.0.align, 1))
        } else {
            None
        }
    }

    /// Return `true` if this opaque layout's array size will fit within the
    /// maximum number of array elements that Rust allows deriving traits
    /// with. Return `false` otherwise.
    pub fn array_size_within_derive_limit(&self) -> bool {
        self.array_size().map_or(false, |size| {
            size <= RUST_DERIVE_IN_ARRAY_LIMIT
        })
    }
}

impl CanTriviallyDeriveDebug for Opaque {
    fn can_trivially_derive_debug(&self) -> bool {
        self.array_size_within_derive_limit()
    }
}

impl CanTriviallyDeriveDefault for Opaque {
    fn can_trivially_derive_default(&self) -> bool {
        self.array_size_within_derive_limit()
    }
}

impl CanTriviallyDeriveCopy for Opaque {
    fn can_trivially_derive_copy(&self) -> bool {
        self.array_size_within_derive_limit()
    }
}

impl CanTriviallyDeriveHash for Opaque {
    fn can_trivially_derive_hash(&self) -> bool {
        self.array_size_within_derive_limit()
    }
}

impl CanTriviallyDerivePartialEqOrPartialOrd for Opaque {
    fn can_trivially_derive_partialeq_or_partialord(&self) -> CanDerive {
        self.array_size().map_or(CanDerive::No, |size| {
            if size <= RUST_DERIVE_IN_ARRAY_LIMIT {
                CanDerive::Yes
            } else {
                CanDerive::ArrayTooLarge
            }
        })
    }
}
<commit_msg>ir: Make Opaque types respect constness appropriately.<commit_after>//! Intermediate representation for the physical layout of some type.

use super::derive::{CanTriviallyDeriveCopy, CanTriviallyDeriveDebug,
                    CanTriviallyDeriveDefault, CanTriviallyDeriveHash,
                    CanTriviallyDerivePartialEqOrPartialOrd, CanDerive};
use super::ty::{RUST_DERIVE_IN_ARRAY_LIMIT, Type, TypeKind};
use ir::context::BindgenContext;
use clang;
use std::cmp;

/// A type that represents the struct layout of a type.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Layout {
    /// The size (in bytes) of this layout.
    pub size: usize,
    /// The alignment (in bytes) of this layout.
    pub align: usize,
    /// Whether this layout's members are packed or not.
    pub packed: bool,
}

#[test]
fn test_layout_for_size() {
    use std::mem;

    let ptr_size = mem::size_of::<*mut ()>();
    assert_eq!(
        Layout::for_size_internal(ptr_size, ptr_size),
        Layout::new(ptr_size, ptr_size)
    );
    assert_eq!(
        Layout::for_size_internal(ptr_size, 3 * ptr_size),
        Layout::new(3 * ptr_size, ptr_size)
    );
}

impl Layout {
    /// Construct a new `Layout` with the given `size` and `align`. It is not
    /// packed.
    pub fn new(size: usize, align: usize) -> Self {
        Layout {
            size,
            align,
            packed: false,
        }
    }

    fn for_size_internal(ptr_size: usize, size: usize) -> Self {
        let mut next_align = 2;
        while size % next_align == 0 && next_align <= ptr_size {
            next_align *= 2;
        }
        Layout {
            size: size,
            align: next_align / 2,
            packed: false,
        }
    }

    /// Creates a non-packed layout for a given size, trying to use the maximum
    /// alignment possible.
    pub fn for_size(ctx: &BindgenContext, size: usize) -> Self {
        Self::for_size_internal(ctx.target_pointer_size(), size)
    }

    /// Is this a zero-sized layout?
    pub fn is_zero(&self) -> bool {
        self.size == 0 && self.align == 0
    }

    /// Construct a zero-sized layout.
    pub fn zero() -> Self {
        Self::new(0, 0)
    }

    /// Get this layout as an opaque type.
    pub fn opaque(&self) -> Opaque {
        Opaque(*self)
    }
}

/// When we are treating a type as opaque, it is just a blob with a `Layout`.
#[derive(Clone, Debug, PartialEq)]
pub struct Opaque(pub Layout);

impl Opaque {
    /// Construct a new opaque type from the given clang type.
    pub fn from_clang_ty(ty: &clang::Type) -> Type {
        let layout = Layout::new(ty.size(), ty.align());
        let ty_kind = TypeKind::Opaque;
        let is_const = ty.is_const();
        Type::new(None, Some(layout), ty_kind, is_const)
    }

    /// Return the known rust type we should use to create a correctly-aligned
    /// field with this layout.
    pub fn known_rust_type_for_array(&self) -> Option<&'static str> {
        Some(match self.0.align {
            8 => "u64",
            4 => "u32",
            2 => "u16",
            1 => "u8",
            _ => return None,
        })
    }

    /// Return the array size that an opaque type for this layout should have if
    /// we know the correct type for it, or `None` otherwise.
    pub fn array_size(&self) -> Option<usize> {
        if self.known_rust_type_for_array().is_some() {
            Some(self.0.size / cmp::max(self.0.align, 1))
        } else {
            None
        }
    }

    /// Return `true` if this opaque layout's array size will fit within the
    /// maximum number of array elements that Rust allows deriving traits
    /// with. Return `false` otherwise.
    pub fn array_size_within_derive_limit(&self) -> bool {
        self.array_size().map_or(false, |size| {
            size <= RUST_DERIVE_IN_ARRAY_LIMIT
        })
    }
}

impl CanTriviallyDeriveDebug for Opaque {
    fn can_trivially_derive_debug(&self) -> bool {
        self.array_size_within_derive_limit()
    }
}

impl CanTriviallyDeriveDefault for Opaque {
    fn can_trivially_derive_default(&self) -> bool {
        self.array_size_within_derive_limit()
    }
}

impl CanTriviallyDeriveCopy for Opaque {
    fn can_trivially_derive_copy(&self) -> bool {
        self.array_size_within_derive_limit()
    }
}

impl CanTriviallyDeriveHash for Opaque {
    fn can_trivially_derive_hash(&self) -> bool {
        self.array_size_within_derive_limit()
    }
}

impl CanTriviallyDerivePartialEqOrPartialOrd for Opaque {
    fn can_trivially_derive_partialeq_or_partialord(&self) -> CanDerive {
        self.array_size().map_or(CanDerive::No, |size| {
            if size <= RUST_DERIVE_IN_ARRAY_LIMIT {
                CanDerive::Yes
            } else {
                CanDerive::ArrayTooLarge
            }
        })
    }
}
<|endoftext|>


<commit_before>//! Unix terminal formatter and drain for slog-rs
//!
//! ```
//! #[macro_use]
//! extern crate slog;
//! extern crate slog_term;
//!
//! use slog::*;
//!
//! fn main() {
//!     let root = Logger::root(slog_term::streamer().build().fuse(), o!("build-id" => "8dfljdf"));
//! }
//! ```
#![warn(missing_docs)]

#[macro_use]
extern crate slog;
extern crate slog_stream;
extern crate isatty;
extern crate ansi_term;
extern crate chrono;

use std::{io, fmt, sync};

use ansi_term::Colour;
use isatty::{stderr_isatty, stdout_isatty};

use slog::Record;
use slog::ser;
use slog::{Level, OwnedKeyValueList};
use slog_stream::Format as StreamFormat;
use slog_stream::{Decorator, RecordDecorator, Streamer, AsyncStreamer};

/// Formatting mode
enum FormatMode {
    /// Compact logging format
    Compact,
    /// Full logging format
    Full,
}

/// Full formatting with optional color support
pub struct Format<D: Decorator> {
    mode: FormatMode,
    decorator: D,
    history: sync::Mutex<Vec<usize>>,
    fn_timestamp: Box<Fn() -> String + Send + Sync>,
}

impl<D: Decorator> Format<D> {
    /// New Format format that prints using color
    fn new(mode: FormatMode, d: D, fn_timestamp: Box<Fn() -> String + Send + Sync>) -> Self {
        Format {
            decorator: d,
            mode: mode,
            history: sync::Mutex::new(vec![]),
            fn_timestamp: fn_timestamp,
        }
    }

    fn print_msg_header(&self,
                        io: &mut io::Write,
                        rd: &D::RecordDecorator,
                        info: &Record)
                        -> io::Result<()> {
        try!(rd.fmt_timestamp(io, format_args!("{} ", (self.fn_timestamp)())));
        try!(rd.fmt_level(io, format_args!("{} ", info.level().as_short_str())));

        try!(rd.fmt_msg(io, format_args!("{}", info.msg())));
        Ok(())
    }
    fn format_full(&self,
                   io: &mut io::Write,
                   info: &Record,
                   logger_values: &OwnedKeyValueList)
                   -> io::Result<()> {

        let r_decorator = self.decorator.decorate(info);

        try!(self.print_msg_header(io, &r_decorator, info));
        let mut serializer = Serializer::new(io, r_decorator);

        for &(ref k, ref v) in logger_values.iter() {
            try!(serializer.print_comma());
            try!(v.serialize(info, k, &mut serializer));
        }

        for &(k, v) in info.values() {
            try!(serializer.print_comma());
            try!(v.serialize(info, k, &mut serializer));
        }
        let (mut io, _decorator_r) = serializer.finish();

        let _ = try!(write!(io, "\n"));

        Ok(())
    }

    fn format_compact(&self,
                      io: &mut io::Write,
                      info: &Record,
                      logger_values: &OwnedKeyValueList)
                      -> io::Result<()> {

        let r_decorator = self.decorator.decorate(info);
        let mut ser = Serializer::new(io, r_decorator);

        let indent = try!(self.format_recurse(&mut ser, info, logger_values));

        try!(self.print_indent(&mut ser.io, indent));

        try!(self.print_msg_header(&mut ser.io, &ser.decorator, info));

        for &(k, v) in info.values() {
            try!(ser.print_comma());
            try!(v.serialize(info, k, &mut ser));
        }
        try!(write!(&mut ser.io, "\n"));

        Ok(())
    }

    fn print_indent<W: io::Write>(&self, io: &mut W, indent: usize) -> io::Result<()> {
        for _ in 0..indent {
            try!(write!(io, "  "));
        }
        Ok(())
    }

    // record in the history, and check if should print
    // given set of values
    fn should_print(&self, address: usize, indent: usize) -> bool {
        let mut history = self.history.lock().unwrap();
        if history.len() <= indent {
            debug_assert_eq!(history.len(), indent);
            history.push(address);
            true
        } else {
            let should = history[indent] != address;
            history[indent] = address;
            should
        }
    }

    fn format_recurse<W: io::Write>(&self,
                                    ser: &mut Serializer<W, D::RecordDecorator>,
                                    info: &slog::Record,
                                    logger_values: &slog::OwnedKeyValueList)
                                    -> io::Result<usize> {
        let mut indent = if logger_values.parent().is_none() {
            0
        } else {
            try!(self.format_recurse(ser, info, logger_values.parent().as_ref().unwrap()))
        };

        if !logger_values.values().is_empty() {
            if self.should_print(logger_values.values() as *const _ as usize, indent) {
                try!(self.print_indent(&mut ser.io, indent));
                let mut clean = true;
                for &(ref k, ref v) in logger_values.values() {
                    if !clean {
                        try!(ser.print_comma());
                    }
                    try!(v.serialize(info, k, ser));
                    clean = false;
                }
                try!(write!(&mut ser.io, "\n"));
            }
            indent += 1
        }

        Ok(indent)
    }
}

fn severity_to_color(lvl: Level) -> u8 {
    match lvl {
        Level::Critical => 1,
        Level::Error => 9,
        Level::Warning => 3,
        Level::Info => 2,
        Level::Debug => 6,
        Level::Trace => 4,
    }
}

/// Record decorator (color) for terminal output
pub struct ColorDecorator {
    use_color: bool,
}

impl ColorDecorator {
    /// New decorator that does color records
    pub fn new_colored() -> Self {
        ColorDecorator { use_color: true }
    }
    /// New decorator that does not color records
    pub fn new_plain() -> Self {
        ColorDecorator { use_color: true }
    }
}

/// Particular record decorator (color) for terminal output
pub struct ColorRecordDecorator {
    level_color: Option<Colour>,
    key_style: Option<ansi_term::Style>,
}

impl Decorator for ColorDecorator {
    type RecordDecorator = ColorRecordDecorator;

    fn decorate(&self, record: &Record) -> ColorRecordDecorator {
        if self.use_color {
            ColorRecordDecorator {
                level_color: Some(Colour::Fixed(severity_to_color(record.level()))),
                key_style: Some(ansi_term::Style::new().bold()),
            }
        } else {
            ColorRecordDecorator {
                level_color: None,
                key_style: None,
            }
        }
    }
}

impl RecordDecorator for ColorRecordDecorator {
    fn fmt_level(&self, io: &mut io::Write, args: fmt::Arguments) -> io::Result<()> {
        if let Some(level_color) = self.level_color {
            write!(io, "{}", level_color.paint(format!("{}", args)))
        } else {
            io.write_fmt(args)
        }
    }

    fn fmt_msg(&self, io: &mut io::Write, args: fmt::Arguments) -> io::Result<()> {
        if let Some(key_style) = self.key_style {
            write!(io, "{}", key_style.paint(format!("{}", args)))
        } else {
            io.write_fmt(args)
        }
    }

    fn fmt_key(&self, io: &mut io::Write, args: fmt::Arguments) -> io::Result<()> {
        self.fmt_msg(io, args)
    }
}

struct Serializer<W, D: RecordDecorator> {
    io: W,
    decorator: D,
}

impl<W: io::Write, D: RecordDecorator> Serializer<W, D> {
    fn new(io: W, d: D) -> Self {
        Serializer {
            io: io,
            decorator: d,
        }
    }

    fn print_comma(&mut self) -> io::Result<()> {
        try!(self.decorator.fmt_separator(&mut self.io, format_args!(", ")));
        Ok(())
    }

    fn finish(self) -> (W, D) {
        (self.io, self.decorator)
    }
}

macro_rules! s(
    ($s:expr, $k:expr, $v:expr) => {
        try!($s.decorator.fmt_key(&mut $s.io, format_args!("{}", $k)));
        try!($s.decorator.fmt_separator(&mut $s.io, format_args!(": ")));
        try!($s.decorator.fmt_value(&mut $s.io, format_args!("{}", $v)));
    };
);

impl<W: io::Write, D: RecordDecorator> slog::ser::Serializer for Serializer<W, D> {
    fn emit_none(&mut self, key: &str) -> ser::Result {
        s!(self, key, "None");
        Ok(())
    }
    fn emit_unit(&mut self, key: &str) -> ser::Result {
        s!(self, key, "()");
        Ok(())
    }

    fn emit_bool(&mut self, key: &str, val: bool) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }

    fn emit_char(&mut self, key: &str, val: char) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }

    fn emit_usize(&mut self, key: &str, val: usize) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_isize(&mut self, key: &str, val: isize) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }

    fn emit_u8(&mut self, key: &str, val: u8) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_i8(&mut self, key: &str, val: i8) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_u16(&mut self, key: &str, val: u16) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_i16(&mut self, key: &str, val: i16) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_u32(&mut self, key: &str, val: u32) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_i32(&mut self, key: &str, val: i32) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_f32(&mut self, key: &str, val: f32) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_u64(&mut self, key: &str, val: u64) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_i64(&mut self, key: &str, val: i64) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_f64(&mut self, key: &str, val: f64) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_str(&mut self, key: &str, val: &str) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_arguments(&mut self, key: &str, val: &fmt::Arguments) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }

}

impl<D: Decorator + Send + Sync> StreamFormat for Format<D> {
    fn format(&self,
              io: &mut io::Write,
              info: &Record,
              logger_values: &OwnedKeyValueList)
              -> io::Result<()> {
        match self.mode {
            FormatMode::Compact => self.format_compact(io, info, logger_values),
            FormatMode::Full => self.format_full(io, info, logger_values),
        }
    }
}

const TIMESTAMP_FORMAT: &'static str = "%b %d %H:%M:%S%.3f";

fn timestamp_local() -> String {
    chrono::Local::now().format(TIMESTAMP_FORMAT).to_string()
}

fn timestamp_utc() -> String {
    chrono::UTC::now().format(TIMESTAMP_FORMAT).to_string()
}

/// Streamer builder
pub struct StreamerBuilder {
    color: Option<bool>, // None = auto
    stdout: bool,
    async: bool,
    mode: FormatMode,
    fn_timestamp: Box<Fn() -> String + Send + Sync>,
}

impl StreamerBuilder {
    /// New `StreamerBuilder`
    pub fn new() -> Self {
        StreamerBuilder {
            color: None,
            stdout: true,
            async: false,
            mode: FormatMode::Full,
            fn_timestamp: Box::new(timestamp_local),
        }
    }

    /// Force colored output
    pub fn color(mut self) -> Self {
        self.color = Some(true);
        self
    }

    /// Force plain output
    pub fn plain(mut self) -> Self {
        self.color = Some(false);
        self
    }

    /// Auto detect color (default)
    pub fn auto_color(mut self) -> Self {
        self.color = None;
        self
    }

    /// Output to stderr
    pub fn stderr(mut self) -> Self {
        self.stdout = false;
        self
    }

    /// Output to stdout (default)
    pub fn stdout(mut self) -> Self {
        self.stdout = true;
        self
    }

    /// Output using full mode
    pub fn full(mut self) -> Self {
        self.mode = FormatMode::Full;
        self
    }

    /// Output using compact mode (default)
    pub fn compact(mut self) -> Self {
        self.mode = FormatMode::Compact;
        self
    }

    /// Use asynchronous streamer
    pub fn async(mut self) -> Self {
        self.async = true;
        self
    }

    /// Use synchronous streamer (default)
    pub fn sync(mut self) -> Self {
        self.async = false;
        self
    }

    /// Use the UTC time zone for the timestamp
    pub fn use_utc_timestamp(mut self) -> Self {
        self.fn_timestamp = Box::new(timestamp_utc);
        self
    }

    /// Use the local time zone for the timestamp (default)
    pub fn use_local_timestamp(mut self) -> Self {
        self.fn_timestamp = Box::new(timestamp_local);
        self
    }

    /// Provide a custom function to generate the timestamp
    pub fn use_custom_timestamp(mut self, f: Box<Fn() -> String + Send + Sync>) -> Self  {
        self.fn_timestamp = f;
        self
    }

    /// Build the streamer
    pub fn build(self) -> Box<slog::Drain<Error=io::Error>> {
        let color = self.color.unwrap_or(if self.stdout {
            stdout_isatty()
        } else {
            stderr_isatty()
        });

        let format = Format::new(
            self.mode,
            ColorDecorator { use_color: color },
            self.fn_timestamp
        );

        let io = if self.stdout {
            Box::new(io::stdout()) as Box<io::Write + Send>
        } else {
            Box::new(io::stderr()) as Box<io::Write + Send>
        };

        if self.async {
            Box::new(AsyncStreamer::new(io, format))
        } else {
            Box::new(Streamer::new(io, format))
        }
    }
}

/// Build `slog_stream::Streamer`/`slog_stream::AsyncStreamer` that
/// will output logging records to stderr/stderr.
pub fn streamer() -> StreamerBuilder {
    StreamerBuilder::new()
}
<commit_msg>chore(term): Fix clippy warnings<commit_after>//! Unix terminal formatter and drain for slog-rs
//!
//! ```
//! #[macro_use]
//! extern crate slog;
//! extern crate slog_term;
//!
//! use slog::*;
//!
//! fn main() {
//!     let root = Logger::root(slog_term::streamer().build().fuse(), o!("build-id" => "8dfljdf"));
//! }
//! ```
#![warn(missing_docs)]

#[macro_use]
extern crate slog;
extern crate slog_stream;
extern crate isatty;
extern crate ansi_term;
extern crate chrono;

use std::{io, fmt, sync};

use ansi_term::Colour;
use isatty::{stderr_isatty, stdout_isatty};

use slog::Record;
use slog::ser;
use slog::{Level, OwnedKeyValueList};
use slog_stream::Format as StreamFormat;
use slog_stream::{Decorator, RecordDecorator, Streamer, AsyncStreamer};

/// Formatting mode
enum FormatMode {
    /// Compact logging format
    Compact,
    /// Full logging format
    Full,
}

/// Full formatting with optional color support
pub struct Format<D: Decorator> {
    mode: FormatMode,
    decorator: D,
    history: sync::Mutex<Vec<usize>>,
    fn_timestamp: Box<Fn() -> String + Send + Sync>,
}

impl<D: Decorator> Format<D> {
    /// New Format format that prints using color
    fn new(mode: FormatMode, d: D, fn_timestamp: Box<Fn() -> String + Send + Sync>) -> Self {
        Format {
            decorator: d,
            mode: mode,
            history: sync::Mutex::new(vec![]),
            fn_timestamp: fn_timestamp,
        }
    }

    fn print_msg_header(&self,
                        io: &mut io::Write,
                        rd: &D::RecordDecorator,
                        info: &Record)
                        -> io::Result<()> {
        try!(rd.fmt_timestamp(io, format_args!("{} ", (self.fn_timestamp)())));
        try!(rd.fmt_level(io, format_args!("{} ", info.level().as_short_str())));

        try!(rd.fmt_msg(io, format_args!("{}", info.msg())));
        Ok(())
    }
    fn format_full(&self,
                   io: &mut io::Write,
                   info: &Record,
                   logger_values: &OwnedKeyValueList)
                   -> io::Result<()> {

        let r_decorator = self.decorator.decorate(info);

        try!(self.print_msg_header(io, &r_decorator, info));
        let mut serializer = Serializer::new(io, r_decorator);

        for &(k, ref v) in logger_values.iter() {
            try!(serializer.print_comma());
            try!(v.serialize(info, k, &mut serializer));
        }

        for &(k, v) in info.values() {
            try!(serializer.print_comma());
            try!(v.serialize(info, k, &mut serializer));
        }
        let (mut io, _decorator_r) = serializer.finish();

        try!(write!(io, "\n"));

        Ok(())
    }

    fn format_compact(&self,
                      io: &mut io::Write,
                      info: &Record,
                      logger_values: &OwnedKeyValueList)
                      -> io::Result<()> {

        let r_decorator = self.decorator.decorate(info);
        let mut ser = Serializer::new(io, r_decorator);

        let indent = try!(self.format_recurse(&mut ser, info, logger_values));

        try!(self.print_indent(&mut ser.io, indent));

        try!(self.print_msg_header(&mut ser.io, &ser.decorator, info));

        for &(k, v) in info.values() {
            try!(ser.print_comma());
            try!(v.serialize(info, k, &mut ser));
        }
        try!(write!(&mut ser.io, "\n"));

        Ok(())
    }

    fn print_indent<W: io::Write>(&self, io: &mut W, indent: usize) -> io::Result<()> {
        for _ in 0..indent {
            try!(write!(io, "  "));
        }
        Ok(())
    }

    // record in the history, and check if should print
    // given set of values
    fn should_print(&self, address: usize, indent: usize) -> bool {
        let mut history = self.history.lock().unwrap();
        if history.len() <= indent {
            debug_assert_eq!(history.len(), indent);
            history.push(address);
            true
        } else {
            let should = history[indent] != address;
            history[indent] = address;
            should
        }
    }

    fn format_recurse<W: io::Write>(&self,
                                    ser: &mut Serializer<W, D::RecordDecorator>,
                                    info: &slog::Record,
                                    logger_values: &slog::OwnedKeyValueList)
                                    -> io::Result<usize> {
        let mut indent = if logger_values.parent().is_none() {
            0
        } else {
            try!(self.format_recurse(ser, info, logger_values.parent().as_ref().unwrap()))
        };

        if !logger_values.values().is_empty() {
            if self.should_print(logger_values.values() as *const _ as usize, indent) {
                try!(self.print_indent(&mut ser.io, indent));
                let mut clean = true;
                for &(k, ref v) in logger_values.values() {
                    if !clean {
                        try!(ser.print_comma());
                    }
                    try!(v.serialize(info, k, ser));
                    clean = false;
                }
                try!(write!(&mut ser.io, "\n"));
            }
            indent += 1
        }

        Ok(indent)
    }
}

fn severity_to_color(lvl: Level) -> u8 {
    match lvl {
        Level::Critical => 1,
        Level::Error => 9,
        Level::Warning => 3,
        Level::Info => 2,
        Level::Debug => 6,
        Level::Trace => 4,
    }
}

/// Record decorator (color) for terminal output
pub struct ColorDecorator {
    use_color: bool,
}

impl ColorDecorator {
    /// New decorator that does color records
    pub fn new_colored() -> Self {
        ColorDecorator { use_color: true }
    }
    /// New decorator that does not color records
    pub fn new_plain() -> Self {
        ColorDecorator { use_color: true }
    }
}

/// Particular record decorator (color) for terminal output
pub struct ColorRecordDecorator {
    level_color: Option<Colour>,
    key_style: Option<ansi_term::Style>,
}

impl Decorator for ColorDecorator {
    type RecordDecorator = ColorRecordDecorator;

    fn decorate(&self, record: &Record) -> ColorRecordDecorator {
        if self.use_color {
            ColorRecordDecorator {
                level_color: Some(Colour::Fixed(severity_to_color(record.level()))),
                key_style: Some(ansi_term::Style::new().bold()),
            }
        } else {
            ColorRecordDecorator {
                level_color: None,
                key_style: None,
            }
        }
    }
}

impl RecordDecorator for ColorRecordDecorator {
    fn fmt_level(&self, io: &mut io::Write, args: fmt::Arguments) -> io::Result<()> {
        if let Some(level_color) = self.level_color {
            write!(io, "{}", level_color.paint(format!("{}", args)))
        } else {
            io.write_fmt(args)
        }
    }

    fn fmt_msg(&self, io: &mut io::Write, args: fmt::Arguments) -> io::Result<()> {
        if let Some(key_style) = self.key_style {
            write!(io, "{}", key_style.paint(format!("{}", args)))
        } else {
            io.write_fmt(args)
        }
    }

    fn fmt_key(&self, io: &mut io::Write, args: fmt::Arguments) -> io::Result<()> {
        self.fmt_msg(io, args)
    }
}

struct Serializer<W, D: RecordDecorator> {
    io: W,
    decorator: D,
}

impl<W: io::Write, D: RecordDecorator> Serializer<W, D> {
    fn new(io: W, d: D) -> Self {
        Serializer {
            io: io,
            decorator: d,
        }
    }

    fn print_comma(&mut self) -> io::Result<()> {
        try!(self.decorator.fmt_separator(&mut self.io, format_args!(", ")));
        Ok(())
    }

    fn finish(self) -> (W, D) {
        (self.io, self.decorator)
    }
}

macro_rules! s(
    ($s:expr, $k:expr, $v:expr) => {
        try!($s.decorator.fmt_key(&mut $s.io, format_args!("{}", $k)));
        try!($s.decorator.fmt_separator(&mut $s.io, format_args!(": ")));
        try!($s.decorator.fmt_value(&mut $s.io, format_args!("{}", $v)));
    };
);

impl<W: io::Write, D: RecordDecorator> slog::ser::Serializer for Serializer<W, D> {
    fn emit_none(&mut self, key: &str) -> ser::Result {
        s!(self, key, "None");
        Ok(())
    }
    fn emit_unit(&mut self, key: &str) -> ser::Result {
        s!(self, key, "()");
        Ok(())
    }

    fn emit_bool(&mut self, key: &str, val: bool) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }

    fn emit_char(&mut self, key: &str, val: char) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }

    fn emit_usize(&mut self, key: &str, val: usize) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_isize(&mut self, key: &str, val: isize) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }

    fn emit_u8(&mut self, key: &str, val: u8) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_i8(&mut self, key: &str, val: i8) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_u16(&mut self, key: &str, val: u16) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_i16(&mut self, key: &str, val: i16) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_u32(&mut self, key: &str, val: u32) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_i32(&mut self, key: &str, val: i32) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_f32(&mut self, key: &str, val: f32) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_u64(&mut self, key: &str, val: u64) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_i64(&mut self, key: &str, val: i64) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_f64(&mut self, key: &str, val: f64) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_str(&mut self, key: &str, val: &str) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }
    fn emit_arguments(&mut self, key: &str, val: &fmt::Arguments) -> ser::Result {
        s!(self, key, val);
        Ok(())
    }

}

impl<D: Decorator + Send + Sync> StreamFormat for Format<D> {
    fn format(&self,
              io: &mut io::Write,
              info: &Record,
              logger_values: &OwnedKeyValueList)
              -> io::Result<()> {
        match self.mode {
            FormatMode::Compact => self.format_compact(io, info, logger_values),
            FormatMode::Full => self.format_full(io, info, logger_values),
        }
    }
}

const TIMESTAMP_FORMAT: &'static str = "%b %d %H:%M:%S%.3f";

fn timestamp_local() -> String {
    chrono::Local::now().format(TIMESTAMP_FORMAT).to_string()
}

fn timestamp_utc() -> String {
    chrono::UTC::now().format(TIMESTAMP_FORMAT).to_string()
}

/// Streamer builder
pub struct StreamerBuilder {
    color: Option<bool>, // None = auto
    stdout: bool,
    async: bool,
    mode: FormatMode,
    fn_timestamp: Box<Fn() -> String + Send + Sync>,
}

impl StreamerBuilder {
    /// New `StreamerBuilder`
    pub fn new() -> Self {
        StreamerBuilder {
            color: None,
            stdout: true,
            async: false,
            mode: FormatMode::Full,
            fn_timestamp: Box::new(timestamp_local),
        }
    }

    /// Force colored output
    pub fn color(mut self) -> Self {
        self.color = Some(true);
        self
    }

    /// Force plain output
    pub fn plain(mut self) -> Self {
        self.color = Some(false);
        self
    }

    /// Auto detect color (default)
    pub fn auto_color(mut self) -> Self {
        self.color = None;
        self
    }

    /// Output to stderr
    pub fn stderr(mut self) -> Self {
        self.stdout = false;
        self
    }

    /// Output to stdout (default)
    pub fn stdout(mut self) -> Self {
        self.stdout = true;
        self
    }

    /// Output using full mode
    pub fn full(mut self) -> Self {
        self.mode = FormatMode::Full;
        self
    }

    /// Output using compact mode (default)
    pub fn compact(mut self) -> Self {
        self.mode = FormatMode::Compact;
        self
    }

    /// Use asynchronous streamer
    pub fn async(mut self) -> Self {
        self.async = true;
        self
    }

    /// Use synchronous streamer (default)
    pub fn sync(mut self) -> Self {
        self.async = false;
        self
    }

    /// Use the UTC time zone for the timestamp
    pub fn use_utc_timestamp(mut self) -> Self {
        self.fn_timestamp = Box::new(timestamp_utc);
        self
    }

    /// Use the local time zone for the timestamp (default)
    pub fn use_local_timestamp(mut self) -> Self {
        self.fn_timestamp = Box::new(timestamp_local);
        self
    }

    /// Provide a custom function to generate the timestamp
    pub fn use_custom_timestamp(mut self, f: Box<Fn() -> String + Send + Sync>) -> Self  {
        self.fn_timestamp = f;
        self
    }

    /// Build the streamer
    pub fn build(self) -> Box<slog::Drain<Error=io::Error>> {
        let color = self.color.unwrap_or(if self.stdout {
            stdout_isatty()
        } else {
            stderr_isatty()
        });

        let format = Format::new(
            self.mode,
            ColorDecorator { use_color: color },
            self.fn_timestamp
        );

        let io = if self.stdout {
            Box::new(io::stdout()) as Box<io::Write + Send>
        } else {
            Box::new(io::stderr()) as Box<io::Write + Send>
        };

        if self.async {
            Box::new(AsyncStreamer::new(io, format))
        } else {
            Box::new(Streamer::new(io, format))
        }
    }
}

impl Default for StreamerBuilder {
    fn default() -> Self {
        Self::new()
    }
}

/// Build `slog_stream::Streamer`/`slog_stream::AsyncStreamer` that
/// will output logging records to stderr/stderr.
pub fn streamer() -> StreamerBuilder {
    StreamerBuilder::new()
}
<|endoftext|>


<commit_before>struct NFA
{
	states: ~[State],
}

impl NFA
{
	pub fn new()	->	NFA
	{
		NFA { states: ~[] }
	}

	pub fn add_state(&mut self, state: State)
	{
		self.states.push(state);
	}

	pub fn link_states(&mut self, id0: int, id1: int)
	{
		self.states[id0].add_transition(id1);
	}

	pub fn print(&self)
	{
		println("\nprinting states:");
		for i in range(0, self.states.len())
		{
			print(fmt!("%u: ", i));
			self.states[i].print();
		}
		println("");
	}

	pub fn pop(&mut self)	->	State
	{
		self.states.pop()
	}

	pub fn len(&self)	->	int
	{
		self.states.len() as int
	}

	pub fn check(&self, string: ~str, c: ~[int])		->	bool
	{
		let mut curr = c.clone();
		//println(fmt!("check: string=%? c=%?", string, c));
		if string.len() > 0
		{
			let c = string.char_at(0);
			let mut next = ~[];
			// look to see if any current states have c or an
			// epsilon transition as a value
			let mut l = curr.len();
			let mut i = 0;
			while i < l
			{
				//println(fmt!("on character %?, state=%? val=%?", c, curr[i], self.states[curr[i]].val));
				if self.states[curr[i]].val == c
				{
					for j in range(0, self.states[curr[i]].transitions.len())
					{
						//println(fmt!("adding %d", self.states[curr[i]].transitions[j]));
						next.push(self.states[curr[i]].transitions[j]);
					}
				}
				else if self.states[curr[i]].val == '.'
				{
					for j in range(0, self.states[curr[i]].transitions.len())
					{
						next.push(self.states[curr[i]].transitions[j]);
					}
				}
				else if self.states[curr[i]].val == '%'
				{
					for j in range(0, self.states[curr[i]].transitions.len())
					{
						//println(fmt!("pushing %d", self.states[curr[i]].transitions[j]));
						if !curr.contains(&self.states[curr[i]].transitions[j])
						{
							curr.push(self.states[curr[i]].transitions[j]);
							l += 1;
						}
					}
				}
				i += 1;
				//println(fmt!("curr=%? next=%? l=%? i=%?", curr,next,l, i));
			}
			if next.len() == 0 { return false; }
			return self.check(string.slice_from(1).to_owned(), next);
		}
		else
		{
			// see if we're in a matching state
			for i in range(0, curr.len())
			{
				if self.states[curr[i]].accept
				{
					return true;
				}
			}
			// check to see if there are any epsilon transitions we
			// can make
			let mut next = ~[];
			for i in range(0, curr.len())
			{
				if self.states[curr[i]].val == '%'
				{
					for j in range(0, self.states[curr[i]].transitions.len())
					{
						next.push(self.states[curr[i]].transitions[j]);
					}
				}
			}
			//println(fmt!("curr=%? next=%?", curr, next));
			if next.len() > 0
			{
				return self.check(string, next);
			}
			return false;
		}
	}
}

#[deriving(Clone,DeepClone, Eq)]
struct State
{
	val: char,
	accept: bool,
	transitions: ~[int]
}

impl State
{
	pub fn new(c: char, b: bool)	->	State
	{
		State { val: c, accept: b, transitions: ~[] }
	}

	pub fn print(&self)
	{
		print(fmt!("value=%? matching=%? transitions={", self.val, self.accept));
		for i in range(0, self.transitions.len())
		{
			print(fmt!("%?,", self.transitions[i]));
		}
		println("}");
	}

	pub fn is_accept(&mut self, b: bool)
	{
		self.accept = b;
	}

	pub fn add_transition(&mut self, id: int)
	{
		self.transitions.push(id);
	}

	pub fn change_val(&mut self, c: char)
	{
		self.val = c;
	}
}

fn main()
{
	let test = std::os::args()[1];
	let strings = ~[~"", ~"a", ~"b", ~"aa", ~"bb", ~"ab", ~"ba", ~"aab", ~"aba", ~"baa", ~"abb", ~"bab", ~"bba", ~"bbb", ~"aaa", ~"abbb", ~"abba"];
	let mut nfa = NFA::new();
	let mut parenthesis: ~[int] = ~[];
	let head_state = State::new('%', false);
	nfa.add_state(head_state);
	let mut j = 0;
	let mut escaped = false;
	for i in range(1,(test.len()+1) as int)
	{
		let c = test.char_at((i-1) as uint);
		if c == '\\'
		{
			escaped = true;
		}
		else if c == '(' && !escaped
		{
			// note the place and make an 'in' state
			parenthesis.push(i);
			let state_in = State::new('%', false);
			nfa.add_state(state_in);
			j += 1;

			// link this and the previous
			nfa.link_states(j-1, j);
		}
		else if c == ')' && !escaped
		{
			let state_out = State::new('%', false);
			nfa.add_state(state_out);
			j += 1;

			// link to state_in
			nfa.link_states(j, parenthesis.pop()-1);

			// link to prev
			nfa.link_states(j-1, j);
		}
		else if c == '*' && !escaped
		{
			let state_out = State::new('%', false);

			// link to state_curr
			nfa.add_state(state_out);
			j += 1;
			nfa.link_states(j-1, j);

			// link out to curr
			nfa.link_states(j, j-1);

			// link prev to out, since it's a '*'
			nfa.link_states(j-2, j);
		}
		else if c == '+' && !escaped
		{
			let state_out = State::new('%', false);

			nfa.add_state(state_out);
			j += 1;

			// link out to curr
			nfa.link_states(j, j-1);

			// link curr to out
			nfa.link_states(j-1, j);
		}
		else if c == '?' && !escaped
		{
			let state_out = State::new('%', false);

			nfa.add_state(state_out);
			j += 1;

			// link to curr to out
			nfa.link_states(j-1, j);

			// link prev to out
			nfa.link_states(j-2, j);
		}
		else if c == '.' && !escaped
		{
			let state = State::new(c, false);
			nfa.add_state(state);
			j += 1;

			// link with previous
			nfa.link_states(j-1, j);
		}
		else
		{
			let state = State::new(c, false);
			nfa.add_state(state);
			j += 1;

			// link with previous
			nfa.link_states(j-1, j);
			escaped = false;
		}
	}

	// add a tail state
	let tail_state = State::new('%', true);
	nfa.add_state(tail_state);
	// link with previous
	let l = nfa.len();
	nfa.link_states(l-2, l-1);
	//nfa.states[nfa.len() - 1].is_accept(true);

	nfa.print();

	let curr = ~[0];
	println(fmt!("Regex is: %s", test));
	for i in range(0, strings.len())
	{
		println(fmt!("%? %?", strings[i], nfa.check(strings[i].clone(), curr.clone())));
	}
}
<commit_msg>simplified *, +, and .<commit_after>struct NFA
{
	states: ~[State],
}

impl NFA
{
	pub fn new()	->	NFA
	{
		NFA { states: ~[] }
	}

	pub fn add_state(&mut self, state: State)
	{
		self.states.push(state);
	}

	pub fn add_transition(&mut self, id0: int, c: char, id1: int)
	{
		self.states[id0].add_transition(c, id1);
	}

	pub fn print(&self)
	{
		println("\nprinting states:");
		for i in range(0, self.states.len())
		{
			print(fmt!("%u: ", i));
			self.states[i].print();
		}
		println("");
	}

	pub fn pop(&mut self)	->	State
	{
		self.states.pop()
	}

	pub fn len(&self)	->	int
	{
		self.states.len() as int
	}
	pub fn check(&self, string: ~str, c: ~[int])		->	bool
	{
		let mut curr = c.clone();
		//println(fmt!("check: string=%? c=%?", string, c));
		if string.len() > 0
		{
			let c = string.char_at(0);
			let mut next = ~[];
			// look to see if any current states have c or an
			// epsilon transition as a value
			let mut l = curr.len();
			let mut i = 0;
			while i < l
			{
				for j in range(0, self.states[curr[i]].transitions.len())
				{
					let (t, id) = (self.states[curr[i]].transitions[j]).clone();
					if t == c
					{
						next.push(id);
					}
					else if t == '%'
					{
						curr.push(id);
						l += 1;
					}
				}
				i += 1;
			}
			if next.len() == 0 { return false; }
			return self.check(string.slice_from(1).to_owned(), next);
		}
		else // the NFA has eaten all of the characters
		{
			// see if we're in a matching state
			for i in range(0, curr.len())
			{
				if self.states[curr[i]].accept
				{
					return true;
				}
			}
			// check to see if there are any epsilon transitions we
			// can make
			let mut next = ~[];
			for i in range(0, curr.len())
			{
				for j in range(0, self.states[curr[i]].transitions.len())
				{
					let (t , id) = (self.states[curr[i]].transitions[j]).clone();
					if t == '%'
					{
						next.push(id);
					}
				}
			}
			//println(fmt!("curr=%? next=%?", curr, next));
			if next.len() > 0
			{
				return self.check(string, next);
			}
			return false;
		}
	}
}

#[deriving(Clone, Eq)]
struct State
{
	accept: bool,
	transitions: ~[(char, int)]
}

impl State
{
	pub fn new(b: bool)	->	State
	{
		State { accept: b, transitions: ~[] }
	}

	pub fn print(&self)
	{
		print(fmt!("matching=%? transitions={", self.accept));
		for i in range(0, self.transitions.len())
		{
			print(fmt!("%?,", self.transitions[i]));
		}
		println("}");
	}

	pub fn is_accept(&mut self, b: bool)
	{
		self.accept = b;
	}

	pub fn add_transition(&mut self, c: char, id: int )
	{
		self.transitions.push((c, id));
	}
}

fn main()
{
	let test = std::os::args()[1];
	let lang = ['a', 'b'];
	let strings = ~[~"", ~"a", ~"b", ~"aa", ~"bb", ~"ab", ~"ba", ~"aab", ~"aba", ~"baa", ~"abb", ~"bab", ~"bba", ~"bbb", ~"aaa", ~"abbb", ~"abba"];
	let mut nfa = NFA::new();
	//let mut parenthesis: ~[int] = ~[];
	//let head_state = State::new(false);
	//nfa.add_state(head_state);
	let mut j = -1;
	let mut escaped = false;
	for i in range(1,(test.len()+1) as int)
	{
		let c = test.char_at((i-1) as uint);
		if c == '\\'
		{
			escaped = true;
		}
		/*
		else if c == '(' && !escaped
		{
			// note the place and make an 'in' state
			parenthesis.push(i);
			let state_in = State::new('%', false);
			nfa.add_state(state_in);
			j += 1;

			// link this and the previous
			nfa.link_states(j-1, j);
		}
		else if c == ')' && !escaped
		{
			let state_out = State::new('%', false);
			nfa.add_state(state_out);
			j += 1;

			// link to state_in
			nfa.link_states(j, parenthesis.pop()-1);

			// link to prev
			nfa.link_states(j-1, j);
		}
		*/
		else if c == '*' && !escaped
		{
			// link curr to itself
			for i in range(0, nfa.states[j].transitions.len())
			{
				let (a,_) = (nfa.states[j].transitions[i]).clone();
				if a != '%'
				{
					nfa.add_transition(j, a, j);
				}
			}
			// add epsilon transition to skip this state
			nfa.add_transition(j, '%', j+1);

		}
		else if c == '+' && !escaped
		{
			let state_next = State::new(false);
			// link next to curr

			nfa.add_state(state_next);
			j += 1;

			// link next to curr
			nfa.add_transition(j, '%', j-1);
			// add transition to next state
			nfa.add_transition(j, '%', j+1);
		}
		/*
		else if c == '?' && !escaped
		{
			let state_out = State::new('%', false);

			nfa.add_state(state_out);
			j += 1;

			// link to curr to out
			nfa.link_states(j-1, j);

			// link prev to out
			nfa.link_states(j-2, j);
		}
		*/
		else if c == '.' && !escaped
		{
			let state = State::new(false);
			nfa.add_state(state);
			j += 1;

			// unconditional jump
			for i in range(0, lang.len())
			{
				nfa.add_transition(j, lang[i], j+1);
			}
		}
		else
		{
			let state = State::new(false);
			nfa.add_state(state);
			j += 1;

			// link with next
			nfa.add_transition(j, c, j+1);
			escaped = false;
		}

		nfa.print();
	}
	// make the last state true
	let state = State::new(true);
	nfa.add_state(state);

	nfa.print();

	let curr = ~[0];
	println(fmt!("Regex is: %s", test));
	for i in range(0, strings.len())
	{
		println(fmt!("%? %?", strings[i], nfa.check(strings[i].clone(), curr.clone())));
	}

}
<|endoftext|>


<commit_before>/**
 * A deque, for fun.  Untested as of yet.  Likely buggy.
 */

type t[T] = obj {
            fn size() -> uint;

            fn add_front(&T t);
            fn add_back(&T t);

            fn pop_front() -> T;
            fn pop_back() -> T;

            fn peek_front() -> T;
            fn peek_back() -> T;

            fn get(int i) -> T;
};

fn create[T]() -> t[T] {

    type cell[T] = option::t[T];

    let uint initial_capacity = 32u; // 2^5

    /**
     * Grow is only called on full elts, so nelts is also len(elts), unlike
     * elsewhere.
     */
    fn grow[T](uint nelts, uint lo, vec[cell[T]] elts) -> vec[cell[T]] {
        assert (nelts == vec::len[cell[T]](elts));

        fn fill[T](uint i, uint nelts, uint lo,
                   vec[cell[T]] old) -> cell[T] {
            ret if (i < nelts) {
                old.((lo + i) % nelts)
            } else {
                option::none[T]
            };
        }

        let uint nalloc = uint::next_power_of_two(nelts + 1u);
        let vec::init_op[cell[T]] copy_op = bind fill[T](_, nelts, lo, elts);
        ret vec::init_fn[cell[T]](copy_op, nalloc);
    }

    fn get[T](vec[cell[T]] elts, uint i) -> T {
        ret alt (elts.(i)) {
            case (option::some[T](?t)) { t }
            case (_) { fail }
        };
    }

    obj deque[T](mutable uint nelts,
                 mutable uint lo,
                 mutable uint hi,
                 mutable vec[cell[T]] elts)
        {
            fn size() -> uint { ret nelts; }

            fn add_front(&T t) {
                let uint oldlo = lo;

                if (lo == 0u) {
                    lo = vec::len[cell[T]](elts) - 1u;
                } else {
                    lo -= 1u;
                }

                if (lo == hi) {
                    elts = grow[T](nelts, oldlo, elts);
                    lo = vec::len[cell[T]](elts) - 1u;
                    hi = nelts;
                }

                elts.(lo) = option::some[T](t);
                nelts += 1u;
            }

            fn add_back(&T t) {
                if (lo == hi && nelts != 0u) {
                    elts = grow[T](nelts, lo, elts);
                    lo = 0u;
                    hi = nelts;
                }

                elts.(hi) = option::some[T](t);
                hi = (hi + 1u) % vec::len[cell[T]](elts);
                nelts += 1u;
            }

            /**
             * We actually release (turn to none()) the T we're popping so
             * that we don't keep anyone's refcount up unexpectedly.
             */
            fn pop_front() -> T {
                let T t = get[T](elts, lo);
                elts.(lo) = option::none[T];
                lo = (lo + 1u) % vec::len[cell[T]](elts);
                nelts -= 1u;
                ret t;
            }

            fn pop_back() -> T {
                if (hi == 0u) {
                    hi = vec::len[cell[T]](elts) - 1u;
                } else {
                    hi -= 1u;
                }

                let T t = get[T](elts, hi);
                elts.(hi) = option::none[T];
                nelts -= 1u;
                ret t;
            }

            fn peek_front() -> T {
                ret get[T](elts, lo);
            }

            fn peek_back() -> T {
                ret get[T](elts, hi - 1u);
            }

            fn get(int i) -> T {
                let uint idx = (lo + (i as uint)) % vec::len[cell[T]](elts);
                ret get[T](elts, idx);
            }

        }
    let vec[cell[T]] v = vec::init_elt[cell[T]](option::none[T],
                                                initial_capacity);

    ret deque[T](0u, 0u, 0u, v);
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>stdlib: Make the bound vector an alias in std::deque<commit_after>/**
 * A deque, for fun.  Untested as of yet.  Likely buggy.
 */

type t[T] = obj {
            fn size() -> uint;

            fn add_front(&T t);
            fn add_back(&T t);

            fn pop_front() -> T;
            fn pop_back() -> T;

            fn peek_front() -> T;
            fn peek_back() -> T;

            fn get(int i) -> T;
};

fn create[T]() -> t[T] {

    type cell[T] = option::t[T];

    let uint initial_capacity = 32u; // 2^5

    /**
     * Grow is only called on full elts, so nelts is also len(elts), unlike
     * elsewhere.
     */
    fn grow[T](uint nelts, uint lo, vec[cell[T]] elts) -> vec[cell[T]] {
        assert (nelts == vec::len[cell[T]](elts));

        // FIXME: Making the vector argument an alias is a workaround for
        // issue #375
        fn fill[T](uint i, uint nelts, uint lo,
                   &vec[cell[T]] old) -> cell[T] {
            ret if (i < nelts) {
                old.((lo + i) % nelts)
            } else {
                option::none[T]
            };
        }

        let uint nalloc = uint::next_power_of_two(nelts + 1u);
        let vec::init_op[cell[T]] copy_op = bind fill[T](_, nelts, lo, elts);
        ret vec::init_fn[cell[T]](copy_op, nalloc);
    }

    fn get[T](vec[cell[T]] elts, uint i) -> T {
        ret alt (elts.(i)) {
            case (option::some[T](?t)) { t }
            case (_) { fail }
        };
    }

    obj deque[T](mutable uint nelts,
                 mutable uint lo,
                 mutable uint hi,
                 mutable vec[cell[T]] elts)
        {
            fn size() -> uint { ret nelts; }

            fn add_front(&T t) {
                let uint oldlo = lo;

                if (lo == 0u) {
                    lo = vec::len[cell[T]](elts) - 1u;
                } else {
                    lo -= 1u;
                }

                if (lo == hi) {
                    elts = grow[T](nelts, oldlo, elts);
                    lo = vec::len[cell[T]](elts) - 1u;
                    hi = nelts;
                }

                elts.(lo) = option::some[T](t);
                nelts += 1u;
            }

            fn add_back(&T t) {
                if (lo == hi && nelts != 0u) {
                    elts = grow[T](nelts, lo, elts);
                    lo = 0u;
                    hi = nelts;
                }

                elts.(hi) = option::some[T](t);
                hi = (hi + 1u) % vec::len[cell[T]](elts);
                nelts += 1u;
            }

            /**
             * We actually release (turn to none()) the T we're popping so
             * that we don't keep anyone's refcount up unexpectedly.
             */
            fn pop_front() -> T {
                let T t = get[T](elts, lo);
                elts.(lo) = option::none[T];
                lo = (lo + 1u) % vec::len[cell[T]](elts);
                nelts -= 1u;
                ret t;
            }

            fn pop_back() -> T {
                if (hi == 0u) {
                    hi = vec::len[cell[T]](elts) - 1u;
                } else {
                    hi -= 1u;
                }

                let T t = get[T](elts, hi);
                elts.(hi) = option::none[T];
                nelts -= 1u;
                ret t;
            }

            fn peek_front() -> T {
                ret get[T](elts, lo);
            }

            fn peek_back() -> T {
                ret get[T](elts, hi - 1u);
            }

            fn get(int i) -> T {
                let uint idx = (lo + (i as uint)) % vec::len[cell[T]](elts);
                ret get[T](elts, idx);
            }

        }
    let vec[cell[T]] v = vec::init_elt[cell[T]](option::none[T],
                                                initial_capacity);

    ret deque[T](0u, 0u, 0u, v);
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>//! Lua thread test.
//! Spawns a lua thread!

use std::time::Duration;
use std::thread;
use std::collections::BTreeMap;

use hlua::any::AnyLuaValue;
use hlua::any::AnyLuaValue::*;
use hlua::lua_tables::LuaTable;
use hlua::{Lua, LuaError};

use super::*;

fn wait_for_thread() {
    for i in 0..20 {
        if !thread_running() {
            thread::sleep_ms(200);
        }
        else { return; }
    }
    panic!("Thread didn't run!");
}

#[test]
fn activate_thread() {
    super::init();
}

#[test]
fn thread_exec_okay() {
    wait_for_thread();

    let hello_receiver = send(LuaQuery::Execute(
        "hello = 'hello world'".to_string())).unwrap();
    let hello_result = hello_receiver.recv().unwrap();
    assert!(hello_result.is_ok());
    assert_eq!(hello_result, LuaResponse::Pong);

    let assert_receiver = send(LuaQuery::Execute(
        "assert(hello == 'hello world')".to_string())).unwrap();
    let assert_result = assert_receiver.recv().unwrap();
    assert!(hello_result.is_ok());
    assert_eq!(assert_result, LuaResponse::Pong);
}

#[test]
fn thread_exec_err() {
    wait_for_thread();

    let assert_receiver = send(LuaQuery::Execute(
        "assert(true == false, 'Logic works')".to_string())).unwrap();
    let assert_result = assert_receiver.recv().unwrap();
    assert!(assert_result.is_err());
    assert!(!assert_result.is_ok());
    if let LuaResponse::Error(err) = assert_result {
        if let LuaError::ExecutionError(lua_err) = err {
            assert!(lua_err.contains("Logic works"));
        }
        else {
            panic!("thread_exec_err result was not an ExecutionError: {:?}",
                   err);
        }
    }
    else {
        panic!("thread_exec_err result was not an error: {:?}", assert_result);
    }
}

#[test]
fn thread_exec_file_ok() {
    wait_for_thread();

    let file_receiver = send(LuaQuery::ExecFile(
        "lib/test/lua-exec-file.lua".to_string())).unwrap();
    let file_result = file_receiver.recv().unwrap();
    if let LuaResponse::Error(err) = file_result {
        if let LuaError::ReadError(ioerr) = err {
            panic!("Lua thread was unable to execute file: {:?}", ioerr);
        }
        else {
            panic!("Unexpected error executing file: {:?}", err);
        }
    }
    assert!(file_result.is_ok());
    assert_eq!(file_result, LuaResponse::Pong);

    // Print the method from the file
    let test_receiver = send(LuaQuery::Execute(
        "confirm_file()".to_string())).unwrap();
    let test_result = test_receiver.recv().unwrap();
    assert!(test_result.is_ok());
    assert!(test_result == LuaResponse::Pong);
}

#[test]
fn thread_exec_file_err() {
    wait_for_thread();

    let run_receiver = send(LuaQuery::ExecFile(
        "lib/test/lua-bad-assert.lua".to_string())).unwrap();
    let run_result = run_receiver.recv().unwrap();
    assert!(run_result.is_err());
    match run_result {
        LuaResponse::Error(err) => {
            match err {
                LuaError::ExecutionError(ex) => {
                    assert!(ex.contains("Dude, 1 is totally equal to 0"));
                },
                _ => panic!("Got wrong hlua error type: {:?}", err)
            }
        },
        _ => panic!("Got wrong LuaResponse type: {:?}", run_result)
    }

    let syntax_receiver = send(LuaQuery::ExecFile(
        "lib/test/lua-syntax-err.txt".to_string())).unwrap();
    let syntax_result = syntax_receiver.recv().unwrap();
    assert!(syntax_result.is_err());
    match syntax_result {
        LuaResponse::Error(err) => {
            match err {
                LuaError::SyntaxError(serr) => {
                    assert!(serr.contains("expected"));
                },
                _ => panic!("Got wrong hlua error type: {:?}", err)
            }
        }
        _ => panic!("Got wrong LuaResponse type: {:?}", syntax_result)
    }
}

#[test]
fn test_rust_exec() {
    wait_for_thread();
    let rust_receiver = send(LuaQuery::ExecRust(rust_lua_fn)).unwrap();
    let rust_result = rust_receiver.recv().unwrap();
    assert!(rust_result.is_ok());

    match rust_result {
        LuaResponse::Variable(Some(var)) => {
            match var {
                AnyLuaValue::LuaBoolean(b) => {
                    if !b {
                        panic!("Rust function failed!");
                    }
                },
                _ => panic!("Rust function returned wrong AnyLuaValue")
            }
        },
        _ => panic!("Got wrong LuaResponse from Rust function!")
    }
}

fn rust_lua_fn(lua: &mut Lua) -> AnyLuaValue {
    {
        let mut foo = lua.empty_array("foo");
        foo.set("bar", 12.0);
    }
    let mut maybe_foo = lua.get::<LuaTable<_>, _>("foo");
    assert!(maybe_foo.is_some());
    let mut foo = maybe_foo.unwrap();
    assert!(foo.get::<f64, _>("bar").is_some());
    AnyLuaValue::LuaBoolean(true)
}

<commit_msg>Add syntax error to Lua tests<commit_after>//! Lua thread test.
//! Spawns a lua thread!

use std::time::Duration;
use std::thread;
use std::collections::BTreeMap;

use hlua::any::AnyLuaValue;
use hlua::any::AnyLuaValue::*;
use hlua::lua_tables::LuaTable;
use hlua::{Lua, LuaError};

use super::*;

fn wait_for_thread() {
    for i in 0..20 {
        if !thread_running() {
            thread::sleep_ms(200);
        }
        else { return; }
    }
    panic!("Thread didn't run!");
}

#[test]
fn activate_thread() {
    super::init();
}

#[test]
fn thread_exec_okay() {
    wait_for_thread();

    let hello_receiver = send(LuaQuery::Execute(
        "hello = 'hello world'".to_string())).unwrap();
    let hello_result = hello_receiver.recv().unwrap();
    assert!(hello_result.is_ok());
    assert_eq!(hello_result, LuaResponse::Pong);

    let assert_receiver = send(LuaQuery::Execute(
        "assert(hello == 'hello world')".to_string())).unwrap();
    let assert_result = assert_receiver.recv().unwrap();
    assert!(hello_result.is_ok());
    assert_eq!(assert_result, LuaResponse::Pong);
}

#[test]
fn thread_exec_err() {
    wait_for_thread();

    let assert_receiver = send(LuaQuery::Execute(
        "assert(true == false, 'Logic works')".to_string()))
        .expect("send assertion error");
    let assert_result = assert_receiver.recv()
        .expect("receive assertion error result");
    assert!(assert_result.is_err(), "expected error from syntax error");
    if let LuaResponse::Error(err) = assert_result {
        if let LuaError::ExecutionError(lua_err) = err {
            assert!(lua_err.contains("Logic works"));
        }
        else {
            panic!("thread_exec_err result was not an ExecutionError: {:?}",
                   err);
        }
    }
    else {
        panic!("thread_exec_err result was not an error: {:?}", assert_result);
    }

    let syn_err_rx = send(LuaQuery::Execute(
        "local variable_err = 'sequence\\y'".to_string()))
        .expect("send syntax error");
    let syn_err_result = syn_err_rx.recv()
        .expect("receive assertion error result");
    assert!(syn_err_result.is_err(), "expected error from syntax error");
    if let LuaResponse::Error(lua_err) = syn_err_result {
        if let LuaError::SyntaxError(s_err) = lua_err {
            assert!(s_err.contains("escape sequence"), "Got wrong error type");
        }
        else {
            panic!("Wrong type of lua error!");
        }
    }
    else {
        panic!("Got the wrong LuaResponse type!");
    }
}

#[test]
fn thread_exec_file_ok() {
    wait_for_thread();

    let file_receiver = send(LuaQuery::ExecFile(
        "lib/test/lua-exec-file.lua".to_string())).unwrap();
    let file_result = file_receiver.recv().unwrap();
    if let LuaResponse::Error(err) = file_result {
        if let LuaError::ReadError(ioerr) = err {
            panic!("Lua thread was unable to execute file: {:?}", ioerr);
        }
        else {
            panic!("Unexpected error executing file: {:?}", err);
        }
    }
    assert!(file_result.is_ok());
    assert_eq!(file_result, LuaResponse::Pong);

    // Print the method from the file
    let test_receiver = send(LuaQuery::Execute(
        "confirm_file()".to_string())).unwrap();
    let test_result = test_receiver.recv().unwrap();
    assert!(test_result.is_ok());
    assert!(test_result == LuaResponse::Pong);
}

#[test]
fn thread_exec_file_err() {
    wait_for_thread();

    let run_receiver = send(LuaQuery::ExecFile(
        "lib/test/lua-bad-assert.lua".to_string())).unwrap();
    let run_result = run_receiver.recv().unwrap();
    assert!(run_result.is_err());
    match run_result {
        LuaResponse::Error(err) => {
            match err {
                LuaError::ExecutionError(ex) => {
                    assert!(ex.contains("Dude, 1 is totally equal to 0"));
                },
                _ => panic!("Got wrong hlua error type: {:?}", err)
            }
        },
        _ => panic!("Got wrong LuaResponse type: {:?}", run_result)
    }

    let syntax_receiver = send(LuaQuery::ExecFile(
        "lib/test/lua-syntax-err.txt".to_string())).unwrap();
    let syntax_result = syntax_receiver.recv().unwrap();
    assert!(syntax_result.is_err());
    match syntax_result {
        LuaResponse::Error(err) => {
            match err {
                LuaError::SyntaxError(serr) => {
                    assert!(serr.contains("expected"));
                },
                _ => panic!("Got wrong hlua error type: {:?}", err)
            }
        }
        _ => panic!("Got wrong LuaResponse type: {:?}", syntax_result)
    }
}

#[test]
fn test_rust_exec() {
    wait_for_thread();
    let rust_receiver = send(LuaQuery::ExecRust(rust_lua_fn)).unwrap();
    let rust_result = rust_receiver.recv().unwrap();
    assert!(rust_result.is_ok());

    match rust_result {
        LuaResponse::Variable(Some(var)) => {
            match var {
                AnyLuaValue::LuaBoolean(b) => {
                    if !b {
                        panic!("Rust function failed!");
                    }
                },
                _ => panic!("Rust function returned wrong AnyLuaValue")
            }
        },
        _ => panic!("Got wrong LuaResponse from Rust function!")
    }
}

fn rust_lua_fn(lua: &mut Lua) -> AnyLuaValue {
    {
        let mut foo = lua.empty_array("foo");
        foo.set("bar", 12.0);
    }
    let mut maybe_foo = lua.get::<LuaTable<_>, _>("foo");
    assert!(maybe_foo.is_some());
    let mut foo = maybe_foo.unwrap();
    assert!(foo.get::<f64, _>("bar").is_some());
    AnyLuaValue::LuaBoolean(true)
}

<|endoftext|>