<commit_before>// Copyright 2014-2015 Sam Doshi (sam@metal-fish.co.uk)
// Copyright 2013-2014 Philippe Delrieu (philippe.delrieu@free.fr)
//
// Licensed under the MIT License <LICENSE or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

extern crate libc;
extern crate core;
extern crate serialize;

use std::ptr;
use libc::c_char;

mod ffi;

// Types
// -----
/// Used by PortMidi to refer to a Midi device
pub type PortMidiDeviceId = i32;
pub type PortMidiResult<T> = Result<T, PortMidiError>;

// Errors
// ------
#[derive(Copy, Show, PartialEq, Eq)]
pub enum PortMidiError {
    HostError,
    InvalidDeviceId,
    InsufficientMemory,
    BufferTooSmall,
    BufferOverflow,
    BadPtr,
    BadData,
    InternalError,
    BufferMaxSize
}

fn from_pm_error(pm_error: ffi::PmError) -> PortMidiResult<()> {
    match pm_error {
        ffi::PmError::PmNoError => Ok(()),
        ffi::PmError::PmGotData => Ok(()),
        ffi::PmError::PmHostError => Err(PortMidiError::HostError),
        ffi::PmError::PmInvalidDeviceId => Err(PortMidiError::InvalidDeviceId),
        ffi::PmError::PmInsufficientMemory => Err(PortMidiError::InsufficientMemory),
        ffi::PmError::PmBufferTooSmall => Err(PortMidiError::BufferTooSmall),
        ffi::PmError::PmBufferOverflow => Err(PortMidiError::BufferOverflow),
        ffi::PmError::PmBadPtr => Err(PortMidiError::BadPtr),
        ffi::PmError::PmBadData => Err(PortMidiError::BadData),
        ffi::PmError::PmInternalError => Err(PortMidiError::InternalError),
        ffi::PmError::PmBufferMaxSize => Err(PortMidiError::BufferMaxSize),
    }
}

// Global fns
// ----------
/// `initialize` initalizes the underlying PortMidi C library, call this
/// before using the library.
///
/// Once initialized, PortMidi will no longer pickup any new Midi devices that are
/// connected, i.e. it does not support hot plugging.
pub fn initialize() -> PortMidiResult<()> {
    from_pm_error(unsafe {
        ffi::Pm_Initialize()
    })
}

/// `terminate` terminates the underlying PortMidi C library, call this
/// after using the library.
pub fn terminate() -> PortMidiResult<()> {
    from_pm_error(unsafe {
        ffi::Pm_Terminate()
    })
}

/// Return the number of devices. This number will not change during the lifetime
/// of the program.
pub fn count_devices() -> PortMidiDeviceId {
    unsafe {
        ffi::Pm_CountDevices()
    }
}

/// Gets the `PortMidiDeviceId` for the default input, or `None` if
/// there isn't one
///
/// See the PortMidi documentation for details of how to set the default device
pub fn get_default_input_device_id() -> Option<PortMidiDeviceId> {
    let id = unsafe { ffi::Pm_GetDefaultInputDeviceID() };
    if id == ffi::PM_NO_DEVICE {
        None
    }
    else {
        Some(id)
    }
}

/// Gets the `PortMidiDeviceId` for the default output, or `None` if
/// there isn't one
///
/// See the PortMidi documentation for details of how to set the default device
pub fn get_default_output_device_id() -> Option<PortMidiDeviceId> {
    let id = unsafe { ffi::Pm_GetDefaultOutputDeviceID() };
    if id == ffi::PM_NO_DEVICE {
        None
    }
    else {
        Some(id)
    }
}

// DeviceInfo
// ----------
/// Represents what we know about a device
#[derive(Clone, Show)]
pub struct DeviceInfo {
    /// The `PortMidiDeviceId` used with `OutputPort::new` and `InputPort::new`
    pub device_id: PortMidiDeviceId,
    /// The name of the device
    pub name: String,
    /// Is the device an input
    pub input: bool,
    /// Is the device an output
    pub output: bool
}

impl DeviceInfo {
    fn wrap(device_id: PortMidiDeviceId, device_info: *const ffi::PmDeviceInfo) -> DeviceInfo {
        let name = unsafe {
            let bytes = std::ffi::c_str_to_bytes(&(*device_info).name);
            std::str::from_utf8_unchecked(bytes).to_string()
        };
        let input = unsafe { (*device_info).input };
        let output = unsafe { (*device_info).output };

        DeviceInfo {
            device_id: device_id,
            name: name,
            input: input > 0,
            output: output > 0
        }
    }
}

/// Returns a `DeviceInfo` with information about a device, or `None` if
/// it does not exist
pub fn get_device_info(device_id: PortMidiDeviceId) -> Option<DeviceInfo> {
    let info = unsafe { ffi::Pm_GetDeviceInfo(device_id) };
    if info.is_null() {
        None
    }
    else {
        Some(DeviceInfo::wrap(device_id, info))
    }
}

// Midi events
// -----------
/// Represents a single midi message, see also `MidiEvent`
///
/// TODO: should we use u8?
#[derive(Clone, Copy, PartialEq, Eq, Show)]
pub struct MidiMessage {
    pub status: i8,
    pub data1: i8,
    pub data2: i8,
}

impl MidiMessage {
    fn wrap(cmessage : ffi::PmMessage) -> MidiMessage {
        MidiMessage {
            status:  ((cmessage) & 0xFF) as i8,
            data1 : (((cmessage) >> 8) & 0xFF) as i8,
            data2 : (((cmessage) >> 16) & 0xFF) as i8,
        }
    }

    fn unwrap(&self) -> ffi::PmMessage {
        ((((self.data2 as i32) << 16) & 0xFF0000) |
          (((self.data1 as i32) << 8) & 0xFF00) |
          ((self.status as i32) & 0xFF)) as i32
    }
}

/// Represents a time stamped midi event. See also `MidiMessage`
///
/// See the PortMidi documentation for how SysEx and midi realtime messages
/// are handled
///
/// TODO: what to do about the timestamp?
#[derive(Clone, Copy, PartialEq, Eq, Show)]
pub  struct MidiEvent {
    pub message : MidiMessage,
    pub timestamp : ffi::PmTimestamp,
}

impl MidiEvent {
    fn wrap(event: ffi::PmEvent) -> MidiEvent {
        MidiEvent {
            message:  MidiMessage::wrap(event.message),
            timestamp : event.timestamp,
        }
    }

    fn unwrap(&self) -> ffi::PmEvent {
        ffi::PmEvent {
            message: self.message.unwrap(),
            timestamp: self.timestamp,
        }
    }
}

// Input
// -----
/// Representation of an input midi port
#[allow(missing_copy_implementations)]
pub struct InputPort {
    pm_stream : *const ffi::PortMidiStream,
    input_device : ffi::PmDeviceId,
    buffer_size : i32,
}

impl InputPort {
    /// Construct a new `InputPort` for `input_device`
    pub fn new(input_device : PortMidiDeviceId, buffer_size: i32) -> InputPort {
        InputPort {
            pm_stream : ptr::null(),
            input_device : input_device,
            buffer_size : buffer_size,
        }
    }

    /// Open the port returning an error if there is a problem
    pub fn open(&mut self)  -> PortMidiResult<()> {
        from_pm_error(unsafe {
            ffi::Pm_OpenInput(&self.pm_stream, self.input_device, ptr::null(),
                              self.buffer_size, ptr::null(), ptr::null())
        })
    }

    /// Reads a single `MidiEvent` if one is avaible
    ///
    /// A `Result` of `None` means no event was available.
    ///
    /// See the PortMidi documentation for information on how it deals with input
    /// overflows
    pub fn read(&mut self) -> PortMidiResult<Option<MidiEvent>> {
        use std::num::FromPrimitive;
        //get one note a the time
        let mut event = ffi::PmEvent { message : 0, timestamp : 0 };
        let no_of_notes = unsafe { ffi::Pm_Read(self.pm_stream, &mut event, 1) };
        match no_of_notes {
            y if y == 0 => Ok(None),
            y if y > 0 => Ok(Some(MidiEvent::wrap(event))),
            _ => {
                // if it's negative it's an error, convert it
                let maybe_pm_error: Option<ffi::PmError> = FromPrimitive::from_i32(no_of_notes);
                if let Some(pm_error) = maybe_pm_error {
                    from_pm_error(pm_error).map(|_| None)
                }
                else {
                    // what should we do, if we can't convert the error no?
                    // should we panic?
                    Ok(None)
                }
            }
        }
    }

    /// `poll` tests if there is input available, either returing a bool or an error
    pub fn poll(&self) -> PortMidiResult<bool> {
        let pm_error = unsafe { ffi::Pm_Poll(self.pm_stream) };
        match pm_error {
            ffi::PmError::PmNoError => Ok(false),
            ffi::PmError::PmGotData => Ok(true),
            other => from_pm_error(other).map(|_| false)
        }
    }

    /// Closes the input, flushing any pending buffers
    ///
    /// PortMidi attempts to close open streams when the application
    /// exits, but this can be difficult under Windows
    /// (according to the PortMidi documentation).
    pub fn close(&mut self) -> PortMidiResult<()> {
        from_pm_error(unsafe {
            ffi::Pm_Close(self.pm_stream)
        })
    }

    /*
    *    Test whether stream has a pending host error. Normally, the client finds
    *    out about errors through returned error codes, but some errors can occur
    *    asynchronously where the client does not
    *    explicitly call a function, and therefore cannot receive an error code.
    *    The client can test for a pending error using has_host_error(). If true,
    *    the error can be accessed and cleared by calling get_Error_text().
    *    Errors are also cleared by calling other functions that can return
    *    errors, e.g. open_input(), open_output(), read(), write(). The
    *    client does not need to call Pm_HasHostError(). Any pending error will be
    *    reported the next time the client performs an explicit function call on
    *    the stream, e.g. an input or output operation. Until the error is cleared,
    *    no new error codes will be obtained, even for a different stream.
    */
    pub fn has_host_error(&self) -> bool {
        unsafe {
            ffi::Pm_HasHostError(self.pm_stream) > 0
        }
    }
}

// Output
// ------
/// Representation of an output midi port
#[allow(missing_copy_implementations)]
pub struct OutputPort {
    pm_stream: *const ffi::PortMidiStream,
    output_device: ffi::PmDeviceId,
    buffer_size: i32,
}

impl OutputPort {
    /// Construct a new `InputPort` for `input_device`
    pub fn new(output_device: PortMidiDeviceId, buffer_size: i32) -> OutputPort {
        OutputPort {
            pm_stream: ptr::null(),
            output_device: output_device,
            buffer_size: buffer_size,
        }
    }

    /// Open the port returning an error if there is a problem
    pub fn open(&mut self)  -> PortMidiResult<()> {
        from_pm_error(unsafe {
            ffi::Pm_OpenOutput(&self.pm_stream, self.output_device, ptr::null(),
                               self.buffer_size, ptr::null(), ptr::null(), 0)
        })
    }

    /// Terminates outgoing messages immediately
    ///
    /// The caller should immediately close the output port, this may
    /// result in transmission of a partial midi message. Note, not all platforms
    /// support abort.
    pub fn abort(&mut self) -> PortMidiResult<()> {
        from_pm_error(unsafe {
            ffi::Pm_Abort(self.pm_stream)
        })
    }

    /// Closes the midi stream, flushing any pending buffers
    ///
    /// PortMidi attempts to close open streams when the application
    /// exits, but this can be difficult under Windows
    /// (according to the PortMidi documentation).
    pub fn close(&mut self) -> PortMidiResult<()> {
        from_pm_error(unsafe {
            ffi::Pm_Close(self.pm_stream)
        })
    }

    /// Write a single `MidiEvent`
    pub fn write_event(&mut self, midi_event: MidiEvent) -> PortMidiResult<()> {
        let event = midi_event.unwrap();
        from_pm_error(unsafe {
            ffi::Pm_Write(self.pm_stream, &event, 1)
        })
    }

    /// Write a single `MidiMessage` immediately
    pub fn write_message(&mut self, midi_message: MidiMessage) -> PortMidiResult<()> {
        let message = midi_message.unwrap();
        from_pm_error(unsafe {
            ffi::Pm_WriteShort(self.pm_stream, 0, message)
        })
    }

