<commit_before>use crate::prelude::*;

fn codegen_print(fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>, msg: &str) {
    let puts = fx
        .module
        .declare_function(
            "puts",
            Linkage::Import,
            &Signature {
                call_conv: CallConv::triple_default(fx.triple()),
                params: vec![AbiParam::new(pointer_ty(fx.tcx))],
                returns: vec![AbiParam::new(types::I32)],
            },
        )
        .unwrap();
    let puts = fx.module.declare_func_in_func(puts, &mut fx.bcx.func);
    #[cfg(debug_assertions)]
    {
        fx.add_comment(puts, "puts");
    }

    let symbol_name = fx.tcx.symbol_name(fx.instance);
    let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, symbol_name, msg);
    let msg_ptr = fx.anonymous_str("trap", &real_msg);
    fx.bcx.ins().call(puts, &[msg_ptr]);
}

/// Use this when `rustc_codegen_llvm` would insert a call to the panic handler.
///
/// Trap code: user0
pub(crate) fn trap_panic(
    fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>,
    msg: impl AsRef<str>,
) {
    codegen_print(fx, msg.as_ref());
    fx.bcx.ins().trap(TrapCode::User(0));
}

/// Use this for example when a function call should never return. This will fill the current block,
/// so you can **not** add instructions to it afterwards.
///
/// Trap code: user65535
pub(crate) fn trap_unreachable(
    fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>,
    msg: impl AsRef<str>,
) {
    codegen_print(fx, msg.as_ref());
    fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
}

/// Like `trap_unreachable` but returns a fake value of the specified type.
///
/// Trap code: user65535
pub(crate) fn trap_unreachable_ret_value<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl cranelift_module::Backend>,
    dest_layout: TyAndLayout<'tcx>,
    msg: impl AsRef<str>,
) -> CValue<'tcx> {
    trap_unreachable(fx, msg);
    CValue::by_ref(Pointer::const_addr(fx, 0), dest_layout)
}

/// Use this when something is unimplemented, but `libcore` or `libstd` requires it to codegen.
/// Unlike `trap_unreachable` this will not fill the current block, so you **must** add instructions
/// to it afterwards.
///
/// Trap code: user65535
pub(crate) fn trap_unimplemented(
    fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>,
    msg: impl AsRef<str>,
) {
    codegen_print(fx, msg.as_ref());
    let true_ = fx.bcx.ins().iconst(types::I32, 1);
    fx.bcx.ins().trapnz(true_, TrapCode::User(!0));
}

/// Like `trap_unimplemented` but returns a fake value of the specified type.
///
/// Trap code: user65535
pub(crate) fn trap_unimplemented_ret_value<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl cranelift_module::Backend>,
    dest_layout: TyAndLayout<'tcx>,
    msg: impl AsRef<str>,
) -> CValue<'tcx> {
    trap_unimplemented(fx, msg);
    CValue::by_ref(Pointer::const_addr(fx, 0), dest_layout)
}
<commit_msg>Fix trap_unreachable_ret_value<commit_after>use crate::prelude::*;

fn codegen_print(fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>, msg: &str) {
    let puts = fx
        .module
        .declare_function(
            "puts",
            Linkage::Import,
            &Signature {
                call_conv: CallConv::triple_default(fx.triple()),
                params: vec![AbiParam::new(pointer_ty(fx.tcx))],
                returns: vec![AbiParam::new(types::I32)],
            },
        )
        .unwrap();
    let puts = fx.module.declare_func_in_func(puts, &mut fx.bcx.func);
    #[cfg(debug_assertions)]
    {
        fx.add_comment(puts, "puts");
    }

    let symbol_name = fx.tcx.symbol_name(fx.instance);
    let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, symbol_name, msg);
    let msg_ptr = fx.anonymous_str("trap", &real_msg);
    fx.bcx.ins().call(puts, &[msg_ptr]);
}

/// Use this when `rustc_codegen_llvm` would insert a call to the panic handler.
///
/// Trap code: user0
pub(crate) fn trap_panic(
    fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>,
    msg: impl AsRef<str>,
) {
    codegen_print(fx, msg.as_ref());
    fx.bcx.ins().trap(TrapCode::User(0));
}

/// Use this for example when a function call should never return. This will fill the current block,
/// so you can **not** add instructions to it afterwards.
///
/// Trap code: user65535
pub(crate) fn trap_unreachable(
    fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>,
    msg: impl AsRef<str>,
) {
    codegen_print(fx, msg.as_ref());
    fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
}

/// Like `trap_unreachable` but returns a fake value of the specified type.
///
/// Trap code: user65535
pub(crate) fn trap_unreachable_ret_value<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl cranelift_module::Backend>,
    dest_layout: TyAndLayout<'tcx>,
    msg: impl AsRef<str>,
) -> CValue<'tcx> {
    codegen_print(fx, msg.as_ref());
    let true_ = fx.bcx.ins().iconst(types::I32, 1);
    fx.bcx.ins().trapnz(true_, TrapCode::UnreachableCodeReached);
    CValue::by_ref(Pointer::const_addr(fx, 0), dest_layout)
}

/// Use this when something is unimplemented, but `libcore` or `libstd` requires it to codegen.
/// Unlike `trap_unreachable` this will not fill the current block, so you **must** add instructions
/// to it afterwards.
///
/// Trap code: user65535
pub(crate) fn trap_unimplemented(
    fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>,
    msg: impl AsRef<str>,
) {
    codegen_print(fx, msg.as_ref());
    let true_ = fx.bcx.ins().iconst(types::I32, 1);
    fx.bcx.ins().trapnz(true_, TrapCode::User(!0));
}

/// Like `trap_unimplemented` but returns a fake value of the specified type.
///
/// Trap code: user65535
pub(crate) fn trap_unimplemented_ret_value<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl cranelift_module::Backend>,
    dest_layout: TyAndLayout<'tcx>,
    msg: impl AsRef<str>,
) -> CValue<'tcx> {
    trap_unimplemented(fx, msg);
    CValue::by_ref(Pointer::const_addr(fx, 0), dest_layout)
}
<|endoftext|>


<commit_before>//! Window abstraction

use std::cell::RefCell;
use input::InputEvent;
use current::{ Get, Modifier, Set, Usage };

use GenericEvent;

/// Whether window should close or not.
pub struct ShouldClose(pub bool);

/// Work-around trait for `Get<ShouldClose>`.
/// Used to support generic constraints.
pub trait GetShouldClose: Get<ShouldClose> {
    /// Returns whether window should close.
    fn get_should_close(&self) -> ShouldClose {
        self.get()
    }
}

impl<T: Get<ShouldClose>> GetShouldClose for T {}

/// Work-around trait for `Set<ShouldClose>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetShouldClose: Set<ShouldClose> {
    /// Sets whether window should close.
    fn set_should_close(&mut self, val: ShouldClose);
}

/// The size of the window.
pub struct Size(pub [u32, ..2]);

/// Work-around trait for `Get<Size>`.
/// Used to support generic constraints.
pub trait GetSize: Get<Size> {
    /// Returns the size of window.
    fn get_size(&self) -> Size {
        self.get()
    }
}

impl<T: Get<Size>> GetSize for T {}

/// Work-around trait for `Set<Size>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetSize: Set<Size> {
    /// Sets size of window.
    fn set_size(&mut self, val: Size);
}

/// The title of the window.
pub struct Title(pub String);

/// Work-around trait for `Get<Title>`.
/// Used to support generic constraints.
pub trait GetTitle: Get<Title> {
    /// Returns the title of the window.
    fn get_title(&self) -> Title {
        self.get()
    }
}

impl<T: Get<Title>> GetTitle for T {}

/// Work-around trait for `Set<Title>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetTitle: Set<Title> {
    /// Sets title of window.
    fn set_title(&mut self, val: Title);
}

/// The anti-aliasing samples when rendering.
pub struct Samples(pub u8);

/// Work-around trait for `Get<Samples>`.
/// Used to support generic constraints.
pub trait GetSamples: Get<Samples> {
    /// Returns the antialiasing samples when rendering.
    fn get_samples(&self) -> Samples {
        self.get()
    }
}

impl<T: Get<Samples>> GetSamples for T {}

/// Work-around trait for `Set<Samples>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetSamples: Set<Samples> {
    /// Sets antialiasing samples of window.
    fn set_samples(&mut self, val: Samples);
}

/// Whether window is opened in full screen mode.
pub struct Fullscreen(pub bool);

/// Work-around trait for `Get<Fullscreen>`.
/// Used to support generic constraints.
pub trait GetFullscreen: Get<Fullscreen> {
    /// Returns whether window is in full screen mode.
    fn get_fullscreen(&self) -> Fullscreen {
        self.get()
    }
}

impl<T: Get<Fullscreen>> GetFullscreen for T {}

/// Work-around trait for `Set<Fullscreen>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetFullscreen: Set<Fullscreen> {
    /// Sets window to fullscreen mode.
    fn set_fullscreen(&mut self, val: Fullscreen);
}

/// Whether to exit when pressing the Esc keyboard button.
pub struct ExitOnEsc(pub bool);

/// Work-around trait for `Get<ExitOnEsc>`.
/// Used to support generic constraints.
pub trait GetExitOnEsc: Get<ExitOnEsc> {
    /// Returns whether window exits when pressing Esc.
    fn get_exit_on_esc(&self) -> ExitOnEsc {
        self.get()
    }
}

impl<T: Get<ExitOnEsc>> GetExitOnEsc for T {}

/// Work-around trait for `Set<ExitOnEsc>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetExitOnEsc: Set<ExitOnEsc> {
    /// Sets exit when pressing Esc.
    fn set_exit_on_esc(&mut self, val: ExitOnEsc);
}

/// Whether to capture the mouse cursor.
pub struct CaptureCursor(pub bool);

/// Work-around trait for `Get<CaptureCursor>`.
/// Used to support generic constraints.
pub trait GetCaptureCursor: Get<CaptureCursor> {
    /// Returns whether window captures cursor.
    fn get_capture_cursor(&self) -> CaptureCursor {
        self.get()
    }
}

impl<T: Get<CaptureCursor>> GetCaptureCursor for T {}

/// Work-around trait for `Set<CaptureCursor>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetCaptureCursor: Set<CaptureCursor> {
    /// Sets capture cursor.
    fn set_capture_cursor(&mut self, val: CaptureCursor);
}

/// The draw size of the window.
pub struct DrawSize(pub [u32, ..2]);