    /*
    *    Test whether stream has a pending host error. Normally, the client finds
    *    out about errors through returned error codes, but some errors can occur
    *    asynchronously where the client does not
    *    explicitly call a function, and therefore cannot receive an error code.
    *    The client can test for a pending error using has_host_error(). If true,
    *    the error can be accessed and cleared by calling get_Error_text().
    *    Errors are also cleared by calling other functions that can return
    *    errors, e.g. open_input(), open_output(), read(), write(). The
    *    client does not need to call Pm_HasHostError(). Any pending error will be
    *    reported the next time the client performs an explicit function call on
    *    the stream, e.g. an input or output operation. Until the error is cleared,
    *    no new error codes will be obtained, even for a different stream.
    */
    pub fn has_host_error(&self) -> bool  {
        unsafe {
            ffi::Pm_HasHostError(self.pm_stream) > 0
        }
    }
}

// Old code
// --------
/**  Translate portmidi error number into human readable message.
*    These strings are constants (set at compile time) so client has
*    no need to allocate storage
*/
pub fn get_error_text(error_code: ffi::PmError) -> String {
    unsafe {
        let error_text = ffi::Pm_GetErrorText(error_code);
        let bytes = std::ffi::c_str_to_bytes(&error_text);
        std::str::from_utf8_unchecked(bytes).to_string()
    }
}

/**  Translate portmidi host error into human readable message.
     These strings are computed at run time, so client has to allocate storage.
     After this routine executes, the host error is cleared.
*/
pub fn get_host_error_text(msg: *const c_char, len: i32) {
    unsafe {
        ffi::Pm_GetHostErrorText(msg, len);
    }
}

pub const HDRLENGTH: i32 = 50;
pub const PM_HOST_ERROR_MSG_LEN: i32 = 256;

<commit_msg>remove unused crates<commit_after>// Copyright 2014-2015 Sam Doshi (sam@metal-fish.co.uk)
// Copyright 2013-2014 Philippe Delrieu (philippe.delrieu@free.fr)
//
// Licensed under the MIT License <LICENSE or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

extern crate libc;

use std::ptr;
use libc::c_char;

mod ffi;

// Types
// -----
/// Used by PortMidi to refer to a Midi device
pub type PortMidiDeviceId = i32;
pub type PortMidiResult<T> = Result<T, PortMidiError>;

// Errors
// ------
#[derive(Copy, Show, PartialEq, Eq)]
pub enum PortMidiError {
    HostError,
    InvalidDeviceId,
    InsufficientMemory,
    BufferTooSmall,
    BufferOverflow,
    BadPtr,
    BadData,
    InternalError,
    BufferMaxSize
}

fn from_pm_error(pm_error: ffi::PmError) -> PortMidiResult<()> {
    match pm_error {
        ffi::PmError::PmNoError => Ok(()),
        ffi::PmError::PmGotData => Ok(()),
        ffi::PmError::PmHostError => Err(PortMidiError::HostError),
        ffi::PmError::PmInvalidDeviceId => Err(PortMidiError::InvalidDeviceId),
        ffi::PmError::PmInsufficientMemory => Err(PortMidiError::InsufficientMemory),
        ffi::PmError::PmBufferTooSmall => Err(PortMidiError::BufferTooSmall),
        ffi::PmError::PmBufferOverflow => Err(PortMidiError::BufferOverflow),
        ffi::PmError::PmBadPtr => Err(PortMidiError::BadPtr),
        ffi::PmError::PmBadData => Err(PortMidiError::BadData),
        ffi::PmError::PmInternalError => Err(PortMidiError::InternalError),
        ffi::PmError::PmBufferMaxSize => Err(PortMidiError::BufferMaxSize),
    }
}

// Global fns
// ----------
/// `initialize` initalizes the underlying PortMidi C library, call this
/// before using the library.
///
/// Once initialized, PortMidi will no longer pickup any new Midi devices that are
/// connected, i.e. it does not support hot plugging.
pub fn initialize() -> PortMidiResult<()> {
    from_pm_error(unsafe {
        ffi::Pm_Initialize()
    })
}

/// `terminate` terminates the underlying PortMidi C library, call this
/// after using the library.
pub fn terminate() -> PortMidiResult<()> {
    from_pm_error(unsafe {
        ffi::Pm_Terminate()
    })
}

/// Return the number of devices. This number will not change during the lifetime
/// of the program.
pub fn count_devices() -> PortMidiDeviceId {
    unsafe {
        ffi::Pm_CountDevices()
    }
}

/// Gets the `PortMidiDeviceId` for the default input, or `None` if
/// there isn't one
///
/// See the PortMidi documentation for details of how to set the default device
pub fn get_default_input_device_id() -> Option<PortMidiDeviceId> {
    let id = unsafe { ffi::Pm_GetDefaultInputDeviceID() };
    if id == ffi::PM_NO_DEVICE {
        None
    }
    else {
        Some(id)
    }
}

/// Gets the `PortMidiDeviceId` for the default output, or `None` if
/// there isn't one
///
/// See the PortMidi documentation for details of how to set the default device
pub fn get_default_output_device_id() -> Option<PortMidiDeviceId> {
    let id = unsafe { ffi::Pm_GetDefaultOutputDeviceID() };
    if id == ffi::PM_NO_DEVICE {
        None
    }
    else {
        Some(id)
    }
}

// DeviceInfo
// ----------
/// Represents what we know about a device
#[derive(Clone, Show)]
pub struct DeviceInfo {
    /// The `PortMidiDeviceId` used with `OutputPort::new` and `InputPort::new`
    pub device_id: PortMidiDeviceId,
    /// The name of the device
    pub name: String,
    /// Is the device an input
    pub input: bool,
    /// Is the device an output
    pub output: bool
}

impl DeviceInfo {
    fn wrap(device_id: PortMidiDeviceId, device_info: *const ffi::PmDeviceInfo) -> DeviceInfo {
        let name = unsafe {
            let bytes = std::ffi::c_str_to_bytes(&(*device_info).name);
            std::str::from_utf8_unchecked(bytes).to_string()
        };
        let input = unsafe { (*device_info).input };
        let output = unsafe { (*device_info).output };

        DeviceInfo {
            device_id: device_id,
            name: name,
            input: input > 0,
            output: output > 0
        }
    }
}

/// Returns a `DeviceInfo` with information about a device, or `None` if
/// it does not exist
pub fn get_device_info(device_id: PortMidiDeviceId) -> Option<DeviceInfo> {
    let info = unsafe { ffi::Pm_GetDeviceInfo(device_id) };
    if info.is_null() {
        None
    }
    else {
        Some(DeviceInfo::wrap(device_id, info))
    }
}

// Midi events
// -----------
/// Represents a single midi message, see also `MidiEvent`
///
/// TODO: should we use u8?
#[derive(Clone, Copy, PartialEq, Eq, Show)]
pub struct MidiMessage {
    pub status: i8,
    pub data1: i8,
    pub data2: i8,
}

impl MidiMessage {
    fn wrap(cmessage : ffi::PmMessage) -> MidiMessage {
        MidiMessage {
            status:  ((cmessage) & 0xFF) as i8,
            data1 : (((cmessage) >> 8) & 0xFF) as i8,
            data2 : (((cmessage) >> 16) & 0xFF) as i8,
        }
    }

    fn unwrap(&self) -> ffi::PmMessage {
        ((((self.data2 as i32) << 16) & 0xFF0000) |
          (((self.data1 as i32) << 8) & 0xFF00) |
          ((self.status as i32) & 0xFF)) as i32
    }
}

/// Represents a time stamped midi event. See also `MidiMessage`
///
/// See the PortMidi documentation for how SysEx and midi realtime messages
/// are handled
///
/// TODO: what to do about the timestamp?
#[derive(Clone, Copy, PartialEq, Eq, Show)]
pub  struct MidiEvent {
    pub message : MidiMessage,
    pub timestamp : ffi::PmTimestamp,
}

impl MidiEvent {
    fn wrap(event: ffi::PmEvent) -> MidiEvent {
        MidiEvent {
            message:  MidiMessage::wrap(event.message),
            timestamp : event.timestamp,
        }
    }

    fn unwrap(&self) -> ffi::PmEvent {
        ffi::PmEvent {
            message: self.message.unwrap(),
            timestamp: self.timestamp,
        }
    }
}

// Input
// -----
/// Representation of an input midi port
#[allow(missing_copy_implementations)]
pub struct InputPort {
    pm_stream : *const ffi::PortMidiStream,
    input_device : ffi::PmDeviceId,
    buffer_size : i32,
}

impl InputPort {
    /// Construct a new `InputPort` for `input_device`
    pub fn new(input_device : PortMidiDeviceId, buffer_size: i32) -> InputPort {
        InputPort {
            pm_stream : ptr::null(),
            input_device : input_device,
            buffer_size : buffer_size,
        }
    }

    /// Open the port returning an error if there is a problem
    pub fn open(&mut self)  -> PortMidiResult<()> {
        from_pm_error(unsafe {
            ffi::Pm_OpenInput(&self.pm_stream, self.input_device, ptr::null(),
                              self.buffer_size, ptr::null(), ptr::null())
        })
    }

    /// Reads a single `MidiEvent` if one is avaible
    ///
    /// A `Result` of `None` means no event was available.
    ///
    /// See the PortMidi documentation for information on how it deals with input
    /// overflows
    pub fn read(&mut self) -> PortMidiResult<Option<MidiEvent>> {
        use std::num::FromPrimitive;
        //get one note a the time
        let mut event = ffi::PmEvent { message : 0, timestamp : 0 };
        let no_of_notes = unsafe { ffi::Pm_Read(self.pm_stream, &mut event, 1) };
        match no_of_notes {
            y if y == 0 => Ok(None),
            y if y > 0 => Ok(Some(MidiEvent::wrap(event))),
            _ => {
                // if it's negative it's an error, convert it
                let maybe_pm_error: Option<ffi::PmError> = FromPrimitive::from_i32(no_of_notes);
                if let Some(pm_error) = maybe_pm_error {
                    from_pm_error(pm_error).map(|_| None)
                }
                else {
                    // what should we do, if we can't convert the error no?
                    // should we panic?
                    Ok(None)
                }
            }
        }
    }

    /// `poll` tests if there is input available, either returing a bool or an error
    pub fn poll(&self) -> PortMidiResult<bool> {
        let pm_error = unsafe { ffi::Pm_Poll(self.pm_stream) };
        match pm_error {
            ffi::PmError::PmNoError => Ok(false),
            ffi::PmError::PmGotData => Ok(true),
            other => from_pm_error(other).map(|_| false)
        }
    }

    /// Closes the input, flushing any pending buffers
    ///
    /// PortMidi attempts to close open streams when the application
    /// exits, but this can be difficult under Windows
    /// (according to the PortMidi documentation).
    pub fn close(&mut self) -> PortMidiResult<()> {
        from_pm_error(unsafe {
            ffi::Pm_Close(self.pm_stream)
        })
    }

    /*
    *    Test whether stream has a pending host error. Normally, the client finds
    *    out about errors through returned error codes, but some errors can occur
    *    asynchronously where the client does not
    *    explicitly call a function, and therefore cannot receive an error code.
    *    The client can test for a pending error using has_host_error(). If true,
    *    the error can be accessed and cleared by calling get_Error_text().
    *    Errors are also cleared by calling other functions that can return
    *    errors, e.g. open_input(), open_output(), read(), write(). The
    *    client does not need to call Pm_HasHostError(). Any pending error will be
    *    reported the next time the client performs an explicit function call on
    *    the stream, e.g. an input or output operation. Until the error is cleared,
    *    no new error codes will be obtained, even for a different stream.
    */
    pub fn has_host_error(&self) -> bool {
        unsafe {
            ffi::Pm_HasHostError(self.pm_stream) > 0
        }
    }
}

// Output
// ------
/// Representation of an output midi port
#[allow(missing_copy_implementations)]
pub struct OutputPort {
    pm_stream: *const ffi::PortMidiStream,
    output_device: ffi::PmDeviceId,
    buffer_size: i32,
}

impl OutputPort {
    /// Construct a new `InputPort` for `input_device`
    pub fn new(output_device: PortMidiDeviceId, buffer_size: i32) -> OutputPort {
        OutputPort {
            pm_stream: ptr::null(),
            output_device: output_device,
            buffer_size: buffer_size,
        }
    }

    /// Open the port returning an error if there is a problem
    pub fn open(&mut self)  -> PortMidiResult<()> {
        from_pm_error(unsafe {
            ffi::Pm_OpenOutput(&self.pm_stream, self.output_device, ptr::null(),
                               self.buffer_size, ptr::null(), ptr::null(), 0)
        })
    }