/// Work-around trait for `Get<DrawSize>`.
/// Used to support generic constraints.
pub trait GetDrawSize: Get<DrawSize> {
    /// Returns the draw size of window.
    fn get_draw_size(&self) -> DrawSize {
        self.get()
    }
}

impl<T: Get<DrawSize>> GetDrawSize for T {}

/// Work-around trait for `Set<DrawSize>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetDrawSize: Set<DrawSize> {
    /// Sets draw size.
    fn set_draw_size(&mut self, val: DrawSize);
}

#[test]
fn test_methods() {
    use current::Modifier;

    struct Obj;

    impl Get<ShouldClose> for Obj {
        fn get(&self) -> ShouldClose { ShouldClose(false) }
    }

    impl Modifier<Obj> for ShouldClose {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetShouldClose for Obj {
        fn set_should_close(&mut self, val: ShouldClose) {
            self.set_mut(val);
        }
    }

    impl Get<Size> for Obj {
        fn get(&self) -> Size { Size([0, 0]) }
    }

    impl Modifier<Obj> for Size {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetSize for Obj {
        fn set_size(&mut self, val: Size) {
            self.set_mut(val);
        }
    }

    impl Get<Title> for Obj {
        fn get(&self) -> Title { Title("hello".to_string()) }
    }

    impl Modifier<Obj> for Title {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetTitle for Obj {
        fn set_title(&mut self, val: Title) {
            self.set_mut(val);
        }
    }

    impl Get<Samples> for Obj {
        fn get(&self) -> Samples { Samples(0) }
    }

    impl Modifier<Obj> for Samples {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetSamples for Obj {
        fn set_samples(&mut self, val: Samples) {
            self.set_mut(val);
        }
    }

    impl Get<Fullscreen> for Obj {
        fn get(&self) -> Fullscreen { Fullscreen(false) }
    }

    impl Modifier<Obj> for Fullscreen {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetFullscreen for Obj {
        fn set_fullscreen(&mut self, val: Fullscreen) {
            self.set_mut(val);
        }
    }

    impl Get<ExitOnEsc> for Obj {
        fn get(&self) -> ExitOnEsc { ExitOnEsc(true) }
    }

    impl Modifier<Obj> for ExitOnEsc {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetExitOnEsc for Obj {
        fn set_exit_on_esc(&mut self, val: ExitOnEsc) {
            self.set_mut(val);
        }
    }

    impl Get<CaptureCursor> for Obj {
        fn get(&self) -> CaptureCursor { CaptureCursor(false) }
    }

    impl Modifier<Obj> for CaptureCursor {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetCaptureCursor for Obj {
        fn set_capture_cursor(&mut self, val: CaptureCursor) {
            self.set_mut(val);
        }
    }

    impl Get<DrawSize> for Obj {
        fn get(&self) -> DrawSize { DrawSize([0, 0]) }
    }

    impl Modifier<Obj> for DrawSize {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetDrawSize for Obj {
        fn set_draw_size(&mut self, val: DrawSize) {
            self.set_mut(val);
        }
    }

    fn foo<T: GetShouldClose + SetShouldClose
            + GetSize + SetSize
            + GetTitle + SetTitle
            + GetSamples + SetSamples
            + GetFullscreen + SetFullscreen
            + GetExitOnEsc + SetExitOnEsc
            + GetCaptureCursor + SetCaptureCursor
            + GetDrawSize + SetDrawSize>(_obj: T) {}

    foo(Obj);
}

/// Implemented by windows that can swap buffers.
pub trait SwapBuffers {
    /// Swaps the buffers.
    fn swap_buffers(&mut self);
}

impl<'a, W: 'a + SwapBuffers> SwapBuffers for Usage<'a, W> {
    #[inline(always)]
    fn swap_buffers(&mut self) {
        self.with_unwrap(|window: &RefCell<W>| {
            window.borrow_mut().deref_mut().swap_buffers()
        })
    }
}

impl<'a, W: 'a + SwapBuffers> SwapBuffers for &'a RefCell<W> {
    #[inline(always)]
    fn swap_buffers(&mut self) {
        self.borrow_mut().deref_mut().swap_buffers()
    }
}

/// Implemented by windows that can pull events.
pub trait PollEvent<E: GenericEvent> {
    /// Polls event from window.
    fn poll_event(&mut self) -> Option<E>;
}

impl<'a, W: 'a + PollEvent<I>, I: GenericEvent> PollEvent<I> for Usage<'a, W> {
    #[inline(always)]
    fn poll_event(&mut self) -> Option<I> {
        self.with_unwrap(|window: &RefCell<W>| {
            window.borrow_mut().deref_mut().poll_event()
        })
    }
}

impl<'a, W: 'a + PollEvent<I>, I: GenericEvent> PollEvent<I> for &'a RefCell<W> {
    #[inline(always)]
    fn poll_event(&mut self) -> Option<I> {
        self.borrow_mut().deref_mut().poll_event()
    }
}

/// Settings for window behavior.
pub struct WindowSettings {
    /// Title of the window.
    pub title: String,
    /// The size of the window.
    pub size: [u32, ..2],
    /// Number samples per pixel (anti-aliasing).
    pub samples: u8,
    /// If true, the window is fullscreen.
    pub fullscreen: bool,
    /// If true, exit when pressing Esc.
    pub exit_on_esc: bool,
}

impl WindowSettings {
    /// Gets default settings.
    ///
    /// This exits the window when pressing `Esc`.
    /// The background color is set to black.
    pub fn default() -> WindowSettings {
        WindowSettings {
            title: "Piston".to_string(),
            size: [640, 480],
            samples: 0,
            fullscreen: false,
            exit_on_esc: true,
        }
    }
}

/// Implemented by window back-end.
pub trait Window<E: GenericEvent = InputEvent>:
    SwapBuffers
  + PollEvent<E>
  + GetShouldClose
  + SetShouldClose
  + GetSize
  + SetCaptureCursor
  + GetDrawSize
  + GetTitle
  + SetTitle {}

/// An implementation of Window that runs without a window at all.
pub struct NoWindow {
    should_close: bool,
    title: String,
}

impl NoWindow {
    /// Returns a new `NoWindow`.
    pub fn new(settings: WindowSettings) -> NoWindow {
        let title = settings.title.clone();
        NoWindow {
            should_close: false,
            title: title,
        }
    }
}

impl SwapBuffers for NoWindow {
    fn swap_buffers(&mut self) {}
}

impl PollEvent<InputEvent> for NoWindow {
    fn poll_event(&mut self) -> Option<InputEvent> { None }
}

impl Get<ShouldClose> for NoWindow {
    fn get(&self) -> ShouldClose {
        ShouldClose(self.should_close)
    }
}

impl Get<Size> for NoWindow {
    fn get(&self) -> Size {
        Size([0, 0])
    }
}

impl Modifier<NoWindow> for CaptureCursor {
    fn modify(self, _window: &mut NoWindow) {}
}

impl SetCaptureCursor for NoWindow {
    fn set_capture_cursor(&mut self, val: CaptureCursor) {
        self.set_mut(val);
    }
}

impl Modifier<NoWindow> for ShouldClose {
    fn modify(self, window: &mut NoWindow) {
        let ShouldClose(val) = self;
        window.should_close = val;
    }
}

impl SetShouldClose for NoWindow {
    fn set_should_close(&mut self, val: ShouldClose) {
        self.set_mut(val);
    }
}

impl Get<DrawSize> for NoWindow {
    fn get(&self) -> DrawSize {
        let Size(val) = self.get();
        DrawSize(val)
    }
}

impl Window<InputEvent> for NoWindow {}

impl Get<Title> for NoWindow {
    fn get(&self) -> Title {
        Title(self.title.clone())
    }
}

impl Modifier<NoWindow> for Title {
    fn modify(self, window: &mut NoWindow) {
        let Title(val) = self;
        window.title = val;
    }
}

impl SetTitle for NoWindow {
    fn set_title(&mut self, val: Title) {
        self.set_mut(val);
    }
}

<commit_msg>Added `GetExitOnEsc` and `SetExitOnEsc` to Window trait<commit_after>//! Window abstraction

use std::cell::RefCell;
use input::InputEvent;
use current::{ Get, Modifier, Set, Usage };

use GenericEvent;

/// Whether window should close or not.
pub struct ShouldClose(pub bool);

/// Work-around trait for `Get<ShouldClose>`.
/// Used to support generic constraints.
pub trait GetShouldClose: Get<ShouldClose> {
    /// Returns whether window should close.
    fn get_should_close(&self) -> ShouldClose {
        self.get()
    }
}

impl<T: Get<ShouldClose>> GetShouldClose for T {}

/// Work-around trait for `Set<ShouldClose>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetShouldClose: Set<ShouldClose> {
    /// Sets whether window should close.
    fn set_should_close(&mut self, val: ShouldClose);
}

/// The size of the window.
pub struct Size(pub [u32, ..2]);

/// Work-around trait for `Get<Size>`.
/// Used to support generic constraints.
pub trait GetSize: Get<Size> {
    /// Returns the size of window.
    fn get_size(&self) -> Size {
        self.get()
    }
}

impl<T: Get<Size>> GetSize for T {}

/// Work-around trait for `Set<Size>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetSize: Set<Size> {
    /// Sets size of window.
    fn set_size(&mut self, val: Size);
}

/// The title of the window.
pub struct Title(pub String);

/// Work-around trait for `Get<Title>`.
/// Used to support generic constraints.
pub trait GetTitle: Get<Title> {
    /// Returns the title of the window.
    fn get_title(&self) -> Title {
        self.get()
    }
}

impl<T: Get<Title>> GetTitle for T {}

/// Work-around trait for `Set<Title>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetTitle: Set<Title> {
    /// Sets title of window.
    fn set_title(&mut self, val: Title);
}

/// The anti-aliasing samples when rendering.
pub struct Samples(pub u8);

/// Work-around trait for `Get<Samples>`.
/// Used to support generic constraints.
pub trait GetSamples: Get<Samples> {
    /// Returns the antialiasing samples when rendering.
    fn get_samples(&self) -> Samples {
        self.get()
    }
}

impl<T: Get<Samples>> GetSamples for T {}

/// Work-around trait for `Set<Samples>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetSamples: Set<Samples> {
    /// Sets antialiasing samples of window.
    fn set_samples(&mut self, val: Samples);
}

/// Whether window is opened in full screen mode.
pub struct Fullscreen(pub bool);

/// Work-around trait for `Get<Fullscreen>`.
/// Used to support generic constraints.
pub trait GetFullscreen: Get<Fullscreen> {
    /// Returns whether window is in full screen mode.
    fn get_fullscreen(&self) -> Fullscreen {
        self.get()
    }
}

impl<T: Get<Fullscreen>> GetFullscreen for T {}

/// Work-around trait for `Set<Fullscreen>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetFullscreen: Set<Fullscreen> {
    /// Sets window to fullscreen mode.
    fn set_fullscreen(&mut self, val: Fullscreen);
}

/// Whether to exit when pressing the Esc keyboard button.
pub struct ExitOnEsc(pub bool);

/// Work-around trait for `Get<ExitOnEsc>`.
/// Used to support generic constraints.
pub trait GetExitOnEsc: Get<ExitOnEsc> {
    /// Returns whether window exits when pressing Esc.
    fn get_exit_on_esc(&self) -> ExitOnEsc {
        self.get()
    }
}

impl<T: Get<ExitOnEsc>> GetExitOnEsc for T {}

/// Work-around trait for `Set<ExitOnEsc>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetExitOnEsc: Set<ExitOnEsc> {
    /// Sets exit when pressing Esc.
    fn set_exit_on_esc(&mut self, val: ExitOnEsc);
}

/// Whether to capture the mouse cursor.
pub struct CaptureCursor(pub bool);

/// Work-around trait for `Get<CaptureCursor>`.
/// Used to support generic constraints.
pub trait GetCaptureCursor: Get<CaptureCursor> {
    /// Returns whether window captures cursor.
    fn get_capture_cursor(&self) -> CaptureCursor {
        self.get()
    }
}

impl<T: Get<CaptureCursor>> GetCaptureCursor for T {}

/// Work-around trait for `Set<CaptureCursor>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetCaptureCursor: Set<CaptureCursor> {
    /// Sets capture cursor.
    fn set_capture_cursor(&mut self, val: CaptureCursor);
}

/// The draw size of the window.
pub struct DrawSize(pub [u32, ..2]);

/// Work-around trait for `Get<DrawSize>`.
/// Used to support generic constraints.
pub trait GetDrawSize: Get<DrawSize> {
    /// Returns the draw size of window.
    fn get_draw_size(&self) -> DrawSize {
        self.get()
    }
}

impl<T: Get<DrawSize>> GetDrawSize for T {}

/// Work-around trait for `Set<DrawSize>`.
/// Used to support generic constraints.
/// This must be implemented for every `Modifier` impl.
pub trait SetDrawSize: Set<DrawSize> {
    /// Sets draw size.
    fn set_draw_size(&mut self, val: DrawSize);
}