    /// Terminates outgoing messages immediately
    ///
    /// The caller should immediately close the output port, this may
    /// result in transmission of a partial midi message. Note, not all platforms
    /// support abort.
    pub fn abort(&mut self) -> PortMidiResult<()> {
        from_pm_error(unsafe {
            ffi::Pm_Abort(self.pm_stream)
        })
    }

    /// Closes the midi stream, flushing any pending buffers
    ///
    /// PortMidi attempts to close open streams when the application
    /// exits, but this can be difficult under Windows
    /// (according to the PortMidi documentation).
    pub fn close(&mut self) -> PortMidiResult<()> {
        from_pm_error(unsafe {
            ffi::Pm_Close(self.pm_stream)
        })
    }

    /// Write a single `MidiEvent`
    pub fn write_event(&mut self, midi_event: MidiEvent) -> PortMidiResult<()> {
        let event = midi_event.unwrap();
        from_pm_error(unsafe {
            ffi::Pm_Write(self.pm_stream, &event, 1)
        })
    }

    /// Write a single `MidiMessage` immediately
    pub fn write_message(&mut self, midi_message: MidiMessage) -> PortMidiResult<()> {
        let message = midi_message.unwrap();
        from_pm_error(unsafe {
            ffi::Pm_WriteShort(self.pm_stream, 0, message)
        })
    }

    /*
    *    Test whether stream has a pending host error. Normally, the client finds
    *    out about errors through returned error codes, but some errors can occur
    *    asynchronously where the client does not
    *    explicitly call a function, and therefore cannot receive an error code.
    *    The client can test for a pending error using has_host_error(). If true,
    *    the error can be accessed and cleared by calling get_Error_text().
    *    Errors are also cleared by calling other functions that can return
    *    errors, e.g. open_input(), open_output(), read(), write(). The
    *    client does not need to call Pm_HasHostError(). Any pending error will be
    *    reported the next time the client performs an explicit function call on
    *    the stream, e.g. an input or output operation. Until the error is cleared,
    *    no new error codes will be obtained, even for a different stream.
    */
    pub fn has_host_error(&self) -> bool  {
        unsafe {
            ffi::Pm_HasHostError(self.pm_stream) > 0
        }
    }
}

// Old code
// --------
/**  Translate portmidi error number into human readable message.
*    These strings are constants (set at compile time) so client has
*    no need to allocate storage
*/
pub fn get_error_text(error_code: ffi::PmError) -> String {
    unsafe {
        let error_text = ffi::Pm_GetErrorText(error_code);
        let bytes = std::ffi::c_str_to_bytes(&error_text);
        std::str::from_utf8_unchecked(bytes).to_string()
    }
}

/**  Translate portmidi host error into human readable message.
     These strings are computed at run time, so client has to allocate storage.
     After this routine executes, the host error is cleared.
*/
pub fn get_host_error_text(msg: *const c_char, len: i32) {
    unsafe {
        ffi::Pm_GetHostErrorText(msg, len);
    }
}

pub const HDRLENGTH: i32 = 50;
pub const PM_HOST_ERROR_MSG_LEN: i32 = 256;

<|endoftext|>


<commit_before><commit_msg>Refactor FFI<commit_after><|endoftext|>


<commit_before><commit_msg>Change test output to use debug!()<commit_after><|endoftext|>


<commit_before>#![crate_name="kernel"]
#![crate_type="staticlib"]
#![feature(alloc)]
#![feature(allocator)]
#![feature(arc_counts)]
#![feature(augmented_assignments)]
#![feature(asm)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(core_str_ext)]
#![feature(core_slice_ext)]
#![feature(fnbox)]
#![feature(fundamental)]
#![feature(lang_items)]
#![feature(op_assign_traits)]
#![feature(unboxed_closures)]
#![feature(unsafe_no_drop_flag)]
#![feature(unwind_attributes)]
#![feature(vec_push_all)]
#![feature(zero_one)]
#![feature(collections_range)]
#![no_std]

#![allow(deprecated)]
#![deny(warnings)]

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate collections;

extern crate system;

use acpi::Acpi;

use alloc::boxed::Box;

use arch::context::{context_switch, Context};
use arch::memory;
use arch::paging::Page;
use arch::regs::Regs;
use arch::tss::TSS;

use collections::string::ToString;

use core::{ptr, mem, usize};
use core::slice::SliceExt;

use common::time::Duration;

use drivers::pci;
use drivers::io::{Io, Pio};
use drivers::ps2::*;
use drivers::rtc::*;
use drivers::serial::*;

use env::Environment;

use graphics::display;

use schemes::context::*;
use schemes::debug::*;
use schemes::display::*;
use schemes::interrupt::*;
use schemes::memory::*;
use schemes::test::*;

use syscall::execute::execute;
use syscall::{do_sys_chdir, do_sys_exit, do_sys_open, syscall_handle};

pub use system::externs::*;

/// Common std-like functionality
#[macro_use]
pub mod common;
#[macro_use]
pub mod macros;
/// Allocation
pub mod alloc_system;
/// ACPI
pub mod acpi;
/// Architecture dependant
pub mod arch;
/// Audio
pub mod audio;
/// Disk drivers
pub mod disk;
/// Various drivers
pub mod drivers;
/// Environment
pub mod env;
/// Filesystems
pub mod fs;
/// Various graphical methods
pub mod graphics;
/// Networking
pub mod network;
/// Panic
pub mod panic;
/// Schemes
pub mod schemes;
/// Synchronization
pub mod sync;
/// System calls
pub mod syscall;
/// USB input/output
pub mod usb;

pub static mut TSS_PTR: Option<&'static mut TSS> = None;
pub static mut ENV_PTR: Option<&'static mut Environment> = None;

pub fn env() -> &'static Environment {
    unsafe {
        match ENV_PTR {
            Some(&mut ref p) => p,
            None => unreachable!(),
        }
    }
}

/// Pit duration
static PIT_DURATION: Duration = Duration {
    secs: 0,
    nanos: 4500572,
};

/// Idle loop (active while idle)
fn idle_loop() {
    loop {
        unsafe { asm!("cli" : : : : "intel", "volatile"); }

        let mut halt = true;

        for context in env().contexts.lock().iter().skip(1) {
            if ! context.blocked {
                halt = false;
                break;
            }
        }

        if halt {
            unsafe { asm!("sti ; hlt" : : : : "intel", "volatile"); }
        } else {
            unsafe { asm!("sti ; nop" : : : : "intel", "volatile"); }
            unsafe { context_switch(); }
        }
    }
}

extern {
    static mut __text_start: u8;
    static mut __text_end: u8;
    static mut __rodata_start: u8;
    static mut __rodata_end: u8;
    static mut __data_start: u8;
    static mut __data_end: u8;
    static mut __bss_start: u8;
    static mut __bss_end: u8;
}

static BSS_TEST_ZERO: usize = 0;
static BSS_TEST_NONZERO: usize = usize::MAX;

/// Initialize kernel
unsafe fn init(tss_data: usize) {

    // Test
    assume!(true);

    // Zero BSS, this initializes statics that are set to 0
    {
        let start_ptr = &mut __bss_start as *mut u8;
        let end_ptr = & __bss_end as *const u8 as usize;

        if start_ptr as usize <= end_ptr {
            let size = end_ptr - start_ptr as usize;
            memset(start_ptr, 0, size);
        }

        assert_eq!(BSS_TEST_ZERO, 0);
        assert_eq!(BSS_TEST_NONZERO, usize::MAX);
    }

    // Setup paging, this allows for memory allocation
    Page::init();
    memory::cluster_init();

    //Get the VBE information before unmapping the first megabyte
    display::vbe_init();

    // Unmap first page (TODO: Unmap more)
    {
        let start_ptr = 0;
        let end_ptr = 0x1000;

        if start_ptr as usize <= end_ptr {
            let size = end_ptr - start_ptr as usize;
            for page in 0..(size + 4095)/4096 {
                Page::new(start_ptr as usize + page * 4096).unmap();
            }
        }
    }

    //Remap text
    {
        let start_ptr = & __text_start as *const u8 as usize;
        let end_ptr = & __text_end as *const u8 as usize;
        if start_ptr as usize <= end_ptr {
            let size = end_ptr - start_ptr as usize;
            for page in 0..(size + 4095)/4096 {
                Page::new(start_ptr as usize + page * 4096).
                    map_kernel_read(start_ptr as usize + page * 4096);
            }
        }
    }

    //Remap rodata
    {
        let start_ptr = & __rodata_start as *const u8 as usize;
        let end_ptr = & __rodata_end as *const u8 as usize;
        if start_ptr <= end_ptr {
            let size = end_ptr - start_ptr;
            for page in 0..(size + 4095)/4096 {
                Page::new(start_ptr + page * 4096).
                    map_kernel_read(start_ptr + page * 4096);
            }
        }
    }

    TSS_PTR = Some(&mut *(tss_data as *mut TSS));
    ENV_PTR = Some(&mut *Box::into_raw(Environment::new()));

    match ENV_PTR {
        Some(ref mut env) => {
            env.contexts.lock().push(Context::root());

            env.console.lock().draw = true;

            debugln!("Redox {} bits", mem::size_of::<usize>() * 8);

            if let Some(acpi) = Acpi::new() {
                env.schemes.lock().push(acpi);
            }

            *(env.clock_realtime.lock()) = Rtc::new().time();

            env.schemes.lock().push(Ps2::new());
            env.schemes.lock().push(Serial::new(0x3F8, 0x4));

            pci::pci_init(env);

            env.schemes.lock().push(DebugScheme::new());
            env.schemes.lock().push(box DisplayScheme);
            env.schemes.lock().push(box ContextScheme);
            env.schemes.lock().push(box InterruptScheme);
            env.schemes.lock().push(box MemoryScheme);
            env.schemes.lock().push(box TestScheme);

            env.contexts.lock().enabled = true;

            Context::spawn("kinit".to_string(),
            box move || {
                {
                    let wd_c = "file:/\0";
                    do_sys_chdir(wd_c.as_ptr()).unwrap();

                    let stdio_c = "debug:\0";
                    do_sys_open(stdio_c.as_ptr(), 0).unwrap();
                    do_sys_open(stdio_c.as_ptr(), 0).unwrap();
                    do_sys_open(stdio_c.as_ptr(), 0).unwrap();
                }

                if let Err(err) = execute(vec!["init".to_string()]) {
                    debugln!("INIT: Failed to execute: {}", err);
                }
            });
        },
        None => unreachable!(),
    }
}