#[test]
fn test_methods() {
    use current::Modifier;

    struct Obj;

    impl Get<ShouldClose> for Obj {
        fn get(&self) -> ShouldClose { ShouldClose(false) }
    }

    impl Modifier<Obj> for ShouldClose {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetShouldClose for Obj {
        fn set_should_close(&mut self, val: ShouldClose) {
            self.set_mut(val);
        }
    }

    impl Get<Size> for Obj {
        fn get(&self) -> Size { Size([0, 0]) }
    }

    impl Modifier<Obj> for Size {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetSize for Obj {
        fn set_size(&mut self, val: Size) {
            self.set_mut(val);
        }
    }

    impl Get<Title> for Obj {
        fn get(&self) -> Title { Title("hello".to_string()) }
    }

    impl Modifier<Obj> for Title {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetTitle for Obj {
        fn set_title(&mut self, val: Title) {
            self.set_mut(val);
        }
    }

    impl Get<Samples> for Obj {
        fn get(&self) -> Samples { Samples(0) }
    }

    impl Modifier<Obj> for Samples {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetSamples for Obj {
        fn set_samples(&mut self, val: Samples) {
            self.set_mut(val);
        }
    }

    impl Get<Fullscreen> for Obj {
        fn get(&self) -> Fullscreen { Fullscreen(false) }
    }

    impl Modifier<Obj> for Fullscreen {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetFullscreen for Obj {
        fn set_fullscreen(&mut self, val: Fullscreen) {
            self.set_mut(val);
        }
    }

    impl Get<ExitOnEsc> for Obj {
        fn get(&self) -> ExitOnEsc { ExitOnEsc(true) }
    }

    impl Modifier<Obj> for ExitOnEsc {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetExitOnEsc for Obj {
        fn set_exit_on_esc(&mut self, val: ExitOnEsc) {
            self.set_mut(val);
        }
    }

    impl Get<CaptureCursor> for Obj {
        fn get(&self) -> CaptureCursor { CaptureCursor(false) }
    }

    impl Modifier<Obj> for CaptureCursor {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetCaptureCursor for Obj {
        fn set_capture_cursor(&mut self, val: CaptureCursor) {
            self.set_mut(val);
        }
    }

    impl Get<DrawSize> for Obj {
        fn get(&self) -> DrawSize { DrawSize([0, 0]) }
    }

    impl Modifier<Obj> for DrawSize {
        fn modify(self, _obj: &mut Obj) {}
    }

    impl SetDrawSize for Obj {
        fn set_draw_size(&mut self, val: DrawSize) {
            self.set_mut(val);
        }
    }

    fn foo<T: GetShouldClose + SetShouldClose
            + GetSize + SetSize
            + GetTitle + SetTitle
            + GetSamples + SetSamples
            + GetFullscreen + SetFullscreen
            + GetExitOnEsc + SetExitOnEsc
            + GetCaptureCursor + SetCaptureCursor
            + GetDrawSize + SetDrawSize>(_obj: T) {}

    foo(Obj);
}

/// Implemented by windows that can swap buffers.
pub trait SwapBuffers {
    /// Swaps the buffers.
    fn swap_buffers(&mut self);
}

impl<'a, W: 'a + SwapBuffers> SwapBuffers for Usage<'a, W> {
    #[inline(always)]
    fn swap_buffers(&mut self) {
        self.with_unwrap(|window: &RefCell<W>| {
            window.borrow_mut().deref_mut().swap_buffers()
        })
    }
}

impl<'a, W: 'a + SwapBuffers> SwapBuffers for &'a RefCell<W> {
    #[inline(always)]
    fn swap_buffers(&mut self) {
        self.borrow_mut().deref_mut().swap_buffers()
    }
}

/// Implemented by windows that can pull events.
pub trait PollEvent<E: GenericEvent> {
    /// Polls event from window.
    fn poll_event(&mut self) -> Option<E>;
}

impl<'a, W: 'a + PollEvent<I>, I: GenericEvent> PollEvent<I> for Usage<'a, W> {
    #[inline(always)]
    fn poll_event(&mut self) -> Option<I> {
        self.with_unwrap(|window: &RefCell<W>| {
            window.borrow_mut().deref_mut().poll_event()
        })
    }
}

impl<'a, W: 'a + PollEvent<I>, I: GenericEvent> PollEvent<I> for &'a RefCell<W> {
    #[inline(always)]
    fn poll_event(&mut self) -> Option<I> {
        self.borrow_mut().deref_mut().poll_event()
    }
}

/// Settings for window behavior.
pub struct WindowSettings {
    /// Title of the window.
    pub title: String,
    /// The size of the window.
    pub size: [u32, ..2],
    /// Number samples per pixel (anti-aliasing).
    pub samples: u8,
    /// If true, the window is fullscreen.
    pub fullscreen: bool,
    /// If true, exit when pressing Esc.
    pub exit_on_esc: bool,
}

impl WindowSettings {
    /// Gets default settings.
    ///
    /// This exits the window when pressing `Esc`.
    /// The background color is set to black.
    pub fn default() -> WindowSettings {
        WindowSettings {
            title: "Piston".to_string(),
            size: [640, 480],
            samples: 0,
            fullscreen: false,
            exit_on_esc: true,
        }
    }
}

/// Implemented by window back-end.
pub trait Window<E: GenericEvent = InputEvent>:
    SwapBuffers
  + PollEvent<E>
  + GetShouldClose + SetShouldClose
  + GetSize
  + SetCaptureCursor
  + GetDrawSize
  + GetTitle + SetTitle
  + GetExitOnEsc + SetExitOnEsc {}

/// An implementation of Window that runs without a window at all.
pub struct NoWindow {
    should_close: bool,
    title: String,
}

impl NoWindow {
    /// Returns a new `NoWindow`.
    pub fn new(settings: WindowSettings) -> NoWindow {
        let title = settings.title.clone();
        NoWindow {
            should_close: false,
            title: title,
        }
    }
}

impl SwapBuffers for NoWindow {
    fn swap_buffers(&mut self) {}
}

impl PollEvent<InputEvent> for NoWindow {
    fn poll_event(&mut self) -> Option<InputEvent> { None }
}

impl Get<ShouldClose> for NoWindow {
    fn get(&self) -> ShouldClose {
        ShouldClose(self.should_close)
    }
}

impl Get<Size> for NoWindow {
    fn get(&self) -> Size {
        Size([0, 0])
    }
}

impl Modifier<NoWindow> for CaptureCursor {
    fn modify(self, _window: &mut NoWindow) {}
}

impl SetCaptureCursor for NoWindow {
    fn set_capture_cursor(&mut self, val: CaptureCursor) {
        self.set_mut(val);
    }
}

impl Modifier<NoWindow> for ShouldClose {
    fn modify(self, window: &mut NoWindow) {
        let ShouldClose(val) = self;
        window.should_close = val;
    }
}

impl SetShouldClose for NoWindow {
    fn set_should_close(&mut self, val: ShouldClose) {
        self.set_mut(val);
    }
}

impl Get<DrawSize> for NoWindow {
    fn get(&self) -> DrawSize {
        let Size(val) = self.get();
        DrawSize(val)
    }
}

impl Window<InputEvent> for NoWindow {}

impl Get<Title> for NoWindow {
    fn get(&self) -> Title {
        Title(self.title.clone())
    }
}

impl Modifier<NoWindow> for Title {
    fn modify(self, window: &mut NoWindow) {
        let Title(val) = self;
        window.title = val;
    }
}

impl SetTitle for NoWindow {
    fn set_title(&mut self, val: Title) {
        self.set_mut(val);
    }
}

impl Get<ExitOnEsc> for NoWindow {
    fn get(&self) -> ExitOnEsc {
        ExitOnEsc(false)
    }
}

impl Modifier<NoWindow> for ExitOnEsc {
    // Ignore attempt to exit by pressing Esc.
    fn modify(self, _window: &mut NoWindow) {}
}

impl SetExitOnEsc for NoWindow {
    fn set_exit_on_esc(&mut self, val: ExitOnEsc) {
        self.set_mut(val);
    }
}

<|endoftext|>


<commit_before>//! Unix-specific types for signal handling.
//!
//! This module is only defined on Unix platforms and contains the primary
//! `Signal` type for receiving notifications of signals.

#![cfg(unix)]

pub extern crate libc;
extern crate mio;
extern crate tokio_uds;

use std::cell::RefCell;
use std::io::{self, Write, Read};
use std::mem;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Once, ONCE_INIT, Mutex};

use futures::stream::{Stream, Fuse};
use futures::{self, Future, IntoFuture, Complete, Oneshot, Poll, Async};
use self::libc::c_int;
use self::tokio_uds::UnixStream;
use tokio_core::io::IoFuture;
use tokio_core::reactor::{PollEvented, Handle};
use tokio_core::channel::{channel, Sender, Receiver};

static INIT: Once = ONCE_INIT;
static mut GLOBAL_STATE: *mut GlobalState = 0 as *mut _;

/// An implementation of `Stream` for receiving a particular type of signal.
///
/// This structure implements the `Stream` trait and represents notifications
/// of the current process receiving a particular signal. The signal being
/// listened for is passed to `Signal::new`, and the same signal number is then
/// yielded as each element for the stream.
///
/// In general signal handling on Unix is a pretty tricky topic, and this
/// structure is no exception! There are some important limitations to keep in
/// mind when using `Signal` streams:
///
/// * While multiple event loops are supported, the *first* event loop to
///   register a signal handler is required to be active to ensure that signals
///   for other event loops are delivered. In other words, once an event loop
///   registers a signal, it's best to keep it around and running. This is
///   normally just a problem for tests, and the "workaround" is to spawn a
///   thread in the background at the beginning of the test suite which is
///   running an event loop (and listening for a signal).
///
/// * Signals handling in Unix already necessitates coalescing signals
///   together sometimes. This `Signal` stream is also no exception here in
///   that it will also coalesce signals. That is, even if the signal handler
///   for this process runs multiple times, the `Signal` stream may only return
///   one signal notification. Specifically, before `poll` is called, all
///   signal notifications are coalesced into one item returned from `poll`.
///   Once `poll` has been called, however, a further signal is guaranteed to
///   be yielded as an item.
///
/// * Signal handling in general is relatively inefficient. Although some
///   improvements are possible in this crate, it's recommended to not plan on
///   having millions of signal channels open.
///
/// * Currently the "driver task" to process incoming signals never exits.
///
/// If you've got any questions about this feel free to open an issue on the
/// repo, though, as I'd love to chat about this! In other words, I'd love to
/// alleviate some of these limitations if possible!
pub struct Signal {
    signum: c_int,
    reg: PollEvented<MyRegistration>,
    _finished: Complete<()>,
}

struct GlobalState {
    write: UnixStream,
    tx: Mutex<Sender<Message>>,
    signals: [GlobalSignalState; 32],
}

struct GlobalSignalState {
    ready: AtomicBool,
    prev: libc::sigaction,
}

enum Message {
    NewSignal(c_int, Complete<io::Result<Signal>>),
}

struct DriverTask {
    handle: Handle,
    read: UnixStream,
    rx: Fuse<Receiver<Message>>,
    signals: [SignalState; 32],
}

struct SignalState {
    registered: bool,
    tasks: Vec<(RefCell<Oneshot<()>>, mio::SetReadiness)>,
}

impl Signal {
    /// Creates a new stream which will receive notifications when the current
    /// process receives the signal `signum`.
    ///
    /// This function will create a new stream which may be based on the
    /// event loop handle provided. This function returns a future which will
    /// then resolve to the signal stream, if successful.
    ///
    /// The `Signal` stream is an infinite stream which will receive
    /// notifications whenever a signal is received. More documentation can be
    /// found on `Signal` itself, but to reiterate:
    ///
    /// * Signals may be coalesced beyond what the kernel already does.
    /// * While multiple event loops are supported, the first event loop to
    ///   register a signal handler must be active to deliver signal
    ///   notifications
    /// * Once a signal handle is registered with the process the underlying
    ///   libc signal handler is never unregistered.
    ///
    /// A `Signal` stream can be created for a particular signal number
    /// multiple times. When a signal is received then all the associated
    /// channels will receive the signal notification.
    pub fn new(signum: c_int, handle: &Handle) -> IoFuture<Signal> {
        let mut init = None;
        INIT.call_once(|| {
            init = Some(global_init(handle));
        });
        let new_signal = futures::lazy(move || {
            let (tx, rx) = futures::oneshot();
            let msg = Message::NewSignal(signum, tx);
            let res = unsafe {
                (*GLOBAL_STATE).tx.lock().unwrap().send(msg)
            };
            res.expect("failed to request a new signal stream, did the \
                        first event loop go away?");
            rx.then(|r| r.unwrap())
        });
        match init {
            Some(init) => init.into_future().and_then(|()| new_signal).boxed(),
            None => new_signal.boxed(),
        }
    }
}

impl Stream for Signal {
    type Item = c_int;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<c_int>, io::Error> {
        if !self.reg.poll_read().is_ready() {
            return Ok(Async::NotReady)
        }
        self.reg.need_read();
        self.reg.get_ref()
                .inner.borrow()
                .as_ref().unwrap().1
                .set_readiness(mio::Ready::none())
                .expect("failed to set readiness");
        Ok(Async::Ready(Some(self.signum)))
    }
}

fn global_init(handle: &Handle) -> io::Result<()> {
    let (tx, rx) = try!(channel(handle));
    let (read, write) = try!(UnixStream::pair(handle));
    unsafe {
        let state = Box::new(GlobalState {
            write: write,
            signals: {
                fn new() -> GlobalSignalState {
                    GlobalSignalState {
                        ready: AtomicBool::new(false),
                        prev: unsafe { mem::zeroed() },
                    }
                }
                [
                    new(), new(), new(), new(), new(), new(), new(), new(),
                    new(), new(), new(), new(), new(), new(), new(), new(),
                    new(), new(), new(), new(), new(), new(), new(), new(),
                    new(), new(), new(), new(), new(), new(), new(), new(),
                ]
            },
            tx: Mutex::new(tx.clone()),
        });
        GLOBAL_STATE = Box::into_raw(state);

        handle.spawn(DriverTask {
            handle: handle.clone(),
            rx: rx.fuse(),
            read: read,
            signals: {
                fn new() -> SignalState {
                    SignalState { registered: false, tasks: Vec::new() }
                }
                [
                    new(), new(), new(), new(), new(), new(), new(), new(),
                    new(), new(), new(), new(), new(), new(), new(), new(),
                    new(), new(), new(), new(), new(), new(), new(), new(),
                    new(), new(), new(), new(), new(), new(), new(), new(),
                ]
            },
        });

        Ok(())
    }
}

impl Future for DriverTask {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        self.check_signal_drops();
        self.check_messages();
        self.check_signals();

        // TODO: when to finish this task?
        Ok(Async::NotReady)
    }
}

impl DriverTask {
    fn check_signal_drops(&mut self) {
        for signal in self.signals.iter_mut() {
            signal.tasks.retain(|task| {
                !task.0.borrow_mut().poll().is_err()
            });
        }
    }

    fn check_messages(&mut self) {
        loop {
            // Acquire the next message
            let message = match self.rx.poll() {
                Ok(Async::Ready(Some(e))) => e,
                Ok(Async::Ready(None)) |
                Ok(Async::NotReady) => break,
                Err(e) => panic!("error on rx: {}", e),
            };
            let (sig, complete) = match message {
                Message::NewSignal(sig, complete) => (sig, complete),
            };

            // If the signal's too large, then we return an error, otherwise we
            // use this index to look at the signal slot.
            //
            // If the signal wasn't previously registered then we do so now.
            let signal = match self.signals.get_mut(sig as usize) {
                Some(signal) => signal,
                None => {
                    complete.complete(Err(io::Error::new(io::ErrorKind::Other,
                                                         "signum too large")));
                    continue
                }
            };
            if !signal.registered {
                unsafe {
                    let mut new: libc::sigaction = mem::zeroed();
                    new.sa_sigaction = handler as usize;
                    new.sa_flags = libc::SA_RESTART | libc::SA_SIGINFO;
                    let mut prev = mem::zeroed();
                    if libc::sigaction(sig, &new, &mut prev) != 0 {
                        complete.complete(Err(io::Error::last_os_error()));
                        continue
                    }
                    signal.registered = true;
                }
            }

            // Acquire the (registration, set_readiness) pair by... assuming
            // we're on the event loop (true because of the spawn above).
            let reg = MyRegistration { inner: RefCell::new(None) };
            let reg = match PollEvented::new(reg, &self.handle) {
                Ok(reg) => reg,
                Err(e) => {
                    complete.complete(Err(e));
                    continue
                }
            };

            // Create the `Signal` to pass back and then also keep a handle to
            // the `SetReadiness` for ourselves internally.
            let (tx, rx) = futures::oneshot();
            let ready = reg.get_ref().inner.borrow_mut().as_mut().unwrap().1.clone();
            complete.complete(Ok(Signal {
                signum: sig,
                reg: reg,
                _finished: tx,
            }));
            signal.tasks.push((RefCell::new(rx), ready));
        }
    }

    fn check_signals(&mut self) {
        // Drain all data from the pipe
        let mut buf = [0; 32];
        let mut any = false;
        loop {
            match self.read.read(&mut buf) {
                Ok(0) => {  // EOF == something happened
                    any = true;
                    break
                }
                Ok(..) => any = true,   // data read, but keep draining
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => break,
                Err(e) => panic!("bad read: {}", e),
            }
        }

        // If nothing happened, no need to check the signals
        if !any {
            return
        }

        for (i, slot) in self.signals.iter().enumerate() {
            // No need to go farther if we haven't even registered a signal
            if !slot.registered {
                continue
            }

            // See if this signal actually happened since we last checked
            unsafe {
                if !(*GLOBAL_STATE).signals[i].ready.swap(false, Ordering::SeqCst) {
                    continue
                }
            }

            // Wake up all the tasks waiting on this signal
            for task in slot.tasks.iter() {
                task.1.set_readiness(mio::Ready::readable())
                      .expect("failed to set readiness");
            }
        }
    }
}

extern fn handler(signum: c_int,
                  info: *mut libc::siginfo_t,
                  ptr: *mut libc::c_void) {
    type FnSigaction = extern fn(c_int, *mut libc::siginfo_t, *mut libc::c_void);
    type FnHandler = extern fn(c_int);

    unsafe {
        let state = match (*GLOBAL_STATE).signals.get(signum as usize) {
            Some(state) => state,
            None => return,
        };

        if !state.ready.swap(true, Ordering::SeqCst) {
            match (&(*GLOBAL_STATE).write).write(&[1]) {
                Ok(..) => {}
                Err(e) => {
                    if e.kind() != io::ErrorKind::WouldBlock {
                        panic!("bad error on write fd: {}", e)
                    }
                }
            }
        }

        let fnptr = state.prev.sa_sigaction;
        if fnptr == 0 || fnptr == libc::SIG_DFL || fnptr == libc::SIG_IGN {
            return
        }
        if state.prev.sa_flags & libc::SA_SIGINFO == 0 {
            let action = mem::transmute::<usize, FnHandler>(fnptr);
            action(signum)
        } else {
            let action = mem::transmute::<usize, FnSigaction>(fnptr);
            action(signum, info, ptr)
        }
    }
}

struct MyRegistration {
    inner: RefCell<Option<(mio::Registration, mio::SetReadiness)>>,
}

impl mio::Evented for MyRegistration {
    fn register(&self,
                poll: &mio::Poll,
                token: mio::Token,
                events: mio::Ready,
                opts: mio::PollOpt) -> io::Result<()> {
        let reg = mio::Registration::new(poll, token, events, opts);
        *self.inner.borrow_mut() = Some(reg);
        Ok(())
    }

    fn reregister(&self,
                  _poll: &mio::Poll,
                  _token: mio::Token,
                  _events: mio::Ready,
                  _opts: mio::PollOpt) -> io::Result<()> {
        Ok(())
    }

    fn deregister(&self, _poll: &mio::Poll) -> io::Result<()> {
        Ok(())
    }
}
<commit_msg>signal: Add symbolic reexports for common signals<commit_after>//! Unix-specific types for signal handling.
//!
//! This module is only defined on Unix platforms and contains the primary
//! `Signal` type for receiving notifications of signals.

#![cfg(unix)]

pub extern crate libc;
extern crate mio;
extern crate tokio_uds;

use std::cell::RefCell;
use std::io::{self, Write, Read};
use std::mem;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Once, ONCE_INIT, Mutex};