#[cold]
#[inline(never)]
#[no_mangle]
/// Take regs for kernel calls and exceptions
pub extern "cdecl" fn kernel(interrupt: usize, mut regs: &mut Regs) {
    macro_rules! exception_inner {
        ($name:expr) => ({
            {
                let contexts = ::env().contexts.lock();
                if let Ok(context) = contexts.current() {
                    debugln!("PID {}: {}", context.pid, context.name);
                }
            }

            debugln!("  INT {:X}: {}", interrupt, $name);
            debugln!("    CS:  {:08X}    IP:  {:08X}    FLG: {:08X}", regs.cs, regs.ip, regs.flags);
            debugln!("    SS:  {:08X}    SP:  {:08X}    BP:  {:08X}", regs.ss, regs.sp, regs.bp);
            debugln!("    AX:  {:08X}    BX:  {:08X}    CX:  {:08X}    DX:  {:08X}", regs.ax, regs.bx, regs.cx, regs.dx);
            debugln!("    DI:  {:08X}    SI:  {:08X}", regs.di, regs.di);

            let cr0: usize;
            let cr2: usize;
            let cr3: usize;
            let cr4: usize;
            unsafe {
                asm!("mov $0, cr0" : "=r"(cr0) : : : "intel", "volatile");
                asm!("mov $0, cr2" : "=r"(cr2) : : : "intel", "volatile");
                asm!("mov $0, cr3" : "=r"(cr3) : : : "intel", "volatile");
                asm!("mov $0, cr4" : "=r"(cr4) : : : "intel", "volatile");
            }
            debugln!("    CR0: {:08X}    CR2: {:08X}    CR3: {:08X}    CR4: {:08X}", cr0, cr2, cr3, cr4);

            let mut fsw: usize = 0;
            let mut fcw: usize = 0;
            unsafe {
                asm!("fnstsw $0" : "=*m"(&mut fsw) : : : "intel", "volatile");
                asm!("fnstcw $0" : "=*m"(&mut fcw) : : : "intel", "volatile");
            }
            debugln!("    FSW: {:08X}    FCW: {:08X}", fsw, fcw);

            let sp = regs.sp as *const u32;
            for y in -15..16 {
                debug!("    {:>3}:", y * 8 * 4);
                for x in 0..8 {
                    debug!(" {:08X}", unsafe { ptr::read(sp.offset(-(x + y * 8))) });
                }
                debug!("\n");
            }
        })
    };

    macro_rules! exception {
        ($name:expr) => ({
            exception_inner!($name);

            loop {
                do_sys_exit(usize::MAX);
            }
        })
    };

    macro_rules! exception_error {
        ($name:expr) => ({
            let error = regs.ip;
            regs.ip = regs.cs;
            regs.cs = regs.flags;
            regs.flags = regs.sp;
            regs.sp = regs.ss;
            regs.ss = 0;
            //regs.ss = regs.error;

            exception_inner!($name);
            debugln!("    ERR: {:08X}", error);

            loop {
                do_sys_exit(usize::MAX);
            }
        })
    };

    //Do not catch init interrupt
    if interrupt < 0xFF {
        env().interrupts.lock()[interrupt as usize] += 1;
    }

    match interrupt {
        0x20 => {
            {
                let mut clock_monotonic = env().clock_monotonic.lock();
                *clock_monotonic = *clock_monotonic + PIT_DURATION;
            }
            {
                let mut clock_realtime = env().clock_realtime.lock();
                *clock_realtime = *clock_realtime + PIT_DURATION;
            }

            if let Ok(mut current) = env().contexts.lock().current_mut() {
                current.time += 1;
            }

            unsafe { context_switch(); }
        }
        i @ 0x21 ... 0x2F => {
            env().on_irq(i as u8 - 0x20);
        },
        0x80 => syscall_handle(regs),
        0xFF => {
            unsafe {
                init(regs.ax);
                idle_loop();
            }
        },
        0x0 => exception!("Divide by zero exception"),
        0x1 => exception!("Debug exception"),
        0x2 => exception!("Non-maskable interrupt"),
        0x3 => exception!("Breakpoint exception"),
        0x4 => exception!("Overflow exception"),
        0x5 => exception!("Bound range exceeded exception"),
        0x6 => exception!("Invalid opcode exception"),
        0x7 => exception!("Device not available exception"),
        0x8 => exception_error!("Double fault"),
        0x9 => exception!("Coprocessor Segment Overrun"), // legacy
        0xA => exception_error!("Invalid TSS exception"),
        0xB => exception_error!("Segment not present exception"),
        0xC => exception_error!("Stack-segment fault"),
        0xD => exception_error!("General protection fault"),
        0xE => exception_error!("Page fault"),
        0x10 => exception!("x87 floating-point exception"),
        0x11 => exception_error!("Alignment check exception"),
        0x12 => exception!("Machine check exception"),
        0x13 => exception!("SIMD floating-point exception"),
        0x14 => exception!("Virtualization exception"),
        0x1E => exception_error!("Security exception"),
        _ => exception!("Unknown Interrupt"),
    }

    if interrupt >= 0x20 && interrupt < 0x30 {
        if interrupt >= 0x28 {
            Pio::<u8>::new(0xA0).write(0x20);
        }

        Pio::<u8>::new(0x20).write(0x20);
    }
}
<commit_msg>Remove the augmented_assignments feature flag<commit_after>#![crate_name="kernel"]
#![crate_type="staticlib"]
#![feature(alloc)]
#![feature(allocator)]
#![feature(arc_counts)]
#![feature(asm)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(core_str_ext)]
#![feature(core_slice_ext)]
#![feature(fnbox)]
#![feature(fundamental)]
#![feature(lang_items)]
#![feature(op_assign_traits)]
#![feature(unboxed_closures)]
#![feature(unsafe_no_drop_flag)]
#![feature(unwind_attributes)]
#![feature(vec_push_all)]
#![feature(zero_one)]
#![feature(collections_range)]
#![no_std]

#![allow(deprecated)]
#![deny(warnings)]

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate collections;

extern crate system;

use acpi::Acpi;

use alloc::boxed::Box;

use arch::context::{context_switch, Context};
use arch::memory;
use arch::paging::Page;
use arch::regs::Regs;
use arch::tss::TSS;

use collections::string::ToString;

use core::{ptr, mem, usize};
use core::slice::SliceExt;

use common::time::Duration;

use drivers::pci;
use drivers::io::{Io, Pio};
use drivers::ps2::*;
use drivers::rtc::*;
use drivers::serial::*;

use env::Environment;

use graphics::display;

use schemes::context::*;
use schemes::debug::*;
use schemes::display::*;
use schemes::interrupt::*;
use schemes::memory::*;
use schemes::test::*;

use syscall::execute::execute;
use syscall::{do_sys_chdir, do_sys_exit, do_sys_open, syscall_handle};

pub use system::externs::*;

/// Common std-like functionality
#[macro_use]
pub mod common;
#[macro_use]
pub mod macros;
/// Allocation
pub mod alloc_system;
/// ACPI
pub mod acpi;
/// Architecture dependant
pub mod arch;
/// Audio
pub mod audio;
/// Disk drivers
pub mod disk;
/// Various drivers
pub mod drivers;
/// Environment
pub mod env;
/// Filesystems
pub mod fs;
/// Various graphical methods
pub mod graphics;
/// Networking
pub mod network;
/// Panic
pub mod panic;
/// Schemes
pub mod schemes;
/// Synchronization
pub mod sync;
/// System calls
pub mod syscall;
/// USB input/output
pub mod usb;

pub static mut TSS_PTR: Option<&'static mut TSS> = None;
pub static mut ENV_PTR: Option<&'static mut Environment> = None;

pub fn env() -> &'static Environment {
    unsafe {
        match ENV_PTR {
            Some(&mut ref p) => p,
            None => unreachable!(),
        }
    }
}

/// Pit duration
static PIT_DURATION: Duration = Duration {
    secs: 0,
    nanos: 4500572,
};

/// Idle loop (active while idle)
fn idle_loop() {
    loop {
        unsafe { asm!("cli" : : : : "intel", "volatile"); }

        let mut halt = true;

        for context in env().contexts.lock().iter().skip(1) {
            if ! context.blocked {
                halt = false;
                break;
            }
        }

        if halt {
            unsafe { asm!("sti ; hlt" : : : : "intel", "volatile"); }
        } else {
            unsafe { asm!("sti ; nop" : : : : "intel", "volatile"); }
            unsafe { context_switch(); }
        }
    }
}

extern {
    static mut __text_start: u8;
    static mut __text_end: u8;
    static mut __rodata_start: u8;
    static mut __rodata_end: u8;
    static mut __data_start: u8;
    static mut __data_end: u8;
    static mut __bss_start: u8;
    static mut __bss_end: u8;
}

static BSS_TEST_ZERO: usize = 0;
static BSS_TEST_NONZERO: usize = usize::MAX;

/// Initialize kernel
unsafe fn init(tss_data: usize) {

    // Test
    assume!(true);

    // Zero BSS, this initializes statics that are set to 0
    {
        let start_ptr = &mut __bss_start as *mut u8;
        let end_ptr = & __bss_end as *const u8 as usize;

        if start_ptr as usize <= end_ptr {
            let size = end_ptr - start_ptr as usize;
            memset(start_ptr, 0, size);
        }

        assert_eq!(BSS_TEST_ZERO, 0);
        assert_eq!(BSS_TEST_NONZERO, usize::MAX);
    }

    // Setup paging, this allows for memory allocation
    Page::init();
    memory::cluster_init();

    //Get the VBE information before unmapping the first megabyte
    display::vbe_init();

    // Unmap first page (TODO: Unmap more)
    {
        let start_ptr = 0;
        let end_ptr = 0x1000;

        if start_ptr as usize <= end_ptr {
            let size = end_ptr - start_ptr as usize;
            for page in 0..(size + 4095)/4096 {
                Page::new(start_ptr as usize + page * 4096).unmap();
            }
        }
    }

    //Remap text
    {
        let start_ptr = & __text_start as *const u8 as usize;
        let end_ptr = & __text_end as *const u8 as usize;
        if start_ptr as usize <= end_ptr {
            let size = end_ptr - start_ptr as usize;
            for page in 0..(size + 4095)/4096 {
                Page::new(start_ptr as usize + page * 4096).
                    map_kernel_read(start_ptr as usize + page * 4096);
            }
        }
    }

    //Remap rodata
    {
        let start_ptr = & __rodata_start as *const u8 as usize;
        let end_ptr = & __rodata_end as *const u8 as usize;
        if start_ptr <= end_ptr {
            let size = end_ptr - start_ptr;
            for page in 0..(size + 4095)/4096 {
                Page::new(start_ptr + page * 4096).
                    map_kernel_read(start_ptr + page * 4096);
            }
        }
    }

    TSS_PTR = Some(&mut *(tss_data as *mut TSS));
    ENV_PTR = Some(&mut *Box::into_raw(Environment::new()));

    match ENV_PTR {
        Some(ref mut env) => {
            env.contexts.lock().push(Context::root());

            env.console.lock().draw = true;

            debugln!("Redox {} bits", mem::size_of::<usize>() * 8);

            if let Some(acpi) = Acpi::new() {
                env.schemes.lock().push(acpi);
            }

            *(env.clock_realtime.lock()) = Rtc::new().time();

            env.schemes.lock().push(Ps2::new());
            env.schemes.lock().push(Serial::new(0x3F8, 0x4));

            pci::pci_init(env);

            env.schemes.lock().push(DebugScheme::new());
            env.schemes.lock().push(box DisplayScheme);
            env.schemes.lock().push(box ContextScheme);
            env.schemes.lock().push(box InterruptScheme);
            env.schemes.lock().push(box MemoryScheme);
            env.schemes.lock().push(box TestScheme);

            env.contexts.lock().enabled = true;

            Context::spawn("kinit".to_string(),
            box move || {
                {
                    let wd_c = "file:/\0";
                    do_sys_chdir(wd_c.as_ptr()).unwrap();

                    let stdio_c = "debug:\0";
                    do_sys_open(stdio_c.as_ptr(), 0).unwrap();
                    do_sys_open(stdio_c.as_ptr(), 0).unwrap();
                    do_sys_open(stdio_c.as_ptr(), 0).unwrap();
                }

                if let Err(err) = execute(vec!["init".to_string()]) {
                    debugln!("INIT: Failed to execute: {}", err);
                }
            });
        },
        None => unreachable!(),
    }
}