use futures::stream::{Stream, Fuse};
use futures::{self, Future, IntoFuture, Complete, Oneshot, Poll, Async};
use self::libc::c_int;
use self::tokio_uds::UnixStream;
use tokio_core::io::IoFuture;
use tokio_core::reactor::{PollEvented, Handle};
use tokio_core::channel::{channel, Sender, Receiver};

static INIT: Once = ONCE_INIT;
static mut GLOBAL_STATE: *mut GlobalState = 0 as *mut _;

/// An implementation of `Stream` for receiving a particular type of signal.
///
/// This structure implements the `Stream` trait and represents notifications
/// of the current process receiving a particular signal. The signal being
/// listened for is passed to `Signal::new`, and the same signal number is then
/// yielded as each element for the stream.
///
/// In general signal handling on Unix is a pretty tricky topic, and this
/// structure is no exception! There are some important limitations to keep in
/// mind when using `Signal` streams:
///
/// * While multiple event loops are supported, the *first* event loop to
///   register a signal handler is required to be active to ensure that signals
///   for other event loops are delivered. In other words, once an event loop
///   registers a signal, it's best to keep it around and running. This is
///   normally just a problem for tests, and the "workaround" is to spawn a
///   thread in the background at the beginning of the test suite which is
///   running an event loop (and listening for a signal).
///
/// * Signals handling in Unix already necessitates coalescing signals
///   together sometimes. This `Signal` stream is also no exception here in
///   that it will also coalesce signals. That is, even if the signal handler
///   for this process runs multiple times, the `Signal` stream may only return
///   one signal notification. Specifically, before `poll` is called, all
///   signal notifications are coalesced into one item returned from `poll`.
///   Once `poll` has been called, however, a further signal is guaranteed to
///   be yielded as an item.
///
/// * Signal handling in general is relatively inefficient. Although some
///   improvements are possible in this crate, it's recommended to not plan on
///   having millions of signal channels open.
///
/// * Currently the "driver task" to process incoming signals never exits.
///
/// If you've got any questions about this feel free to open an issue on the
/// repo, though, as I'd love to chat about this! In other words, I'd love to
/// alleviate some of these limitations if possible!
pub struct Signal {
    signum: c_int,
    reg: PollEvented<MyRegistration>,
    _finished: Complete<()>,
}

struct GlobalState {
    write: UnixStream,
    tx: Mutex<Sender<Message>>,
    signals: [GlobalSignalState; 32],
}

struct GlobalSignalState {
    ready: AtomicBool,
    prev: libc::sigaction,
}

enum Message {
    NewSignal(c_int, Complete<io::Result<Signal>>),
}

struct DriverTask {
    handle: Handle,
    read: UnixStream,
    rx: Fuse<Receiver<Message>>,
    signals: [SignalState; 32],
}

struct SignalState {
    registered: bool,
    tasks: Vec<(RefCell<Oneshot<()>>, mio::SetReadiness)>,
}

pub use self::libc::{SIGINT, SIGKILL, SIGTERM, SIGUSR1, SIGUSR2};
pub use self::libc::{SIGHUP, SIGQUIT, SIGPIPE, SIGALRM, SIGTRAP};

impl Signal {
    /// Creates a new stream which will receive notifications when the current
    /// process receives the signal `signum`.
    ///
    /// This function will create a new stream which may be based on the
    /// event loop handle provided. This function returns a future which will
    /// then resolve to the signal stream, if successful.
    ///
    /// The `Signal` stream is an infinite stream which will receive
    /// notifications whenever a signal is received. More documentation can be
    /// found on `Signal` itself, but to reiterate:
    ///
    /// * Signals may be coalesced beyond what the kernel already does.
    /// * While multiple event loops are supported, the first event loop to
    ///   register a signal handler must be active to deliver signal
    ///   notifications
    /// * Once a signal handle is registered with the process the underlying
    ///   libc signal handler is never unregistered.
    ///
    /// A `Signal` stream can be created for a particular signal number
    /// multiple times. When a signal is received then all the associated
    /// channels will receive the signal notification.
    pub fn new(signum: c_int, handle: &Handle) -> IoFuture<Signal> {
        let mut init = None;
        INIT.call_once(|| {
            init = Some(global_init(handle));
        });
        let new_signal = futures::lazy(move || {
            let (tx, rx) = futures::oneshot();
            let msg = Message::NewSignal(signum, tx);
            let res = unsafe {
                (*GLOBAL_STATE).tx.lock().unwrap().send(msg)
            };
            res.expect("failed to request a new signal stream, did the \
                        first event loop go away?");
            rx.then(|r| r.unwrap())
        });
        match init {
            Some(init) => init.into_future().and_then(|()| new_signal).boxed(),
            None => new_signal.boxed(),
        }
    }
}

impl Stream for Signal {
    type Item = c_int;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<c_int>, io::Error> {
        if !self.reg.poll_read().is_ready() {
            return Ok(Async::NotReady)
        }
        self.reg.need_read();
        self.reg.get_ref()
                .inner.borrow()
                .as_ref().unwrap().1
                .set_readiness(mio::Ready::none())
                .expect("failed to set readiness");
        Ok(Async::Ready(Some(self.signum)))
    }
}

fn global_init(handle: &Handle) -> io::Result<()> {
    let (tx, rx) = try!(channel(handle));
    let (read, write) = try!(UnixStream::pair(handle));
    unsafe {
        let state = Box::new(GlobalState {
            write: write,
            signals: {
                fn new() -> GlobalSignalState {
                    GlobalSignalState {
                        ready: AtomicBool::new(false),
                        prev: unsafe { mem::zeroed() },
                    }
                }
                [
                    new(), new(), new(), new(), new(), new(), new(), new(),
                    new(), new(), new(), new(), new(), new(), new(), new(),
                    new(), new(), new(), new(), new(), new(), new(), new(),
                    new(), new(), new(), new(), new(), new(), new(), new(),
                ]
            },
            tx: Mutex::new(tx.clone()),
        });
        GLOBAL_STATE = Box::into_raw(state);

        handle.spawn(DriverTask {
            handle: handle.clone(),
            rx: rx.fuse(),
            read: read,
            signals: {
                fn new() -> SignalState {
                    SignalState { registered: false, tasks: Vec::new() }
                }
                [
                    new(), new(), new(), new(), new(), new(), new(), new(),
                    new(), new(), new(), new(), new(), new(), new(), new(),
                    new(), new(), new(), new(), new(), new(), new(), new(),
                    new(), new(), new(), new(), new(), new(), new(), new(),
                ]
            },
        });

        Ok(())
    }
}

impl Future for DriverTask {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        self.check_signal_drops();
        self.check_messages();
        self.check_signals();

        // TODO: when to finish this task?
        Ok(Async::NotReady)
    }
}

impl DriverTask {
    fn check_signal_drops(&mut self) {
        for signal in self.signals.iter_mut() {
            signal.tasks.retain(|task| {
                !task.0.borrow_mut().poll().is_err()
            });
        }
    }

    fn check_messages(&mut self) {
        loop {
            // Acquire the next message
            let message = match self.rx.poll() {
                Ok(Async::Ready(Some(e))) => e,
                Ok(Async::Ready(None)) |
                Ok(Async::NotReady) => break,
                Err(e) => panic!("error on rx: {}", e),
            };
            let (sig, complete) = match message {
                Message::NewSignal(sig, complete) => (sig, complete),
            };

            // If the signal's too large, then we return an error, otherwise we
            // use this index to look at the signal slot.
            //
            // If the signal wasn't previously registered then we do so now.
            let signal = match self.signals.get_mut(sig as usize) {
                Some(signal) => signal,
                None => {
                    complete.complete(Err(io::Error::new(io::ErrorKind::Other,
                                                         "signum too large")));
                    continue
                }
            };
            if !signal.registered {
                unsafe {
                    let mut new: libc::sigaction = mem::zeroed();
                    new.sa_sigaction = handler as usize;
                    new.sa_flags = libc::SA_RESTART | libc::SA_SIGINFO;
                    let mut prev = mem::zeroed();
                    if libc::sigaction(sig, &new, &mut prev) != 0 {
                        complete.complete(Err(io::Error::last_os_error()));
                        continue
                    }
                    signal.registered = true;
                }
            }

            // Acquire the (registration, set_readiness) pair by... assuming
            // we're on the event loop (true because of the spawn above).
            let reg = MyRegistration { inner: RefCell::new(None) };
            let reg = match PollEvented::new(reg, &self.handle) {
                Ok(reg) => reg,
                Err(e) => {
                    complete.complete(Err(e));
                    continue
                }
            };

            // Create the `Signal` to pass back and then also keep a handle to
            // the `SetReadiness` for ourselves internally.
            let (tx, rx) = futures::oneshot();
            let ready = reg.get_ref().inner.borrow_mut().as_mut().unwrap().1.clone();
            complete.complete(Ok(Signal {
                signum: sig,
                reg: reg,
                _finished: tx,
            }));
            signal.tasks.push((RefCell::new(rx), ready));
        }
    }

    fn check_signals(&mut self) {
        // Drain all data from the pipe
        let mut buf = [0; 32];
        let mut any = false;
        loop {
            match self.read.read(&mut buf) {
                Ok(0) => {  // EOF == something happened
                    any = true;
                    break
                }
                Ok(..) => any = true,   // data read, but keep draining
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => break,
                Err(e) => panic!("bad read: {}", e),
            }
        }

        // If nothing happened, no need to check the signals
        if !any {
            return
        }

        for (i, slot) in self.signals.iter().enumerate() {
            // No need to go farther if we haven't even registered a signal
            if !slot.registered {
                continue
            }

            // See if this signal actually happened since we last checked
            unsafe {
                if !(*GLOBAL_STATE).signals[i].ready.swap(false, Ordering::SeqCst) {
                    continue
                }
            }

            // Wake up all the tasks waiting on this signal
            for task in slot.tasks.iter() {
                task.1.set_readiness(mio::Ready::readable())
                      .expect("failed to set readiness");
            }
        }
    }
}

extern fn handler(signum: c_int,
                  info: *mut libc::siginfo_t,
                  ptr: *mut libc::c_void) {
    type FnSigaction = extern fn(c_int, *mut libc::siginfo_t, *mut libc::c_void);
    type FnHandler = extern fn(c_int);

    unsafe {
        let state = match (*GLOBAL_STATE).signals.get(signum as usize) {
            Some(state) => state,
            None => return,
        };

        if !state.ready.swap(true, Ordering::SeqCst) {
            match (&(*GLOBAL_STATE).write).write(&[1]) {
                Ok(..) => {}
                Err(e) => {
                    if e.kind() != io::ErrorKind::WouldBlock {
                        panic!("bad error on write fd: {}", e)
                    }
                }
            }
        }

        let fnptr = state.prev.sa_sigaction;
        if fnptr == 0 || fnptr == libc::SIG_DFL || fnptr == libc::SIG_IGN {
            return
        }
        if state.prev.sa_flags & libc::SA_SIGINFO == 0 {
            let action = mem::transmute::<usize, FnHandler>(fnptr);
            action(signum)
        } else {
            let action = mem::transmute::<usize, FnSigaction>(fnptr);
            action(signum, info, ptr)
        }
    }
}

struct MyRegistration {
    inner: RefCell<Option<(mio::Registration, mio::SetReadiness)>>,
}

impl mio::Evented for MyRegistration {
    fn register(&self,
                poll: &mio::Poll,
                token: mio::Token,
                events: mio::Ready,
                opts: mio::PollOpt) -> io::Result<()> {
        let reg = mio::Registration::new(poll, token, events, opts);
        *self.inner.borrow_mut() = Some(reg);
        Ok(())
    }

    fn reregister(&self,
                  _poll: &mio::Poll,
                  _token: mio::Token,
                  _events: mio::Ready,
                  _opts: mio::PollOpt) -> io::Result<()> {
        Ok(())
    }

    fn deregister(&self, _poll: &mio::Poll) -> io::Result<()> {
        Ok(())
    }
}
<|endoftext|>


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

//! base class automating dispatcher communication via ZMQ

extern crate zmq;
extern crate rand;
extern crate tempfile;

use zmq::{Error, Message, Context, SNDMORE};
use std::ops::Deref;
use std::thread;
use std::time::Duration;
use std::env;
use std::fs::File;
use std::io::{Read,Write, Seek, SeekFrom};
use std::path::Path;
// use std::str;
use std::process::Command;

/// Generic requirements for CorTeX workers
pub trait Worker {
  /// Core processing method
  fn convert(&self, &Path) -> Option<File>;
  /// Size of chunk for network communication, larger implies less IO, smaller implies less RAM use
  fn message_size(&self) -> usize;
  /// Name of the service, as registered in CorTeX
  fn service(&self) -> String;
  /// URL to the CorTeX dispatcher
  fn source(&self) -> String;
  /// URL to the CorTeX sink
  fn sink(&self) -> String;
  /// main worker loop, works in perpetuity or up to a specified `limit`
  fn start(&self, limit : Option<usize>) -> Result<(), Error> {
    let mut work_counter = 0;
    // Connect to a task ventilator
    let mut context_source = Context::new();
    let mut source = context_source.socket(zmq::DEALER).unwrap();
    let identity : String = (0..10).map(|_| rand::random::<u8>() as char).collect();
    source.set_identity(identity.as_bytes()).unwrap();

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

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

      // Prepare a File for the input
      let input_filepath = env::temp_dir().to_str().unwrap().to_string() + "/" + taskid ;
      let mut file = File::create(input_filepath.clone()).unwrap();
      loop {
        source.recv(&mut recv_msg, 0).unwrap();

        file.write(recv_msg.deref()).unwrap();
        if !source.get_rcvmore().unwrap() {
          break;
        }
      }

      file.seek(SeekFrom::Start(0)).unwrap();
      let file_opt = self.convert(Path::new(&input_filepath));
      if file_opt.is_some() {
        let mut converted_file = file_opt.unwrap();
        sink.send_str(&self.service(), SNDMORE).unwrap();
        sink.send_str(taskid, SNDMORE).unwrap();
        loop {
          // Stream converted data via zmq
          let message_size = self.message_size();
          let mut data = vec![0; message_size];
          let size = converted_file.read(&mut data).unwrap();
          data.truncate(size);
          if size < message_size {
            // If exhausted, send the last frame
            sink.send(&data,0).unwrap();
            // And terminate
            break;
          } else {
            // If more to go, send the frame and indicate there's more to come
            sink.send(&data,SNDMORE).unwrap();
          }
        }
      }
      else {
        // If there was nothing to do, retry a minute later
        thread::sleep(Duration::new(60,0));
        continue
      }

      work_counter += 1;
      match limit {
        Some(upper_bound) => {
          if work_counter >= upper_bound {
            // Give enough time to complete the Final job.
            thread::sleep(Duration::new(1,0));
            break;
          }
        },
        None => {}
      };
    }
    Ok(())
  }
}
/// An echo worker for testing
pub struct EchoWorker {
  /// the usual
  pub service : String,
  /// the usual
  pub version : f32,
  /// the usual
  pub message_size : usize,
  /// the usual
  pub source : String,
  /// the usual
  pub sink : String
}
impl Default for EchoWorker {
  fn default() -> EchoWorker {
    EchoWorker {
      service: "echo_service".to_string(),
      version: 0.1,
      message_size: 100000,
      source: "tcp://localhost:5555".to_string(),
      sink: "tcp://localhost:5556".to_string()
    }
  }
}
impl Worker for EchoWorker {
  fn service(&self) -> String {self.service.clone()}
  fn source(&self) -> String {self.source.clone()}
  fn sink(&self) -> String {self.sink.clone()}
  fn message_size(&self) -> usize {self.message_size.clone()}

  fn convert(&self, path : &Path) -> Option<File> {
    Some(File::open(path).unwrap())
  }
}
/// A TeX to HTML conversion worker
pub struct TexToHtmlWorker {
  /// the usual
  pub service : String,
  /// the usual
  pub version : f32,
  /// the usual
  pub message_size : usize,
  /// the usual
  pub source : String,
  /// the usual
  pub sink : String
}
impl Default for TexToHtmlWorker {
  fn default() -> TexToHtmlWorker {
    TexToHtmlWorker {
      service: "tex_to_html".to_string(),
      version: 0.1,
      message_size: 100000,
      source: "tcp://localhost:5555".to_string(),
      sink: "tcp://localhost:5556".to_string()
    }
  }
}
impl Worker for TexToHtmlWorker {
  fn service(&self) -> String {self.service.clone()}
  fn source(&self) -> String {self.source.clone()}
  fn sink(&self) -> String {self.sink.clone()}
  fn message_size(&self) -> usize {self.message_size.clone()}

  fn convert(&self, path : &Path) -> Option<File> {
    let name = path.file_stem().unwrap().to_str().unwrap();
    let destination_path = env::temp_dir().to_str().unwrap().to_string() + "/" +name+ ".zip";
    println!("Source {:?}", path);
    Command::new("latexmlc")
      .arg("--whatsin")
      .arg("archive")
      .arg("--whatsout")
      .arg("archive")
      .arg("--format")
      .arg("html5")
      .arg("--pmml")
      .arg("--cmml")
      .arg("--mathtex")
      .arg("--preload")
      .arg("[ids]latexml.sty")
      .arg("--nodefaultresources")
      .arg("--inputencoding")
      .arg("iso-8859-1")
      .arg("--timeout")
      .arg("300")
      .arg("--log")
      .arg("cortex.log")
      .arg("--destination")
      .arg(destination_path.clone())
      .arg(path.clone())
      .output()
      .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

    println!("Dest: {:?}", destination_path);
    let file_test = File::open(destination_path.clone());
    match file_test {
      Ok(file) => Some(file),
      Err(_) => None
    }
  }
}
<commit_msg>force zip extension for tex_to_html input files<commit_after>// Copyright 2015 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.

//! base class automating dispatcher communication via ZMQ

extern crate zmq;
extern crate rand;
extern crate tempfile;

use zmq::{Error, Message, Context, SNDMORE};
use std::ops::Deref;
use std::thread;
use std::time::Duration;
use std::env;
use std::fs::File;
use std::io::{Read,Write, Seek, SeekFrom};
use std::path::Path;
// use std::str;
use std::process::Command;