#[cold]
#[inline(never)]
#[no_mangle]
/// Take regs for kernel calls and exceptions
pub extern "cdecl" fn kernel(interrupt: usize, mut regs: &mut Regs) {
    macro_rules! exception_inner {
        ($name:expr) => ({
            {
                let contexts = ::env().contexts.lock();
                if let Ok(context) = contexts.current() {
                    debugln!("PID {}: {}", context.pid, context.name);
                }
            }

            debugln!("  INT {:X}: {}", interrupt, $name);
            debugln!("    CS:  {:08X}    IP:  {:08X}    FLG: {:08X}", regs.cs, regs.ip, regs.flags);
            debugln!("    SS:  {:08X}    SP:  {:08X}    BP:  {:08X}", regs.ss, regs.sp, regs.bp);
            debugln!("    AX:  {:08X}    BX:  {:08X}    CX:  {:08X}    DX:  {:08X}", regs.ax, regs.bx, regs.cx, regs.dx);
            debugln!("    DI:  {:08X}    SI:  {:08X}", regs.di, regs.di);

            let cr0: usize;
            let cr2: usize;
            let cr3: usize;
            let cr4: usize;
            unsafe {
                asm!("mov $0, cr0" : "=r"(cr0) : : : "intel", "volatile");
                asm!("mov $0, cr2" : "=r"(cr2) : : : "intel", "volatile");
                asm!("mov $0, cr3" : "=r"(cr3) : : : "intel", "volatile");
                asm!("mov $0, cr4" : "=r"(cr4) : : : "intel", "volatile");
            }
            debugln!("    CR0: {:08X}    CR2: {:08X}    CR3: {:08X}    CR4: {:08X}", cr0, cr2, cr3, cr4);

            let mut fsw: usize = 0;
            let mut fcw: usize = 0;
            unsafe {
                asm!("fnstsw $0" : "=*m"(&mut fsw) : : : "intel", "volatile");
                asm!("fnstcw $0" : "=*m"(&mut fcw) : : : "intel", "volatile");
            }
            debugln!("    FSW: {:08X}    FCW: {:08X}", fsw, fcw);

            let sp = regs.sp as *const u32;
            for y in -15..16 {
                debug!("    {:>3}:", y * 8 * 4);
                for x in 0..8 {
                    debug!(" {:08X}", unsafe { ptr::read(sp.offset(-(x + y * 8))) });
                }
                debug!("\n");
            }
        })
    };

    macro_rules! exception {
        ($name:expr) => ({
            exception_inner!($name);

            loop {
                do_sys_exit(usize::MAX);
            }
        })
    };

    macro_rules! exception_error {
        ($name:expr) => ({
            let error = regs.ip;
            regs.ip = regs.cs;
            regs.cs = regs.flags;
            regs.flags = regs.sp;
            regs.sp = regs.ss;
            regs.ss = 0;
            //regs.ss = regs.error;

            exception_inner!($name);
            debugln!("    ERR: {:08X}", error);

            loop {
                do_sys_exit(usize::MAX);
            }
        })
    };

    //Do not catch init interrupt
    if interrupt < 0xFF {
        env().interrupts.lock()[interrupt as usize] += 1;
    }

    match interrupt {
        0x20 => {
            {
                let mut clock_monotonic = env().clock_monotonic.lock();
                *clock_monotonic = *clock_monotonic + PIT_DURATION;
            }
            {
                let mut clock_realtime = env().clock_realtime.lock();
                *clock_realtime = *clock_realtime + PIT_DURATION;
            }

            if let Ok(mut current) = env().contexts.lock().current_mut() {
                current.time += 1;
            }

            unsafe { context_switch(); }
        }
        i @ 0x21 ... 0x2F => {
            env().on_irq(i as u8 - 0x20);
        },
        0x80 => syscall_handle(regs),
        0xFF => {
            unsafe {
                init(regs.ax);
                idle_loop();
            }
        },
        0x0 => exception!("Divide by zero exception"),
        0x1 => exception!("Debug exception"),
        0x2 => exception!("Non-maskable interrupt"),
        0x3 => exception!("Breakpoint exception"),
        0x4 => exception!("Overflow exception"),
        0x5 => exception!("Bound range exceeded exception"),
        0x6 => exception!("Invalid opcode exception"),
        0x7 => exception!("Device not available exception"),
        0x8 => exception_error!("Double fault"),
        0x9 => exception!("Coprocessor Segment Overrun"), // legacy
        0xA => exception_error!("Invalid TSS exception"),
        0xB => exception_error!("Segment not present exception"),
        0xC => exception_error!("Stack-segment fault"),
        0xD => exception_error!("General protection fault"),
        0xE => exception_error!("Page fault"),
        0x10 => exception!("x87 floating-point exception"),
        0x11 => exception_error!("Alignment check exception"),
        0x12 => exception!("Machine check exception"),
        0x13 => exception!("SIMD floating-point exception"),
        0x14 => exception!("Virtualization exception"),
        0x1E => exception_error!("Security exception"),
        _ => exception!("Unknown Interrupt"),
    }

    if interrupt >= 0x20 && interrupt < 0x30 {
        if interrupt >= 0x28 {
            Pio::<u8>::new(0xA0).write(0x20);
        }

        Pio::<u8>::new(0x20).write(0x20);
    }
}
<|endoftext|>


<commit_before><commit_msg>Better names<commit_after><|endoftext|>


<commit_before><commit_msg>Initial commit<commit_after>extern crate time;

use std::env;

#[derive(Clone, Debug)]
enum Token {
    DOTTEDDATE, HYPHENDATE,
    HOURMIN,
    INT1DIGIT, INT2DIGIT, INT4DIGIT, INT58DIGIT,
    INT, FLOAT,
    NOW,
    AM, PM,
    NOON, MIDNIGHT, TEATIME,
    SUN, MON, TUE, WED, THU, FRI, SAT,
    TODAY, TOMORROW,
    NEXT,
    MINUTE, HOUR, DAY, WEEK, MONTH, YEAR,
    JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC,
    UTC,
    PLUS, MINUS
}

fn usage(name: String) {
    println!("Usage: {} [timespec]", name)
}

fn main() {
    let args: Vec<_> = env::args().collect();
    if args.len() > 1 {
        let result = parsetime(args[1].clone());
        println!("{}", result.asctime());
    } else {
        usage(args[0].clone());
    }
}

fn parse_timespec(tokens: Vec<Token>, current_time: time::Tm) -> time::Tm {
    let mut new_time = time::empty_tm();
    for token in tokens {
        match token {
            Token::NOW => {
                new_time = current_time;
            }
            Token::MIDNIGHT => {
                new_time.tm_hour = 0;
                new_time.tm_min = 0;
            }
            Token::NOON => {
                new_time.tm_hour = 12;
                new_time.tm_min = 0;
            }
            Token::TEATIME => {
                new_time.tm_hour = 16;
                new_time.tm_min = 0;
            }
            Token::SUN => {
                new_time.tm_wday = 0;
            }
            Token::MON => {
                new_time.tm_wday = 1;
            }
            Token::TUE => {
                new_time.tm_wday = 2;
            }
            Token::WED => {
                new_time.tm_wday = 3;
            }
            Token::THU => {
                new_time.tm_wday = 4;
            }
            Token::FRI => {
                new_time.tm_wday = 5;
            }
            Token::SAT => {
                new_time.tm_wday = 6;
            }
            Token::JAN => {
                new_time.tm_mon = 0;
            }
            Token::FEB => {
                new_time.tm_mon = 1;
            }
            Token::MAR => {
                new_time.tm_mon = 2;
            }
            Token::APR => {
                new_time.tm_mon = 3;
            }
            Token::MAY => {
                new_time.tm_mon = 4;
            }
            Token::JUN => {
                new_time.tm_mon = 5;
            }
            Token::JUL => {
                new_time.tm_mon = 6;
            }
            Token::AUG => {
                new_time.tm_mon = 7;
            }
            Token::SEP => {
                new_time.tm_mon = 8;
            }
            Token::OCT => {
                new_time.tm_mon = 9;
            }
            Token::NOV => {
                new_time.tm_mon = 10;
            }
            Token::DEC => {
                new_time.tm_mon = 11;
            }
            Token::PLUS => {
                new_time = current_time;
            }
            _ => println!("Unknown token: {:?}", token)
        }
    }
    return new_time;
}

fn increment_time(tokens: Vec<Token>) -> time::Tm {
    inc_dec_time(decrement_tm, tokens)
}

fn decrement_time(tokens: Vec<Token>) -> time::Tm {
    inc_dec_time(increment_tm, tokens)
}

fn inc_dec_time(inc_dec: fn(time::Tm, time::Duration) -> time::Tm, tokens:Vec<Token>) -> time::Tm {
    return time::now();
}

fn increment_tm(a: time::Tm, b: time::Duration) -> time::Tm {
    return a + b;
}

fn decrement_tm(a: time::Tm, b: time::Duration) -> time::Tm {
    return a - b;
}

fn tokenize (timespec: String) -> Vec<Token> {
    let mut tokens: Vec<Token> = vec![];
    let exprs = timespec.split(' ');
    for expr in exprs {
        match expr {
            "now" => {
                tokens.push(Token::NOW.clone());
            }
            "midnight" => {
                tokens.push(Token::MIDNIGHT.clone());
            }
            "noon" => {
                tokens.push(Token::NOON.clone());
            }
            "teatime" => {
                tokens.push(Token::TEATIME.clone());
            }
            "sun" | "sunday" => {
                tokens.push(Token::SUN.clone());
            }
            "mon" | "monday" => {
                tokens.push(Token::MON.clone());
            }
            "tue" | "tuesday" => {
                tokens.push(Token::TUE.clone());
            }
            "wed" | "wednesday" => {
                tokens.push(Token::WED.clone());
            }
            "thu" | "thursday" => {
                tokens.push(Token::TUE.clone());
            }
            "fri" | "friday" => {
                tokens.push(Token::FRI.clone());
            }
            "sat" | "saturday" => {
                tokens.push(Token::SAT.clone());
            }
            "jan" | "january" => {
                tokens.push(Token::JAN.clone());
            }
            "feb" | "february" => {
                tokens.push(Token::FEB.clone());
            }
            "mar" | "march" => {
                tokens.push(Token::MAR.clone());
            }
            "apr" | "april" => {
                tokens.push(Token::APR.clone());
            }
            "may" => {
                tokens.push(Token::MAY.clone());
            }
            "jun" | "june" => {
                tokens.push(Token::JUN.clone());
            }
            "jul" | "july" => {
                tokens.push(Token::JUL.clone());
            }
            "aug" | "august" => {
                tokens.push(Token::AUG.clone());
            }
            "sep" | "september" => {
                tokens.push(Token::SEP.clone());
            }
            "oct" | "october" => {
                tokens.push(Token::OCT.clone());
            }
            "nov" | "november" => {
                tokens.push(Token::NOV.clone());
            }
            "dec" | "december" => {
                tokens.push(Token::DEC.clone());
            }
            "+" => {
                tokens.push(Token::PLUS.clone());
            }
            _ => {
            }
        }
    }
    return tokens;
}

fn parsetime (timespec: String) -> time::Tm {
    let now = time::now();

    let tokens = tokenize(timespec);
    let time = parse_timespec(tokens, now);

    return time;
}
<|endoftext|>


<commit_before><commit_msg>formatting<commit_after><|endoftext|>


<commit_before><commit_msg>Added default values for host, port, and password<commit_after><|endoftext|>


<commit_before>#![forbid(unsafe_code)]

extern crate bincode;
extern crate clap;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate actix_web;
extern crate actix_net;
extern crate binascii;
extern crate toml;
#[macro_use]
extern crate log;
extern crate bzip2;
extern crate fern;
extern crate num_cpus;
extern crate serde_json;
extern crate futures;
#[macro_use]
extern crate lazy_static;

mod config;
mod server;
mod stackvec;
mod tracker;
mod webserver;

use config::Configuration;
use std::process::exit;

lazy_static!{
    static ref term_mutex: std::sync::Arc<std::sync::atomic::AtomicBool> = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
}

fn setup_logging(cfg: &Configuration) {
    let log_level = match cfg.get_log_level() {
        None => log::LevelFilter::Info,
        Some(level) => match level.as_str() {
            "off" => log::LevelFilter::Off,
            "trace" => log::LevelFilter::Trace,
            "debug" => log::LevelFilter::Debug,
            "info" => log::LevelFilter::Info,
            "warn" => log::LevelFilter::Warn,
            "error" => log::LevelFilter::Error,
            _ => {
                eprintln!("udpt: unknown log level encountered '{}'", level.as_str());
                exit(-1);
            }
        },
    };

    if let Err(err) = fern::Dispatch::new()
        .format(|out, message, record| {
            out.finish(format_args!(
                "{}[{}][{}]\t{}",
                std::time::SystemTime::now()
                    .duration_since(std::time::UNIX_EPOCH)
                    .unwrap()
                    .as_secs(),
                record.target(),
                record.level(),
                message
            ))
        })
        .level(log_level)
        .chain(std::io::stdout())
        .apply()
    {
        eprintln!("udpt: failed to initialize logging. {}", err);
        std::process::exit(-1);
    }
    info!("logging initialized.");
}

fn signal_termination() {
    term_mutex.store(true, std::sync::atomic::Ordering::Relaxed);
}