/// Generic requirements for CorTeX workers
pub trait Worker {
  /// Core processing method
  fn convert(&self, &Path) -> Option<File>;
  /// Size of chunk for network communication, larger implies less IO, smaller implies less RAM use
  fn message_size(&self) -> usize;
  /// Name of the service, as registered in CorTeX
  fn service(&self) -> String;
  /// URL to the CorTeX dispatcher
  fn source(&self) -> String;
  /// URL to the CorTeX sink
  fn sink(&self) -> String;
  /// main worker loop, works in perpetuity or up to a specified `limit`
  fn start(&self, limit : Option<usize>) -> Result<(), Error> {
    let mut work_counter = 0;
    // Connect to a task ventilator
    let mut context_source = Context::new();
    let mut source = context_source.socket(zmq::DEALER).unwrap();
    let identity : String = (0..10).map(|_| rand::random::<u8>() as char).collect();
    source.set_identity(identity.as_bytes()).unwrap();

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

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

      // Prepare a File for the input
      let input_filepath = env::temp_dir().to_str().unwrap().to_string() + "/" + taskid + ".zip";
      let mut file = File::create(input_filepath.clone()).unwrap();
      loop {
        source.recv(&mut recv_msg, 0).unwrap();

        file.write(recv_msg.deref()).unwrap();
        if !source.get_rcvmore().unwrap() {
          break;
        }
      }

      file.seek(SeekFrom::Start(0)).unwrap();
      let file_opt = self.convert(Path::new(&input_filepath));
      if file_opt.is_some() {
        let mut converted_file = file_opt.unwrap();
        sink.send_str(&self.service(), SNDMORE).unwrap();
        sink.send_str(taskid, SNDMORE).unwrap();
        loop {
          // Stream converted data via zmq
          let message_size = self.message_size();
          let mut data = vec![0; message_size];
          let size = converted_file.read(&mut data).unwrap();
          data.truncate(size);
          if size < message_size {
            // If exhausted, send the last frame
            sink.send(&data,0).unwrap();
            // And terminate
            break;
          } else {
            // If more to go, send the frame and indicate there's more to come
            sink.send(&data,SNDMORE).unwrap();
          }
        }
      }
      else {
        // If there was nothing to do, retry a minute later
        thread::sleep(Duration::new(60,0));
        continue
      }

      work_counter += 1;
      match limit {
        Some(upper_bound) => {
          if work_counter >= upper_bound {
            // Give enough time to complete the Final job.
            thread::sleep(Duration::new(1,0));
            break;
          }
        },
        None => {}
      };
    }
    Ok(())
  }
}
/// An echo worker for testing
pub struct EchoWorker {
  /// the usual
  pub service : String,
  /// the usual
  pub version : f32,
  /// the usual
  pub message_size : usize,
  /// the usual
  pub source : String,
  /// the usual
  pub sink : String
}
impl Default for EchoWorker {
  fn default() -> EchoWorker {
    EchoWorker {
      service: "echo_service".to_string(),
      version: 0.1,
      message_size: 100000,
      source: "tcp://localhost:5555".to_string(),
      sink: "tcp://localhost:5556".to_string()
    }
  }
}
impl Worker for EchoWorker {
  fn service(&self) -> String {self.service.clone()}
  fn source(&self) -> String {self.source.clone()}
  fn sink(&self) -> String {self.sink.clone()}
  fn message_size(&self) -> usize {self.message_size.clone()}

  fn convert(&self, path : &Path) -> Option<File> {
    Some(File::open(path).unwrap())
  }
}
/// A TeX to HTML conversion worker
pub struct TexToHtmlWorker {
  /// the usual
  pub service : String,
  /// the usual
  pub version : f32,
  /// the usual
  pub message_size : usize,
  /// the usual
  pub source : String,
  /// the usual
  pub sink : String
}
impl Default for TexToHtmlWorker {
  fn default() -> TexToHtmlWorker {
    TexToHtmlWorker {
      service: "tex_to_html".to_string(),
      version: 0.1,
      message_size: 100000,
      source: "tcp://localhost:5555".to_string(),
      sink: "tcp://localhost:5556".to_string()
    }
  }
}
impl Worker for TexToHtmlWorker {
  fn service(&self) -> String {self.service.clone()}
  fn source(&self) -> String {self.source.clone()}
  fn sink(&self) -> String {self.sink.clone()}
  fn message_size(&self) -> usize {self.message_size.clone()}

  fn convert(&self, path : &Path) -> Option<File> {
    let name = path.file_stem().unwrap().to_str().unwrap();
    let destination_path = env::temp_dir().to_str().unwrap().to_string() + "/" +name+ ".zip";
    println!("Source {:?}", path);
    Command::new("latexmlc")
      .arg("--whatsin")
      .arg("archive")
      .arg("--whatsout")
      .arg("archive")
      .arg("--format")
      .arg("html5")
      .arg("--pmml")
      .arg("--cmml")
      .arg("--mathtex")
      .arg("--preload")
      .arg("[ids]latexml.sty")
      .arg("--nodefaultresources")
      .arg("--inputencoding")
      .arg("iso-8859-1")
      .arg("--timeout")
      .arg("300")
      .arg("--log")
      .arg("cortex.log")
      .arg("--destination")
      .arg(destination_path.clone())
      .arg(path.clone())
      .output()
      .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

    println!("Dest: {:?}", destination_path);
    let file_test = File::open(destination_path.clone());
    match file_test {
      Ok(file) => Some(file),
      Err(_) => None
    }
  }
}
<|endoftext|>


<commit_before>use std::fs::OpenOptions;
use std::io::{Error,Write};
use std::path::Path;

use byteorder::{BigEndian, WriteBytesExt};

use SMF;
use ::{Event,AbsoluteEvent,MetaEvent,MetaCommand,SMFFormat};

/// An SMFWriter is used to write an SMF to a file.  It can be either
/// constructed empty and have tracks added, or created from an
/// existing rimd::SMF.
///
/// # Writing an existing SMF to a file
/// ```
/// use rimd::{SMF,SMFWriter};
/// // Create smf
/// let writer = SMFWriter::from_smf(smf);
/// let result = writer.write_to_file(Path::new("/path/to/file.smf"));
/// // handle result
pub struct SMFWriter {
    format: u16,
    ticks: i16,
    tracks: Vec<Vec<u8>>,
}

impl SMFWriter {

    /// Create a new SMFWriter with the given number of units per
    /// beat.  The SMFWriter will initially have no tracks.
    pub fn new_with_division(ticks: i16) -> SMFWriter {
        SMFWriter {
            format: 1,
            ticks: ticks,
            tracks: Vec::new(),
        }
    }

    /// Create a new SMFWriter with the given format and number of
    /// units per beat.  The SMFWriter will initially have no tracks.
    pub fn new_with_division_and_format(format: SMFFormat, ticks: i16) -> SMFWriter {
        SMFWriter {
            format: format as u16,
            ticks: ticks,
            tracks: Vec::new(),
        }
    }

    /// Create a writer that has all the tracks from the given SMF already added
    pub fn from_smf(smf: SMF) -> SMFWriter {
        let mut writer = SMFWriter::new_with_division_and_format
            (smf.format, smf.division);

        let mut length = 0;
        let mut saw_eot = false;

        for track in smf.tracks.iter() {
            let mut vec = Vec::new();
            writer.start_track_header(&mut vec);

            for event in track.events.iter() {
                length += SMFWriter::write_vtime(event.vtime as u64,&mut vec).unwrap(); // TODO: Handle error
                writer.write_event(&mut vec, &(event.event) , &mut length, &mut saw_eot);
            }

            writer.finish_track_write(&mut vec, &mut length, saw_eot);
            writer.tracks.push(vec);
        }

        writer
    }

    pub fn vtime_to_vec(val: u64) -> Vec<u8> {
        let mut storage = Vec::new();
        let mut cur = val;
        let mut continuation = false;
        let cont_mask = 0x80 as u8;
        let val_mask = 0x7F as u64;
        loop {
            let mut to_write = (cur & val_mask) as u8;
            cur = cur >> 7;
            if continuation {
                // we're writing a continuation byte, so set the bit
                to_write |= cont_mask;
            }
            storage.push(to_write);
            continuation = true;
            if cur == 0 { break; }
        }
        storage.reverse();
        storage
    }

    // Write a variable length value.  Return number of bytes written.
    pub fn write_vtime(val: u64, writer: &mut Write) -> Result<u32,Error> {
        let storage = SMFWriter::vtime_to_vec(val);
        try!(writer.write_all(&storage[..]));
        Ok(storage.len() as u32)
    }

    fn start_track_header(&self, vec: &mut Vec<u8>) {
        vec.push(0x4D);
        vec.push(0x54);
        vec.push(0x72);
        vec.push(0x6B);
        // reserve space for track len
        vec.push(0);
        vec.push(0);
        vec.push(0);
        vec.push(0);
    }

    fn write_event(&self, vec: &mut Vec<u8>, event: &Event, length: &mut u32, saw_eot: &mut bool) {
        match event {
            &Event::Midi(ref midi) => {
                vec.extend(midi.data.iter());
                *length += midi.data.len() as u32;
            }
            &Event::Meta(ref meta) => {
                vec.push(0xff); // indicate we're writing a meta event
                vec.push(meta.command as u8);
                // +2 on next line for the 0xff and the command byte we just wrote
                *length += SMFWriter::write_vtime(meta.length,vec).unwrap() + 2;
                vec.extend(meta.data.iter());
                *length += meta.data.len() as u32;
                if meta.command == MetaCommand::EndOfTrack {
                    *saw_eot = true;
                }
            }
        }
    }

    fn finish_track_write(&self, vec: &mut Vec<u8>, length: &mut u32, saw_eot: bool) {
        if !saw_eot {
            // no end of track marker in passed data, add one
            *length += SMFWriter::write_vtime(0,vec).unwrap();
            vec.push(0xff); // indicate we're writing a meta event
            vec.push(MetaCommand::EndOfTrack as u8);
            *length += SMFWriter::write_vtime(0,vec).unwrap() + 2; // write length of meta command: 0
        }

        // write in the length in the space we reserved
        for i in 0..4 {
            let lbyte = (*length & 0xFF) as u8;
            // 7-i because smf is big endian and we want to put this in bytes 4-7
            vec[7-i] = lbyte;
            *length = (*length)>>8;
        }
    }

    /// Add any sequence of AbsoluteEvents as a track to this writer
    pub fn add_track<'a,I>(&mut self, track: I) where I: Iterator<Item=&'a AbsoluteEvent> {
        self.add_track_with_name(track,None)
    }

    /// Add any sequence of AbsoluteEvents as a track to this writer.  A meta event with the given name will
    /// be added at the start of the track
    pub fn add_track_with_name<'a,I>(&mut self, track: I, name: Option<String>) where I: Iterator<Item=&'a AbsoluteEvent> {
        let mut vec = Vec::new();

        self.start_track_header(&mut vec);

        let mut length = 0;
        let mut cur_time: u64 = 0;
        let mut saw_eot = false;

        match name {
            Some(n) => {
                let namemeta = Event::Meta(MetaEvent::sequence_or_track_name(n));
                length += SMFWriter::write_vtime(0,&mut vec).unwrap();
                self.write_event(&mut vec, &namemeta, &mut length, &mut saw_eot);
            }
            None => {}
        }

        for ev in track {
            let vtime = ev.get_time() - cur_time;
            cur_time = vtime;
            length += SMFWriter::write_vtime(vtime as u64,&mut vec).unwrap(); // TODO: Handle error
            self.write_event(&mut vec, ev.get_event(), &mut length, &mut saw_eot);
        }

        self.finish_track_write(&mut vec, &mut length, saw_eot);

        self.tracks.push(vec);
    }