fn main() {
    let parser = clap::App::new("udpt")
        .about("High performance, lightweight, udp based torrent tracker.")
        .author("Naim A. <naim94a@gmail.com>")
        .arg(
            clap::Arg::with_name("config")
                .takes_value(true)
                .short("-c")
                .help("Configuration file to load.")
                .required(true),
        );

    let matches = parser.get_matches();
    let cfg_path = matches.value_of("config").unwrap();

    let cfg = match Configuration::load_file(cfg_path) {
        Ok(v) => std::sync::Arc::new(v),
        Err(e) => {
            eprintln!("udpt: failed to open configuration: {}", e);
            return;
        }
    };

    setup_logging(&cfg);

    let tracker_obj = match cfg.get_db_path() {
        Some(path) => {
            let file_path = std::path::Path::new(path);
            if !file_path.exists() {
                warn!("database file \"{}\" doesn't exist.", path);
                tracker::TorrentTracker::new(cfg.get_mode().clone())
            }
            else {
                let mut input_file = match std::fs::File::open(file_path) {
                    Ok(v) => v,
                    Err(err) => {
                        error!("failed to open \"{}\". error: {}", path.as_str(), err);
                        panic!("error opening file. check logs.");
                    }
                };
                match tracker::TorrentTracker::load_database(cfg.get_mode().clone(), &mut input_file) {
                    Ok(v) => v,
                    Err(err) => {
                        error!("failed to load database. error: {}", err);
                        panic!("failed to load database. check logs.");
                    }
                }
            }
        }
        None => tracker::TorrentTracker::new(cfg.get_mode().clone()),
    };

    let mut threads = Vec::new();

    let tracker = std::sync::Arc::new(tracker_obj);

    let http_server = if cfg.get_http_config().is_some() {
        let http_tracker_ref = tracker.clone();
        let cfg_ref = cfg.clone();

        Some(webserver::WebServer::new(http_tracker_ref, cfg_ref))
    } else {
        None
    };

    let udp_server = std::sync::Arc::new(server::UDPTracker::new(cfg.clone(), tracker.clone()).unwrap());

    trace!("Waiting for UDP packets");
    let logical_cpus = num_cpus::get();
    for i in 0..logical_cpus {
        debug!("starting thread {}/{}", i + 1, logical_cpus);
        let server_handle = udp_server.clone();
        let thread_term_ref = term_mutex.clone();
        threads.push(std::thread::spawn(move || loop {
            match server_handle.accept_packet() {
                Err(e) => {
                    if thread_term_ref.load(std::sync::atomic::Ordering::Relaxed) == true {
                        debug!("Thread terminating...");
                        break;
                    }
                    match e.kind() {
                        std::io::ErrorKind::TimedOut => {},
                        std::io::ErrorKind::WouldBlock => {},
                        _ => {
                            error!("Failed to process packet. {}", e);
                        }
                    }
                }
                Ok(_) => {}
            }
        }));
    }

    match cfg.get_db_path() {
        Some(db_path) => {
            let db_p = db_path.clone();
            let tracker_clone = tracker.clone();
            let cleanup_interval = match *cfg.get_cleanup_interval() {
                Some(v) => v,
                None => 10 * 60,
            };

            let thread_term_mutex = term_mutex.clone();
            threads.push(std::thread::spawn(move || {
                let timeout = std::time::Duration::new(cleanup_interval, 0);

                let timeout_start = std::time::Instant::now();
                let mut timeout_remaining = timeout;
                loop {
                    std::thread::park_timeout(std::time::Duration::new(cleanup_interval, 0));

                    if thread_term_mutex.load(std::sync::atomic::Ordering::Relaxed) {
                        debug!("Maintenance thread terminating.");
                        break;
                    }

                    let elapsed = std::time::Instant::now() - timeout_start;
                    if elapsed < timeout_remaining {
                        timeout_remaining = timeout - elapsed;
                        continue;
                    }
                    else {
                        timeout_remaining = timeout;
                    }

                    debug!("periodically saving database.");
                    tracker_clone.periodic_task(db_p.as_str());
                    debug!("database saved.");
                }
            }));
        },
        None => {}
    }

    loop {
        if term_mutex.load(std::sync::atomic::Ordering::Relaxed) {
            // termination signaled. start cleanup.
            break;
        }
        std::thread::sleep(std::time::Duration::from_secs(1));
    }

    match http_server {
        Some(v) => v.shutdown(),
        None => {},
    };

    while !threads.is_empty() {
        if let Some(thread) = threads.pop() {
            thread.thread().unpark();
            let _ = thread.join();
        }
    }
}
<commit_msg>write db on termination<commit_after>#![forbid(unsafe_code)]

extern crate bincode;
extern crate clap;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate actix_web;
extern crate actix_net;
extern crate binascii;
extern crate toml;
#[macro_use]
extern crate log;
extern crate bzip2;
extern crate fern;
extern crate num_cpus;
extern crate serde_json;
extern crate futures;
#[macro_use]
extern crate lazy_static;

mod config;
mod server;
mod stackvec;
mod tracker;
mod webserver;

use config::Configuration;
use std::process::exit;

lazy_static!{
    static ref term_mutex: std::sync::Arc<std::sync::atomic::AtomicBool> = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
}

fn setup_logging(cfg: &Configuration) {
    let log_level = match cfg.get_log_level() {
        None => log::LevelFilter::Info,
        Some(level) => match level.as_str() {
            "off" => log::LevelFilter::Off,
            "trace" => log::LevelFilter::Trace,
            "debug" => log::LevelFilter::Debug,
            "info" => log::LevelFilter::Info,
            "warn" => log::LevelFilter::Warn,
            "error" => log::LevelFilter::Error,
            _ => {
                eprintln!("udpt: unknown log level encountered '{}'", level.as_str());
                exit(-1);
            }
        },
    };

    if let Err(err) = fern::Dispatch::new()
        .format(|out, message, record| {
            out.finish(format_args!(
                "{}[{}][{}]\t{}",
                std::time::SystemTime::now()
                    .duration_since(std::time::UNIX_EPOCH)
                    .unwrap()
                    .as_secs(),
                record.target(),
                record.level(),
                message
            ))
        })
        .level(log_level)
        .chain(std::io::stdout())
        .apply()
    {
        eprintln!("udpt: failed to initialize logging. {}", err);
        std::process::exit(-1);
    }
    info!("logging initialized.");
}

fn signal_termination() {
    term_mutex.store(true, std::sync::atomic::Ordering::Relaxed);
}

fn main() {
    let parser = clap::App::new(env!("CARGO_PKG_NAME"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .version(env!("CARGO_PKG_VERSION"))
        .arg(
            clap::Arg::with_name("config")
                .takes_value(true)
                .short("-c")
                .help("Configuration file to load.")
                .required(true),
        );

    let matches = parser.get_matches();
    let cfg_path = matches.value_of("config").unwrap();

    let cfg = match Configuration::load_file(cfg_path) {
        Ok(v) => std::sync::Arc::new(v),
        Err(e) => {
            eprintln!("udpt: failed to open configuration: {}", e);
            return;
        }
    };

    setup_logging(&cfg);

    let tracker_obj = match cfg.get_db_path() {
        Some(path) => {
            let file_path = std::path::Path::new(path);
            if !file_path.exists() {
                warn!("database file \"{}\" doesn't exist.", path);
                tracker::TorrentTracker::new(cfg.get_mode().clone())
            }
            else {
                let mut input_file = match std::fs::File::open(file_path) {
                    Ok(v) => v,
                    Err(err) => {
                        error!("failed to open \"{}\". error: {}", path.as_str(), err);
                        panic!("error opening file. check logs.");
                    }
                };
                match tracker::TorrentTracker::load_database(cfg.get_mode().clone(), &mut input_file) {
                    Ok(v) => v,
                    Err(err) => {
                        error!("failed to load database. error: {}", err);
                        panic!("failed to load database. check logs.");
                    }
                }
            }
        }
        None => tracker::TorrentTracker::new(cfg.get_mode().clone()),
    };

    let mut threads = Vec::new();

    let tracker = std::sync::Arc::new(tracker_obj);

    let http_server = if cfg.get_http_config().is_some() {
        let http_tracker_ref = tracker.clone();
        let cfg_ref = cfg.clone();

        Some(webserver::WebServer::new(http_tracker_ref, cfg_ref))
    } else {
        None
    };

    let udp_server = std::sync::Arc::new(server::UDPTracker::new(cfg.clone(), tracker.clone()).unwrap());

    trace!("Waiting for UDP packets");
    let logical_cpus = num_cpus::get();
    for i in 0..logical_cpus {
        debug!("starting thread {}/{}", i + 1, logical_cpus);
        let server_handle = udp_server.clone();
        let thread_term_ref = term_mutex.clone();
        threads.push(std::thread::spawn(move || loop {
            match server_handle.accept_packet() {
                Err(e) => {
                    if thread_term_ref.load(std::sync::atomic::Ordering::Relaxed) == true {
                        debug!("Thread terminating...");
                        break;
                    }
                    match e.kind() {
                        std::io::ErrorKind::TimedOut => {},
                        std::io::ErrorKind::WouldBlock => {},
                        _ => {
                            error!("Failed to process packet. {}", e);
                        }
                    }
                }
                Ok(_) => {}
            }
        }));
    }

    match cfg.get_db_path() {
        Some(db_path) => {
            let db_p = db_path.clone();
            let tracker_clone = tracker.clone();
            let cleanup_interval = match *cfg.get_cleanup_interval() {
                Some(v) => v,
                None => 10 * 60,
            };

            let thread_term_mutex = term_mutex.clone();
            threads.push(std::thread::spawn(move || {
                let timeout = std::time::Duration::new(cleanup_interval, 0);

                let timeout_start = std::time::Instant::now();
                let mut timeout_remaining = timeout;
                loop {
                    std::thread::park_timeout(std::time::Duration::new(cleanup_interval, 0));

                    if thread_term_mutex.load(std::sync::atomic::Ordering::Relaxed) {
                        debug!("Maintenance thread terminating.");
                        break;
                    }

                    let elapsed = std::time::Instant::now() - timeout_start;
                    if elapsed < timeout_remaining {
                        timeout_remaining = timeout - elapsed;
                        continue;
                    }
                    else {
                        timeout_remaining = timeout;
                    }

                    debug!("periodically saving database.");
                    tracker_clone.periodic_task(db_p.as_str());
                    debug!("database saved.");
                }
            }));
        },
        None => {}
    }

    loop {
        if term_mutex.load(std::sync::atomic::Ordering::Relaxed) {
            // termination signaled. start cleanup.
            break;
        }
        std::thread::sleep(std::time::Duration::from_secs(1));
    }

    match http_server {
        Some(v) => v.shutdown(),
        None => {},
    };

    while !threads.is_empty() {
        if let Some(thread) = threads.pop() {
            thread.thread().unpark();
            let _ = thread.join();
        }
    }

    if let Some(db_path) = cfg.get_db_path() {
        info!("running final cleanup & saving database...");
        tracker.periodic_task(db_path.as_str());
    }
    info!("goodbye.");
}
<|endoftext|>


<commit_before><commit_msg>learning how to use proc properly<commit_after>/*
    closu2.rs
    demonstrating closures
    vanilla
*/

fn main(){
    fn call_twice(f: ||) {
        f();
        f();
    }

    let closure = || { "I'm a closure, and it doesn't matter what type I am"; };

    fn function() {
        "I'm a normal function";
    }

    call_twice(|| println!("{:?}",function()));

    call_twice(|| println!("{:?}","pewpew"));

    call_twice(proc(){println!("pew")});

    call_twice(closure);
    call_twice(function);
}
<|endoftext|>


<commit_before><commit_msg>complete custom dictionary test<commit_after>#![cfg(test)]
#![allow(non_upper_case_globals)]
#![allow(dead_code)]
extern crate core;
extern crate brotli_decompressor;
use brotli_decompressor::{CustomRead, CustomWrite};
use super::brotli::enc::BrotliEncoderParams;
use super::brotli::concat::{BroCatli, BroCatliResult};
use std::io::{Read, Write};
use super::integration_tests::UnlimitedBuffer;
static RANDOM_THEN_UNICODE : &'static [u8] = include_bytes!("../../testdata/random_then_unicode");
static ALICE: &'static[u8]  = include_bytes!("../../testdata/alice29.txt");
use super::Rebox;

#[test]
fn test_custom_dict() {
    let mut raw = UnlimitedBuffer::new(ALICE);
    let mut params = BrotliEncoderParams::default();
    params.quality = 10;
    let mut br = UnlimitedBuffer::new(&[]);
    let mut rt = UnlimitedBuffer::new(&[]);
    let dict = &ALICE[12515..23411];
    super::compress(&mut raw, &mut br, 4096, &params, dict).unwrap();
    raw.reset_read();
    let mut vec = Vec::<u8>::new();
    vec.extend(dict);
    super::decompress(&mut br, &mut rt, 4096, Rebox::from(vec)).unwrap();
    assert_eq!(rt.data(), raw.data());
    assert_eq!(br.data().len(), 43629);
}

#[test]
fn test_custom_wrong_dict_fails() {
    let mut raw = UnlimitedBuffer::new(ALICE);
    let mut params = BrotliEncoderParams::default();
    params.quality = 10;
    let mut br = UnlimitedBuffer::new(&[]);
    let mut rt = UnlimitedBuffer::new(&[]);
    let dict = &ALICE[12515..19515];
    super::compress(&mut raw, &mut br, 4096, &params, dict).unwrap();
    raw.reset_read();
    let mut vec = Vec::<u8>::new();
    vec.extend(&dict[1..]); // slightly offset dictionary to be wrong, and ensure the dict was being used above
    match super::decompress(&mut br, &mut rt, 4096, Rebox::from(vec)) {
        Ok(_) => panic!("Decompression should have failed"),
        Err(_) => {},
    }
    if rt.data() == raw.data() {
        panic!("they should be unequal");
    }
}

#[test]
fn test_custom_wrong_dict_fails_but_doesnt_disrupt_compression_strategy() {
    let mut raw = UnlimitedBuffer::new(ALICE);
    let mut params = BrotliEncoderParams::default();
    params.quality = 6;
    let mut br = UnlimitedBuffer::new(&[]);
    let mut rt = UnlimitedBuffer::new(&[]);
    let dict = &ALICE[12515..19515];
    super::compress(&mut raw, &mut br, 4096, &params, dict).unwrap();
    raw.reset_read();
    let mut vec = Vec::<u8>::new();
    vec.extend(&dict[1..]); // slightly offset dictionary to be wrong, and ensure the dict was being used above
    super::decompress(&mut br, &mut rt, 4096, Rebox::from(vec)).unwrap();
    if rt.data() == raw.data() {
        panic!("they should be unequal");
    }
}

#[test]
fn test_custom_dict_for_multithreading() {
    let mut raws = [UnlimitedBuffer::new(&ALICE[..ALICE.len()/3]),
                    UnlimitedBuffer::new(&ALICE[ALICE.len()/3..2*ALICE.len()/3]),
                    UnlimitedBuffer::new(&ALICE[2 * ALICE.len()/3..]),
    ];
    let mut params = BrotliEncoderParams::default();
    params.quality = 10;
    params.appendable = true;
    let mut brs = [
        UnlimitedBuffer::new(&[]),
        UnlimitedBuffer::new(&[]),
        UnlimitedBuffer::new(&[]),
    ];
    let mut rts = [
        UnlimitedBuffer::new(&[]),
        UnlimitedBuffer::new(&[]),
        UnlimitedBuffer::new(&[]),
    ];
    let dicts = [
        &[],
        &ALICE[..ALICE.len()/3],
        &ALICE[..2*ALICE.len()/3],
    ];
    for (raw, (br, (rt, dict))) in raws.iter_mut().zip(brs.iter_mut().zip(rts.iter_mut().zip(dicts.iter()))) {
        super::compress(raw, br, 4096, &params, dict).unwrap();
        raw.reset_read();
        let mut vec = Vec::<u8>::new();
        vec.extend(*dict);
        super::decompress(br, rt, 4096, Rebox::from(vec)).unwrap();
        assert_eq!(rt.data(), raw.data());
        params.catable = true;
    }
    let mut bro_cat_li = BroCatli::new();
    let mut output = UnlimitedBuffer::new(&[]);
    let mut ibuffer = vec![0u8; 1];
    let mut obuffer = vec![0u8; 1];
    let mut ooffset = 0usize;
    for brotli in brs.iter_mut() {
        brotli.reset_read();
        bro_cat_li.new_brotli_file();
        let mut input = brotli;
        loop {
            let mut ioffset = 0usize;
            match input.read(&mut ibuffer[..]) {
                Err(e) => panic!(e),
                Ok(cur_read) => {
                    if cur_read == 0 {
                        break;
                    }
                    loop {
                        match bro_cat_li.stream(&ibuffer[..cur_read], &mut ioffset,
                                                &mut obuffer[..], &mut ooffset) {
                            BroCatliResult::NeedsMoreOutput => {
                                match output.write(&obuffer[..ooffset]) {
                                    Err(why) => panic!("couldn't write: {:}", why),
                                    Ok(count) => {assert_eq!(count, ooffset);},
                                }
                                ooffset = 0;
                            },
                            BroCatliResult::NeedsMoreInput => {
                                break;
                            },
                            BroCatliResult::Success => {
                                panic!("Unexpected state: Success when streaming before finish");
                            },
                            failure => {
                                panic!(failure);
                            },
                        }
                    }
                }
            }
        }
    }
    loop {
        match bro_cat_li.finish(&mut obuffer[..], &mut ooffset) {
            BroCatliResult::NeedsMoreOutput => {
                match output.write(&obuffer[..ooffset]) {
                    Err(why) => panic!("couldn't write\n{:}", why),
                    Ok(count) => {assert_eq!(count, ooffset);},
                }
                ooffset = 0;
            },
            BroCatliResult::NeedsMoreInput => {
                panic!("Unexpected EOF");
            },
            BroCatliResult::Success => {
                if ooffset != 0 {
                    match output.write(&obuffer[..ooffset]) {
                        Err(why) => panic!("couldn't write\n{:}", why),
                        Ok(count) => {assert_eq!(count, ooffset);},
                    }
                }
                break;
            }
            failure => {
                panic!(failure)
            }
        }
    }
    let mut rt = UnlimitedBuffer::new(&[]);
    output.reset_read();
    super::decompress(&mut output, &mut rt, 4096, Rebox::default()).unwrap();
    assert_eq!(rt.data(), ALICE);
    assert_eq!(output.data().len(), 48564); // as opposed to 46487 with standard settings
}

<|endoftext|>


<commit_before>/*
    This file is part of trig-rs, a library for doing typesafe trigonometry
    with a variety of angle formats (radians, degrees, grad, turns, and so on).
*/

#![crate_name   = "trig"]
#![comment = "Provides trigonometric primitives."]
#![crate_type = "dylib"]
#![crate_type = "rlib"]

#![unstable]
#![feature(macro_rules)]
#![feature(struct_variant)]

use std::fmt;

/*
    Top-level functions.
*/

/// Calculate the sine.
#[stable] #[inline] pub fn sin<S: BaseFloat, T: Trigonometry<S>>(t: T) -> S { t.sin() }

/// Calculate the cosine.
#[stable] #[inline] pub fn cos<S: BaseFloat, T: Trigonometry<S>>(t: T) -> S { t.cos() }

/// Calculate the tangent.
#[stable] #[inline] pub fn tan<S: BaseFloat, T: Trigonometry<S>>(t: T) -> S { t.tan() }

/// Calculate the arcsine (in radians).
#[inline] pub fn asin<S: BaseFloat>(s: S) -> Angle<S> { Angle::radians(s.asin()) }

/// Calculate the arccosine (in radians).
#[inline] pub fn acos<S: BaseFloat>(s: S) -> Angle<S> { Angle::radians(s.acos()) }

/// Calculate the arctangent (in radians).
#[inline] pub fn atan<S: BaseFloat>(s: S) -> Angle<S> { Angle::radians(s.atan()) }

/*
    The Trigonometry trait.
*/

/// Represents an object for which trigonometric methods are sensible and return
/// values of type `S`.
#[stable]
pub trait Trigonometry<S> {
    /// Compute the sine of the object.
    fn sin(&self) -> S;
    /// Compute the cosine of the object.
    fn cos(&self) -> S;
    /// Compute the tangent of the object.
    fn tan(&self) -> S;
    // /// Compute the cosecant of the object.
    // fn csc(&self) -> S;
    // /// Compute the secant of the object.
    // fn sec(&self) -> S;
    // /// Compute the cotangent of the object.
    // fn cot(&self) -> S;
}

/*
    The Angle enum and its implementations.
*/

/// Base floating point types
pub trait BaseFloat: Primitive + FromPrimitive + fmt::Show + fmt::Float + Float + FloatMath {}

impl BaseFloat for f32 {}
impl BaseFloat for f64 {}

/// Encompasses representations of angles in the Euclidean plane.
#[deriving(Clone, PartialEq, PartialOrd, Hash)]
pub enum Angle<S> {
    /// An angle in radians.
    #[stable] Rad(S),
    /// An angle in degrees.
    #[stable] Deg(S),
    /// An angle in [gradians](http://en.wikipedia.org/wiki/Grad_(angle)).
    #[stable] Grad(S),
    /// An angle in [turns](http://en.wikipedia.org/wiki/Turn_(geometry)).
    #[stable] Turn(S),
    /// An angle as it would appear on the face of a clock.
    #[experimental] Clock {
        /// The hours portion.
        pub hour: S,
        /// The minutes portion.
        pub minute: S,
        /// The seconds portion.
        pub second: S
    },
}

impl<S: BaseFloat + Mul<S, S> + Div<S, S> + Rem<S, S>> Angle<S> {
    /// Returns an angle in radians.
    pub fn radians(s: S) -> Angle<S> { Rad(s % Float::two_pi()) }

    /// Returns an angle in degrees.
    pub fn degrees(s: S) -> Angle<S> { Deg(s % FromPrimitive::from_f64(360.0).unwrap()) }

    /// Returns an angle in gradians.
    pub fn gradians(s: S) -> Angle<S> { Grad(s % FromPrimitive::from_f64(400.0).unwrap()) }

    /// Returns an angle in turns.
    pub fn turns(s: S) -> Angle<S> { Turn(s.fract()) }

    /// Returns an angle as it would appear on a clock.
    pub fn clock_face(hour: S, minute: S, second: S) -> Angle<S> {
        Clock { hour: hour, minute: minute, second: second }
    }

    /// Converts an angle to radians.
    pub fn to_radians(&self) -> Angle<S> {
        match self {
            &Rad(val) => Angle::radians(val),
            &Deg(val) => Angle::radians(val.to_radians()),
            &Grad(val) => Angle::radians(val * Float::pi() / FromPrimitive::from_f64(200.0).unwrap()),
            &Turn(val) => Angle::radians(val * Float::two_pi()),
            _ => unimplemented!()
        }
    }

    /// Converts an angle to degrees.
    pub fn to_degrees(&self) -> Angle<S> {
        match self {
            &Rad(val) => Angle::degrees(val.to_degrees()),
            &Deg(val) => Angle::degrees(val),
            &Grad(val) => Angle::degrees(val * FromPrimitive::from_f64(360.0 / 400.0).unwrap()),
            &Turn(val) => Angle::degrees(val * FromPrimitive::from_f64(360.0).unwrap()),
            _ => unimplemented!()
        }
    }

    /// Converts an angle to gradians.
    pub fn to_gradians(&self) -> Angle<S> {
        match self {
            &Rad(val) => Angle::gradians(val / Float::pi() * FromPrimitive::from_f64(200.0).unwrap()),
            &Deg(val) => Angle::gradians(val * FromPrimitive::from_f64(400.0 / 360.0).unwrap()),
            &Grad(val) => Angle::gradians(val),
            &Turn(val) => Angle::gradians(val * FromPrimitive::from_f64(400.0).unwrap()),
            _ => unimplemented!()
        }
    }

    /// Converts an angle to turns.
    pub fn to_turns(&self) -> Angle<S> {
        match self {
            &Rad(val) => Angle::turns(val / Float::two_pi()),
            &Deg(val) => Angle::turns(val / FromPrimitive::from_f64(360.0).unwrap()),
            &Grad(val) => Angle::turns(val / FromPrimitive::from_f64(400.0).unwrap()),
            &Turn(val) => Angle::turns(val),
            _ => unimplemented!()
        }
    }

    /// One half of the domain. In radians, this is `π`.
    pub fn half() -> Angle<S> { Rad(Float::pi()) }

    /// One quarter of the domain. In radians, this is `π/2`.
    pub fn quarter() -> Angle<S> { Rad(Float::frac_pi_2()) }

    /// One sixth of the domain. In radians, this is `π/3`.
    pub fn sixth() -> Angle<S> { Rad(Float::frac_pi_3()) }

    /// One eighth of the domain. In radians, this is `π/4`.
    pub fn eighth() -> Angle<S> { Rad(Float::frac_pi_4()) }
}

macro_rules! angle_trigonometry (
    ($($method:ident),+ ) => (
        impl<S: BaseFloat> Trigonometry<S> for Angle<S> {
            $(fn $method(&self) -> S {
                match self {
                    &Rad(val) => val.$method(),
                    &Deg(val) => val.to_radians().$method(),
                    _ => fail!("Not yet implemented.")
                }
            }
            )+
        }
    )
)

angle_trigonometry!(sin, cos, tan)

macro_rules! angle_ops (
    ($Trait:ident, $method:ident) => (
        impl<S: BaseFloat> $Trait<Angle<S>, Angle<S>> for Angle<S> {
            #[inline]
            fn $method(&self, other: &Angle<S>) -> Angle<S> {
                match (self, other) {
                    (&Deg(s1), &Deg(s2)) => Angle::degrees(s1.$method(&s2)),
                    (&Deg(s1), &Rad(s2)) => Angle::degrees(s1.$method(&s2.to_degrees())),
                    (&Rad(s1), &Rad(s2)) => Angle::radians(s1.$method(&s2)),
                    (&Rad(s1), &Deg(s2)) => Angle::radians(s1.$method(&s2.to_radians())),
                    _ => fail!("Not yet implemented.")
                }
            }
        }
    )
)

angle_ops!(Add, add)
angle_ops!(Sub, sub)
angle_ops!(Mul, mul)
angle_ops!(Div, div)

impl<S: BaseFloat + fmt::Show> fmt::Show for Angle<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Deg(val) => write!(f, "{}°", val),
            &Rad(val) => write!(f, "{} rad", val),
            &Grad(val) => write!(f, "{} gon", val),
            &Turn(val) => write!(f, "{} turns", val),
            _ => fail!("Not yet implemented.")
        }
    }
}