    // actual writing stuff below

    fn write_header(&self, writer: &mut Write) -> Result<(),Error> {
        try!(writer.write_all(&[0x4D,0x54,0x68,0x64]));
        try!(writer.write_u32::<BigEndian>(6));
        try!(writer.write_u16::<BigEndian>(self.format));
        try!(writer.write_u16::<BigEndian>(self.tracks.len() as u16));
        try!(writer.write_i16::<BigEndian>(self.ticks));
        Ok(())
    }

    /// Write out all the tracks that have been added to this
    /// SMFWriter to the passed writer
    pub fn write_all(self, writer: &mut Write) -> Result<(),Error> {
        try!(self.write_header(writer));
        for track in self.tracks.into_iter() {
            try!(writer.write_all(&track[..]));
        }
        Ok(())
    }

    /// Write out the result of the tracks that have been added to a
    /// file.
    /// Warning: This will overwrite an existing file
    pub fn write_to_file(self, path: &Path) -> Result<(),Error> {
        let mut file = try!(OpenOptions::new().write(true).truncate(true).create(true).open(path));
        self.write_all(&mut file)
    }

}

#[test]
fn vwrite() {
    let mut vec1 = Vec::new();
    SMFWriter::write_vtime(127,&mut vec1).unwrap();
    assert!(vec1[0] == 0x7f);

    vec1.clear();
    SMFWriter::write_vtime(255,&mut vec1).unwrap();
    assert!(vec1[0] == 0x81);
    assert!(vec1[1] == 0x7f);

    vec1.clear();
    SMFWriter::write_vtime(32768,&mut vec1).unwrap();
    assert!(vec1[0] == 0x82);
    assert!(vec1[1] == 0x80);
    assert!(vec1[2] == 0x00);
}

<commit_msg>Fix documentation example code<commit_after>use std::fs::OpenOptions;
use std::io::{Error,Write};
use std::path::Path;

use byteorder::{BigEndian, WriteBytesExt};

use SMF;
use ::{Event,AbsoluteEvent,MetaEvent,MetaCommand,SMFFormat};

/// An SMFWriter is used to write an SMF to a file.  It can be either
/// constructed empty and have tracks added, or created from an
/// existing rimd::SMF.
///
/// # Writing an existing SMF to a file
/// ```
/// use rimd::{SMF,SMFWriter,SMFBuilder};
/// use std::path::Path;
/// // Create smf
/// let mut builder = SMFBuilder::new();
/// // add some events to builder
/// let smf = builder.result();
/// let writer = SMFWriter::from_smf(smf);
/// let result = writer.write_to_file(Path::new("/path/to/file.smf"));
/// // handle result
pub struct SMFWriter {
    format: u16,
    ticks: i16,
    tracks: Vec<Vec<u8>>,
}

impl SMFWriter {

    /// Create a new SMFWriter with the given number of units per
    /// beat.  The SMFWriter will initially have no tracks.
    pub fn new_with_division(ticks: i16) -> SMFWriter {
        SMFWriter {
            format: 1,
            ticks: ticks,
            tracks: Vec::new(),
        }
    }

    /// Create a new SMFWriter with the given format and number of
    /// units per beat.  The SMFWriter will initially have no tracks.
    pub fn new_with_division_and_format(format: SMFFormat, ticks: i16) -> SMFWriter {
        SMFWriter {
            format: format as u16,
            ticks: ticks,
            tracks: Vec::new(),
        }
    }

    /// Create a writer that has all the tracks from the given SMF already added
    pub fn from_smf(smf: SMF) -> SMFWriter {
        let mut writer = SMFWriter::new_with_division_and_format
            (smf.format, smf.division);

        let mut length = 0;
        let mut saw_eot = false;

        for track in smf.tracks.iter() {
            let mut vec = Vec::new();
            writer.start_track_header(&mut vec);

            for event in track.events.iter() {
                length += SMFWriter::write_vtime(event.vtime as u64,&mut vec).unwrap(); // TODO: Handle error
                writer.write_event(&mut vec, &(event.event) , &mut length, &mut saw_eot);
            }

            writer.finish_track_write(&mut vec, &mut length, saw_eot);
            writer.tracks.push(vec);
        }

        writer
    }

    pub fn vtime_to_vec(val: u64) -> Vec<u8> {
        let mut storage = Vec::new();
        let mut cur = val;
        let mut continuation = false;
        let cont_mask = 0x80 as u8;
        let val_mask = 0x7F as u64;
        loop {
            let mut to_write = (cur & val_mask) as u8;
            cur = cur >> 7;
            if continuation {
                // we're writing a continuation byte, so set the bit
                to_write |= cont_mask;
            }
            storage.push(to_write);
            continuation = true;
            if cur == 0 { break; }
        }
        storage.reverse();
        storage
    }

    // Write a variable length value.  Return number of bytes written.
    pub fn write_vtime(val: u64, writer: &mut Write) -> Result<u32,Error> {
        let storage = SMFWriter::vtime_to_vec(val);
        try!(writer.write_all(&storage[..]));
        Ok(storage.len() as u32)
    }

    fn start_track_header(&self, vec: &mut Vec<u8>) {
        vec.push(0x4D);
        vec.push(0x54);
        vec.push(0x72);
        vec.push(0x6B);
        // reserve space for track len
        vec.push(0);
        vec.push(0);
        vec.push(0);
        vec.push(0);
    }

    fn write_event(&self, vec: &mut Vec<u8>, event: &Event, length: &mut u32, saw_eot: &mut bool) {
        match event {
            &Event::Midi(ref midi) => {
                vec.extend(midi.data.iter());
                *length += midi.data.len() as u32;
            }
            &Event::Meta(ref meta) => {
                vec.push(0xff); // indicate we're writing a meta event
                vec.push(meta.command as u8);
                // +2 on next line for the 0xff and the command byte we just wrote
                *length += SMFWriter::write_vtime(meta.length,vec).unwrap() + 2;
                vec.extend(meta.data.iter());
                *length += meta.data.len() as u32;
                if meta.command == MetaCommand::EndOfTrack {
                    *saw_eot = true;
                }
            }
        }
    }

    fn finish_track_write(&self, vec: &mut Vec<u8>, length: &mut u32, saw_eot: bool) {
        if !saw_eot {
            // no end of track marker in passed data, add one
            *length += SMFWriter::write_vtime(0,vec).unwrap();
            vec.push(0xff); // indicate we're writing a meta event
            vec.push(MetaCommand::EndOfTrack as u8);
            *length += SMFWriter::write_vtime(0,vec).unwrap() + 2; // write length of meta command: 0
        }

        // write in the length in the space we reserved
        for i in 0..4 {
            let lbyte = (*length & 0xFF) as u8;
            // 7-i because smf is big endian and we want to put this in bytes 4-7
            vec[7-i] = lbyte;
            *length = (*length)>>8;
        }
    }

    /// Add any sequence of AbsoluteEvents as a track to this writer
    pub fn add_track<'a,I>(&mut self, track: I) where I: Iterator<Item=&'a AbsoluteEvent> {
        self.add_track_with_name(track,None)
    }

    /// Add any sequence of AbsoluteEvents as a track to this writer.  A meta event with the given name will
    /// be added at the start of the track
    pub fn add_track_with_name<'a,I>(&mut self, track: I, name: Option<String>) where I: Iterator<Item=&'a AbsoluteEvent> {
        let mut vec = Vec::new();

        self.start_track_header(&mut vec);

        let mut length = 0;
        let mut cur_time: u64 = 0;
        let mut saw_eot = false;

        match name {
            Some(n) => {
                let namemeta = Event::Meta(MetaEvent::sequence_or_track_name(n));
                length += SMFWriter::write_vtime(0,&mut vec).unwrap();
                self.write_event(&mut vec, &namemeta, &mut length, &mut saw_eot);
            }
            None => {}
        }

        for ev in track {
            let vtime = ev.get_time() - cur_time;
            cur_time = vtime;
            length += SMFWriter::write_vtime(vtime as u64,&mut vec).unwrap(); // TODO: Handle error
            self.write_event(&mut vec, ev.get_event(), &mut length, &mut saw_eot);
        }

        self.finish_track_write(&mut vec, &mut length, saw_eot);

        self.tracks.push(vec);
    }

    // actual writing stuff below

    fn write_header(&self, writer: &mut Write) -> Result<(),Error> {
        try!(writer.write_all(&[0x4D,0x54,0x68,0x64]));
        try!(writer.write_u32::<BigEndian>(6));
        try!(writer.write_u16::<BigEndian>(self.format));
        try!(writer.write_u16::<BigEndian>(self.tracks.len() as u16));
        try!(writer.write_i16::<BigEndian>(self.ticks));
        Ok(())
    }

    /// Write out all the tracks that have been added to this
    /// SMFWriter to the passed writer
    pub fn write_all(self, writer: &mut Write) -> Result<(),Error> {
        try!(self.write_header(writer));
        for track in self.tracks.into_iter() {
            try!(writer.write_all(&track[..]));
        }
        Ok(())
    }

    /// Write out the result of the tracks that have been added to a
    /// file.
    /// Warning: This will overwrite an existing file
    pub fn write_to_file(self, path: &Path) -> Result<(),Error> {
        let mut file = try!(OpenOptions::new().write(true).truncate(true).create(true).open(path));
        self.write_all(&mut file)
    }

}

#[test]
fn vwrite() {
    let mut vec1 = Vec::new();
    SMFWriter::write_vtime(127,&mut vec1).unwrap();
    assert!(vec1[0] == 0x7f);

    vec1.clear();
    SMFWriter::write_vtime(255,&mut vec1).unwrap();
    assert!(vec1[0] == 0x81);
    assert!(vec1[1] == 0x7f);

    vec1.clear();
    SMFWriter::write_vtime(32768,&mut vec1).unwrap();
    assert!(vec1[0] == 0x82);
    assert!(vec1[1] == 0x80);
    assert!(vec1[2] == 0x00);
}

<|endoftext|>