/*
    Test suite.
*/

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

    #[test]
    fn test_conversion() {
        let half: Angle<f64> = Angle::half();
        assert_eq!(half.to_degrees().to_gradians().to_turns().to_radians(), half);
        assert_eq!(half.to_turns().to_gradians().to_degrees().to_radians(), half);
        assert_eq!(half.to_degrees().to_turns().to_gradians().to_radians(), half);
        assert_eq!(half.to_gradians().to_radians(), half);
    }

    #[test]
    fn test_operators() {
        assert_eq!(Angle::degrees(100.0f64) + Angle::degrees(100.0f64), Angle::degrees(200.0f64));
        assert_eq!(Angle::degrees(100.0f64) - Angle::degrees(100.0f64), Angle::degrees(0.0f64));
        assert_eq!(Angle::degrees(100.0f64) + Angle::radians(0.0f64), Angle::degrees(100.0f64));
        assert_eq!(Angle::radians(1.0f64) - Angle::degrees(0.0f64), Angle::radians(1.0f64));
        assert_eq!(Angle::degrees(2.0f64) * Angle::degrees(100.0f64), Angle::degrees(200.0f64));
    }
}
<commit_msg>Implements Add and Sub by hand as concatenate operations.<commit_after>/*
    This file is part of trig-rs, a library for doing typesafe trigonometry
    with a variety of angle formats (radians, degrees, grad, turns, and so on).
*/

#![crate_name   = "trig"]
#![comment = "Provides trigonometric primitives."]
#![crate_type = "dylib"]
#![crate_type = "rlib"]

#![unstable]
#![feature(macro_rules)]
#![feature(struct_variant)]

use std::fmt;

/*
    Top-level functions.
*/

/// Calculate the sine.
#[stable] #[inline] pub fn sin<S: BaseFloat, T: Trigonometry<S>>(t: T) -> S { t.sin() }

/// Calculate the cosine.
#[stable] #[inline] pub fn cos<S: BaseFloat, T: Trigonometry<S>>(t: T) -> S { t.cos() }

/// Calculate the tangent.
#[stable] #[inline] pub fn tan<S: BaseFloat, T: Trigonometry<S>>(t: T) -> S { t.tan() }

/// Calculate the arcsine (in radians).
#[inline] pub fn asin<S: BaseFloat>(s: S) -> Angle<S> { Angle::radians(s.asin()) }

/// Calculate the arccosine (in radians).
#[inline] pub fn acos<S: BaseFloat>(s: S) -> Angle<S> { Angle::radians(s.acos()) }

/// Calculate the arctangent (in radians).
#[inline] pub fn atan<S: BaseFloat>(s: S) -> Angle<S> { Angle::radians(s.atan()) }

/*
    The Trigonometry trait.
*/

/// Represents an object for which trigonometric methods are sensible and return
/// values of type `S`.
#[stable]
pub trait Trigonometry<S> {
    /// Compute the sine of the object.
    fn sin(&self) -> S;
    /// Compute the cosine of the object.
    fn cos(&self) -> S;
    /// Compute the tangent of the object.
    fn tan(&self) -> S;
    // /// Compute the cosecant of the object.
    // fn csc(&self) -> S;
    // /// Compute the secant of the object.
    // fn sec(&self) -> S;
    // /// Compute the cotangent of the object.
    // fn cot(&self) -> S;
}

/*
    The Angle enum and its implementations.
*/

/// Base floating point types
pub trait BaseFloat: Primitive + FromPrimitive + fmt::Show + fmt::Float + Float + FloatMath {}

impl BaseFloat for f32 {}
impl BaseFloat for f64 {}

/// Encompasses representations of angles in the Euclidean plane.
#[deriving(Clone, PartialEq, PartialOrd, Hash)]
pub enum Angle<S> {
    /// An angle in radians.
    #[stable] Rad(S),
    /// An angle in degrees.
    #[stable] Deg(S),
    /// An angle in [gradians](http://en.wikipedia.org/wiki/Grad_(angle)).
    #[stable] Grad(S),
    /// An angle in [turns](http://en.wikipedia.org/wiki/Turn_(geometry)).
    #[stable] Turn(S),
    /// An angle as it would appear on the face of a clock.
    #[experimental] Clock {
        /// The hours portion.
        pub hour: S,
        /// The minutes portion.
        pub minute: S,
        /// The seconds portion.
        pub second: S
    },
}

impl<S: BaseFloat + Mul<S, S> + Div<S, S> + Rem<S, S>> Angle<S> {
    /// Returns an angle in radians.
    pub fn radians(s: S) -> Angle<S> { Rad(s % Float::two_pi()) }

    /// Returns an angle in degrees.
    pub fn degrees(s: S) -> Angle<S> { Deg(s % FromPrimitive::from_f64(360.0).unwrap()) }

    /// Returns an angle in gradians.
    pub fn gradians(s: S) -> Angle<S> { Grad(s % FromPrimitive::from_f64(400.0).unwrap()) }

    /// Returns an angle in turns.
    pub fn turns(s: S) -> Angle<S> { Turn(s.fract()) }

    /// Returns an angle as it would appear on a clock.
    pub fn clock_face(hour: S, minute: S, second: S) -> Angle<S> {
        Clock { hour: hour, minute: minute, second: second }
    }

    /// Converts an angle to radians.
    pub fn to_radians(&self) -> Angle<S> {
        match self {
            &Rad(val) => Angle::radians(val),
            &Deg(val) => Angle::radians(val.to_radians()),
            &Grad(val) => Angle::radians(val * Float::pi() / FromPrimitive::from_f64(200.0).unwrap()),
            &Turn(val) => Angle::radians(val * Float::two_pi()),
            _ => unimplemented!()
        }
    }

    /// Converts an angle to degrees.
    pub fn to_degrees(&self) -> Angle<S> {
        match self {
            &Rad(val) => Angle::degrees(val.to_degrees()),
            &Deg(val) => Angle::degrees(val),
            &Grad(val) => Angle::degrees(val * FromPrimitive::from_f64(360.0 / 400.0).unwrap()),
            &Turn(val) => Angle::degrees(val * FromPrimitive::from_f64(360.0).unwrap()),
            _ => unimplemented!()
        }
    }

    /// Converts an angle to gradians.
    pub fn to_gradians(&self) -> Angle<S> {
        match self {
            &Rad(val) => Angle::gradians(val / Float::pi() * FromPrimitive::from_f64(200.0).unwrap()),
            &Deg(val) => Angle::gradians(val * FromPrimitive::from_f64(400.0 / 360.0).unwrap()),
            &Grad(val) => Angle::gradians(val),
            &Turn(val) => Angle::gradians(val * FromPrimitive::from_f64(400.0).unwrap()),
            _ => unimplemented!()
        }
    }

    /// Converts an angle to turns.
    pub fn to_turns(&self) -> Angle<S> {
        match self {
            &Rad(val) => Angle::turns(val / Float::two_pi()),
            &Deg(val) => Angle::turns(val / FromPrimitive::from_f64(360.0).unwrap()),
            &Grad(val) => Angle::turns(val / FromPrimitive::from_f64(400.0).unwrap()),
            &Turn(val) => Angle::turns(val),
            _ => unimplemented!()
        }
    }

    /// One half of the domain. In radians, this is `π`.
    pub fn half() -> Angle<S> { Rad(Float::pi()) }

    /// One quarter of the domain. In radians, this is `π/2`.
    pub fn quarter() -> Angle<S> { Rad(Float::frac_pi_2()) }

    /// One sixth of the domain. In radians, this is `π/3`.
    pub fn sixth() -> Angle<S> { Rad(Float::frac_pi_3()) }

    /// One eighth of the domain. In radians, this is `π/4`.
    pub fn eighth() -> Angle<S> { Rad(Float::frac_pi_4()) }

    /// Gets the raw value that is stored in the angle.
    ///
    /// ## Failure
    ///
    /// Clock-valued angles are not encoded as a single value, and so this
    /// method will always fail for them.
    pub fn unwrap(&self) -> S {
        match self {
            &Rad(s)|&Deg(s)|&Grad(s)|&Turn(s) => s,
            _ => fail!("Clock values cannot be unwrapped.")
        }
    }
}

impl<S: BaseFloat> Add<Angle<S>, Angle<S>> for Angle<S> {
    #[inline]
    fn add(&self, other: &Angle<S>) -> Angle<S> {
        match (self, other) {
            (&Rad(val), othr) => Angle::radians(val + othr.to_radians().unwrap()),
            (&Deg(val), othr) => Angle::degrees(val + othr.to_degrees().unwrap()),
            (&Grad(val), othr) => Angle::gradians(val + othr.to_gradians().unwrap()),
            (&Turn(val), othr) => Angle::turns(val + othr.to_turns().unwrap()),
            _ => unimplemented!()
        }
    }
}

impl<S: BaseFloat> Sub<Angle<S>, Angle<S>> for Angle<S> {
    #[inline]
    fn sub(&self, other: &Angle<S>) -> Angle<S> {
        match (self, other) {
            (&Rad(val), othr) => Angle::radians(val - othr.to_radians().unwrap()),
            (&Deg(val), othr) => Angle::degrees(val - othr.to_degrees().unwrap()),
            (&Grad(val), othr) => Angle::gradians(val - othr.to_gradians().unwrap()),
            (&Turn(val), othr) => Angle::turns(val - othr.to_turns().unwrap()),
            _ => unimplemented!()
        }
    }
}

impl<S: BaseFloat + fmt::Show> fmt::Show for Angle<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Deg(val) => write!(f, "{}°", val),
            &Rad(val) => write!(f, "{} rad", val),
            &Grad(val) => write!(f, "{} gon", val),
            &Turn(val) => write!(f, "{} turns", val),
            _ => fail!("Not yet implemented.")
        }
    }
}

macro_rules! angle_trigonometry (
    ($($method:ident),+ ) => (
        impl<S: BaseFloat> Trigonometry<S> for Angle<S> {
            $(fn $method(&self) -> S {
                match self {
                    &Rad(val) => val.$method(),
                    &Deg(val) => val.to_radians().$method(),
                    _ => fail!("Not yet implemented.")
                }
            }
            )+
        }
    )
)

angle_trigonometry!(sin, cos, tan)

/*
    Test suite.
*/

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

    #[test]
    fn test_conversion() {
        let half: Angle<f64> = Angle::half();
        assert_eq!(half.to_degrees().to_gradians().to_turns().to_radians(), half);
        assert_eq!(half.to_turns().to_gradians().to_degrees().to_radians(), half);
        assert_eq!(half.to_degrees().to_turns().to_gradians().to_radians(), half);
        assert_eq!(half.to_gradians().to_radians(), half);
    }

    #[test]
    fn test_operators() {
        assert_eq!(Angle::degrees(100.0f64) + Angle::degrees(100.0f64), Angle::degrees(200.0f64));
        assert_eq!(Angle::degrees(100.0f64) - Angle::degrees(100.0f64), Angle::degrees(0.0f64));
        assert_eq!(Angle::degrees(100.0f64) + Angle::radians(0.0f64), Angle::degrees(100.0f64));
        assert_eq!(Angle::radians(1.0f64) - Angle::degrees(0.0f64), Angle::radians(1.0f64));
    }
}
<|endoftext|>


<commit_before>use std::collections::hash_map::RandomState;
use std::hash::{Hash, Hasher, BuildHasher};

use layout::Rect;

pub fn hash<T: Hash>(t: &T, area: &Rect) -> u64 {
    let state = RandomState::new();
    let mut hasher = state.build_hasher();
    t.hash(&mut hasher);
    area.hash(&mut hasher);
    hasher.finish()
}
<commit_msg>Fix layout cache on nightly<commit_after><|endoftext|>


<commit_before><commit_msg>drop method<commit_after><|endoftext|>


<commit_before><commit_msg>Deal with one of the validation layer warnings regarding multisample resolve<commit_after><|endoftext|>


<commit_before><commit_msg>Use error output from runtime to print error<commit_after><|endoftext|>