<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

//! Types used in the PortAudio API

#![allow(dead_code)]

use std::{string, ptr};
use std::mem::{transmute};

use ffi;

/// The type used to refer to audio devices. Values of this type usually range
/// from 0 to (pa::get_device_count()-1)
pub type PaDeviceIndex = i32;
/// A special PaDeviceIndex value indicating that no device is available,
/// or should be used.
pub static PaNoDevice: PaDeviceIndex = -1;
/// A special PaDeviceIndex value indicating that the device(s) to be used are
/// specified in the host api specific stream info structure.
pub static PaUseHostApiSpecificDeviceSpecification: PaDeviceIndex = -2;

/// The type used to enumerate to host APIs at runtime.
/// Values of this type range from 0 to (pa::get_host_api_count()-1).
pub type PaHostApiIndex = i32;

/// The type used to represent monotonic time in seconds.
pub type PaTime = f64;

/// A type used to specify one or more sample formats.
#[repr(u64)]
#[deriving(Clone, PartialEq, PartialOrd, Show)]
pub enum PaSampleFormat {
    /// 32 bits float sample format
    PaFloat32 =         ffi::PaFloat32,
    /// 32 bits int sample format
    PaInt32 =           ffi::PaInt32,
    /// 16 bits int sample format
    PaInt16 =           ffi::PaInt16,
    /// 8 bits int sample format
    PaInt8 =            ffi::PaInt8,
    /// 8 bits unsigned int sample format
    PaUInt8 =           ffi::PaUInt8,
    /// Custom sample format
    PaCustomFormat =    ffi::PaCustomFormat,
    /// Non interleaved sample format
    PaNonInterleaved =  ffi::PaNonInterleaved
}

/// The flags to pass to a stream
#[repr(u64)]
#[deriving(Clone, PartialEq, PartialOrd, Show)]
pub enum PaStreamFlags {
    /// No flags
    PaNoFlag =                                  ffi::PaNoFlag,
    /// Disable default clipping of out of range samples.
    PaClipOff =                                 ffi::PaClipOff,
    /// Disable default dithering.
    PaDitherOff =                               ffi::PaDitherOff,
    /// Flag requests that where possible a full duplex stream will not discard overflowed input samples without calling the stream callback.
    PaNeverDropInput =                          ffi::PaNeverDropInput,
    /// Call the stream callback to fill initial output buffers, rather than the default behavior of priming the buffers with zeros (silence)
    PaPrimeOutputBuffersUsingStreamCallback =   ffi::PaPrimeOutputBuffersUsingStreamCallback,
    /// A mask specifying the platform specific bits.
    PaPlatformSpecificFlags =                   ffi::PaPlatformSpecificFlags
}

#[doc(hidden)]
pub type PaStreamCallbackFlags = u64;
/*
    pub static PaInputUnderflow : PaStreamCallbackFlags = 0x00000001;
    pub static PaInputOverflow : PaStreamCallbackFlags = 0x00000002;
    pub static PaOutputUnderflow : PaStreamCallbackFlags = 0x00000004;
    pub static PaOutputOverflow : PaStreamCallbackFlags = 0x00000008;
    pub static PaPrimingOutput : PaStreamCallbackFlags = 0x00000010;
*/

#[doc(hidden)]
pub type PaCallbackFunction = extern fn(i : f32) -> PaStreamCallbackResult;
#[doc(hidden)]
pub enum PaStreamCallbackResult {
    PaContinue = 0,
    PaComplete = 1,
    PaAbort = 2
}

/// Error codes returned by PortAudio functions.
#[repr(C)]
#[deriving(Clone, PartialEq, PartialOrd, Show)]
pub enum PaError {
    /// No Error
    PaNoError = 0,
    /// Portaudio not initialized
    PaNotInitialized = -10000,
    /// Unanticipated error from the host
    PaUnanticipatedHostError,
    /// Invalid channel count
    PaInvalidChannelCount,
    /// Invalid sample rate
    PaInvalidSampleRate,
    /// Invalid Device
    PaInvalidDevice,
    /// Invalid Flag
    PaInvalidFlag,
    /// The Sample format is not supported
    PaSampleFormatNotSupported,
    /// Input device not compatible with output device
    PaBadIODeviceCombination,
    /// Memory insufficient
    PaInsufficientMemory,
    /// The buffer is too big
    PaBufferTooBig,
    /// The buffer is too small
    PaBufferTooSmall,
    /// Invalid callback
    PaNullCallback,
    /// Invalid Stream
    PaBadStreamPtr,
    /// Time out
    PaTimedOut,
    /// Portaudio internal error
    PaInternalError,
    /// Device unavailable
    PaDeviceUnavailable,
    /// Stream info not compatible with the host
    PaIncompatibleHostApiSpecificStreamInfo,
    /// The stream is stopped
    PaStreamIsStopped,
    /// The stream is not stopped
    PaStreamIsNotStopped,
    /// The input stream has overflowed
    PaInputOverflowed,
    /// The output has overflowed
    PaOutputUnderflowed,
    /// The host API is not found by Portaudio
    PaHostApiNotFound,
    /// The host API is invalid
    PaInvalidHostApi,
    /// Portaudio cannot read from the callback stream
    PaCanNotReadFromACallbackStream,
    /// Portaudio cannot wrtie to the callback stream
    PaCanNotWriteToACallbackStream,
    /// Portaudio cannot read from an output only stream
    PaCanNotReadFromAnOutputOnlyStream,
    /// Portaudio cannot write to an input only stream
    PaCanNotWriteToAnInputOnlyStream,
    /// The stream is not compatible with the host API
    PaIncompatibleStreamHostApi,
    /// Invalid buffer
    PaBadBufferPtr
}

/// Unchanging unique identifiers for each supported host API
#[repr(i32)]
#[deriving(Clone, PartialEq, PartialOrd, Show)]
pub enum PaHostApiTypeId {
    /// In development host
    PaInDevelopment =   ffi::PaInDevelopment,
    /// Direct sound
    PaDirectSound =     ffi::PaDirectSound,
    /// MMe API
    PaMME =             ffi::PaMME,
    /// ASIO API
    PaASIO =            ffi::PaASIO,
    /// Sound manager API
    PaSoundManager =    ffi::PaSoundManager,
    /// Core Audio API
    PaCoreAudio =       ffi::PaCoreAudio,
    /// OSS API
    PaOSS =             ffi::PaOSS,
    /// Alsa API
    PaALSA =            ffi::PaALSA,
    /// AL API
    PaAL =              ffi::PaAL,
    /// BeOS API
    PaBeOS =            ffi::PaBeOS,
    /// WDMKS
    PaWDMKS =           ffi::PaWDMKS,
    /// Jack API
    PaJACK =            ffi::PaJACK,
    /// WASAPI
    PaWASAPI =          ffi::PaWASAPI,
    /// Audio Science HPI
    PaAudioScienceHPI = ffi::PaAudioScienceHPI
}

/// A structure containing information about a particular host API.
pub struct PaHostApiInfo{
    /// The version of the struct
    pub struct_version : int,
    /// The type of the current host
    pub host_type : PaHostApiTypeId,
    /// The name of the host
    pub name : String,
    /// The total count of device in the host
    pub device_count : int,
    /// The index to the default input device
    pub default_input_device : PaDeviceIndex,
    /// The index to the default output device
    pub default_output_device : PaDeviceIndex
}

#[doc(hidden)]
impl PaHostApiInfo {
    pub fn wrap(c_info : *const ffi::C_PaHostApiInfo) -> PaHostApiInfo {
        unsafe {
            PaHostApiInfo {
                struct_version : (*c_info).struct_version as int,
                host_type : transmute(((*c_info).host_type)),
                name : string::raw::from_buf((*c_info).name as *const u8),
                device_count : (*c_info).device_count as int,
                default_input_device : (*c_info).default_input_device,
                default_output_device : (*c_info).default_output_device
            }
        }
    }

    pub fn unwrap(&self) -> ffi::C_PaHostApiInfo {
        ffi::C_PaHostApiInfo {
            struct_version : self.struct_version as i32,
            host_type : self.host_type as i32,
            name : unsafe { self.name.to_c_str().unwrap() },
            device_count : self.device_count as i32,
            default_input_device : self.default_input_device as i32,
            default_output_device : self.default_output_device as i32
        }
    }
}

/// Structure used to return information about a host error condition.
#[deriving(Clone, PartialEq, PartialOrd, Show)]
pub struct PaHostErrorInfo {
    /// The code of the error
    pub error_code : u32,
    /// The string which explain the error
    pub error_text : String
}

#[doc(hidden)]
impl PaHostErrorInfo {
    pub fn wrap(c_error : *const ffi::C_PaHostErrorInfo) -> PaHostErrorInfo {
        PaHostErrorInfo {
            error_code : unsafe { (*c_error).error_code },
            error_text : unsafe { string::raw::from_buf((*c_error).error_text as *const u8) }
        }
    }

    pub fn unwrap(&self) -> ffi::C_PaHostErrorInfo {
        ffi::C_PaHostErrorInfo {
            error_code : self.error_code,
            error_text : unsafe { self.error_text.to_c_str().unwrap() }
        }
    }
}

/// A structure providing information and capabilities of PortAudio devices.
/// Devices may support input, output or both input and output.
#[deriving(Clone, PartialEq, PartialOrd, Show)]
pub struct PaDeviceInfo {
    /// The version of the struct
    pub struct_version : int,
    /// The name of the devie
    pub name : String,
    /// Host API identifier
    pub host_api : PaHostApiIndex,
    /// Maximal number of input channels for this device
    pub max_input_channels : int,
    /// maximal number of output channel for this device
    pub max_output_channels : int,
    /// The default low latency for input with this device
    pub default_low_input_latency : PaTime,
    /// The default low latency for output with this device
    pub default_low_output_latency : PaTime,
    /// The default high latency for input with this device
    pub default_high_input_latency : PaTime,
    /// The default high latency for output with this device
    pub default_high_output_latency : PaTime,
    /// The default sample rate for this device
    pub default_sample_rate : f64
}

#[doc(hidden)]
impl PaDeviceInfo {
    pub fn wrap(c_info : *const ffi::C_PaDeviceInfo) -> PaDeviceInfo {
        unsafe {
            PaDeviceInfo {
                struct_version : (*c_info).struct_version as int,
                name : string::raw::from_buf((*c_info).name as *const u8),
                host_api : (*c_info).host_api,
                max_input_channels : (*c_info).max_input_channels as int,
                max_output_channels : (*c_info).max_output_channels as int,
                default_low_input_latency : (*c_info).default_low_input_latency,
                default_low_output_latency : (*c_info).default_low_output_latency,
                default_high_input_latency : (*c_info).default_high_input_latency,
                default_high_output_latency : (*c_info).default_high_output_latency,
                default_sample_rate : (*c_info).default_sample_rate
            }
        }
    }

    pub fn unwrap(&self) -> ffi::C_PaDeviceInfo {
        ffi::C_PaDeviceInfo {
            struct_version : self.struct_version as i32,
            name : unsafe { self.name.to_c_str().unwrap() },
            host_api : self.host_api,
            max_input_channels : self.max_input_channels as i32,
            max_output_channels : self.max_output_channels as i32,
            default_low_input_latency : self.default_low_input_latency,
            default_low_output_latency : self.default_low_output_latency,
            default_high_input_latency : self.default_high_input_latency,
            default_high_output_latency : self.default_high_output_latency,
            default_sample_rate : self.default_sample_rate
        }
    }
}

/// Parameters for one direction (input or output) of a stream.
#[deriving(Clone, PartialEq, PartialOrd, Show)]
pub struct PaStreamParameters {
    /// Index of the device
    pub device : PaDeviceIndex,
    /// The number of channels for this device
    pub channel_count : i32,
    /// Sample format of the device
    pub sample_format : PaSampleFormat,
    /// The suggested latency for this device
    pub suggested_latency : PaTime,
}

#[doc(hidden)]
impl PaStreamParameters {
    pub fn wrap(c_parameters : *mut ffi::C_PaStreamParameters) -> PaStreamParameters {
        unsafe {
            PaStreamParameters {
                device : (*c_parameters).device,
                channel_count : (*c_parameters).channel_count,
                sample_format : transmute((*c_parameters).sample_format),
                suggested_latency : (*c_parameters).suggested_latency
            }
        }
    }

    pub fn unwrap(&self) -> ffi::C_PaStreamParameters {
        ffi::C_PaStreamParameters {
            device : self.device,
            channel_count : self.channel_count as i32,
            sample_format : self.sample_format as ffi::PaSampleFormat,
            suggested_latency : self.suggested_latency,
            host_api_specific_stream_info : ptr::null_mut()
        }
    }
}

#[doc(hidden)]
pub struct PaStreamCallbackTimeInfo {
    pub input_buffer_adc_time : PaTime,
    pub current_time : PaTime,
    pub output_buffer_dac_time : PaTime
}

/// A structure containing unchanging information about an open stream.
#[deriving(Clone, PartialEq, PartialOrd, Show)]
#[repr(C)]
pub struct PaStreamInfo {
    /// Struct version
    pub struct_version : i32,
    /// The input latency for this open stream
    pub input_latency : PaTime,
    /// The output latency for this open stream
    pub output_latency : PaTime,
    /// The sample rate for this open stream
    pub sample_rate : f64
}

<commit_msg>Add repr(C) to ffi types<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

//! Types used in the PortAudio API

#![allow(dead_code)]

use std::{string, ptr};
use std::mem::{transmute};

use ffi;

/// The type used to refer to audio devices. Values of this type usually range
/// from 0 to (pa::get_device_count()-1)
pub type PaDeviceIndex = i32;
/// A special PaDeviceIndex value indicating that no device is available,
/// or should be used.
pub static PaNoDevice: PaDeviceIndex = -1;
/// A special PaDeviceIndex value indicating that the device(s) to be used are
/// specified in the host api specific stream info structure.
pub static PaUseHostApiSpecificDeviceSpecification: PaDeviceIndex = -2;

/// The type used to enumerate to host APIs at runtime.
/// Values of this type range from 0 to (pa::get_host_api_count()-1).
pub type PaHostApiIndex = i32;

/// The type used to represent monotonic time in seconds.
pub type PaTime = f64;

/// A type used to specify one or more sample formats.
#[repr(u64)]
#[deriving(Clone, PartialEq, PartialOrd, Show)]
pub enum PaSampleFormat {
    /// 32 bits float sample format
    PaFloat32 =         ffi::PaFloat32,
    /// 32 bits int sample format
    PaInt32 =           ffi::PaInt32,
    /// 16 bits int sample format
    PaInt16 =           ffi::PaInt16,
    /// 8 bits int sample format
    PaInt8 =            ffi::PaInt8,
    /// 8 bits unsigned int sample format
    PaUInt8 =           ffi::PaUInt8,
    /// Custom sample format
    PaCustomFormat =    ffi::PaCustomFormat,
    /// Non interleaved sample format
    PaNonInterleaved =  ffi::PaNonInterleaved
}

/// The flags to pass to a stream
#[repr(u64)]
#[deriving(Clone, PartialEq, PartialOrd, Show)]
pub enum PaStreamFlags {
    /// No flags
    PaNoFlag =                                  ffi::PaNoFlag,
    /// Disable default clipping of out of range samples.
    PaClipOff =                                 ffi::PaClipOff,
    /// Disable default dithering.
    PaDitherOff =                               ffi::PaDitherOff,
    /// Flag requests that where possible a full duplex stream will not discard overflowed input samples without calling the stream callback.
    PaNeverDropInput =                          ffi::PaNeverDropInput,
    /// Call the stream callback to fill initial output buffers, rather than the default behavior of priming the buffers with zeros (silence)
    PaPrimeOutputBuffersUsingStreamCallback =   ffi::PaPrimeOutputBuffersUsingStreamCallback,
    /// A mask specifying the platform specific bits.
    PaPlatformSpecificFlags =                   ffi::PaPlatformSpecificFlags
}

#[doc(hidden)]
pub type PaStreamCallbackFlags = u64;
/*
    pub static PaInputUnderflow : PaStreamCallbackFlags = 0x00000001;
    pub static PaInputOverflow : PaStreamCallbackFlags = 0x00000002;
    pub static PaOutputUnderflow : PaStreamCallbackFlags = 0x00000004;
    pub static PaOutputOverflow : PaStreamCallbackFlags = 0x00000008;
    pub static PaPrimingOutput : PaStreamCallbackFlags = 0x00000010;
*/

#[doc(hidden)]
pub type PaCallbackFunction = extern fn(i : f32) -> PaStreamCallbackResult;
#[doc(hidden)]
#[repr(C)]
pub enum PaStreamCallbackResult {
    PaContinue = 0,
    PaComplete = 1,
    PaAbort = 2
}

/// Error codes returned by PortAudio functions.
#[repr(C)]
#[deriving(Clone, PartialEq, PartialOrd, Show)]
pub enum PaError {
    /// No Error
    PaNoError = 0,
    /// Portaudio not initialized
    PaNotInitialized = -10000,
    /// Unanticipated error from the host
    PaUnanticipatedHostError,
    /// Invalid channel count
    PaInvalidChannelCount,
    /// Invalid sample rate
    PaInvalidSampleRate,
    /// Invalid Device
    PaInvalidDevice,
    /// Invalid Flag
    PaInvalidFlag,
    /// The Sample format is not supported
    PaSampleFormatNotSupported,
    /// Input device not compatible with output device
    PaBadIODeviceCombination,
    /// Memory insufficient
    PaInsufficientMemory,
    /// The buffer is too big
    PaBufferTooBig,
    /// The buffer is too small
    PaBufferTooSmall,
    /// Invalid callback
    PaNullCallback,
    /// Invalid Stream
    PaBadStreamPtr,
    /// Time out
    PaTimedOut,
    /// Portaudio internal error
    PaInternalError,
    /// Device unavailable
    PaDeviceUnavailable,
    /// Stream info not compatible with the host
    PaIncompatibleHostApiSpecificStreamInfo,
    /// The stream is stopped
    PaStreamIsStopped,
    /// The stream is not stopped
    PaStreamIsNotStopped,
    /// The input stream has overflowed
    PaInputOverflowed,
    /// The output has overflowed
    PaOutputUnderflowed,
    /// The host API is not found by Portaudio
    PaHostApiNotFound,
    /// The host API is invalid
    PaInvalidHostApi,
    /// Portaudio cannot read from the callback stream
    PaCanNotReadFromACallbackStream,
    /// Portaudio cannot wrtie to the callback stream
    PaCanNotWriteToACallbackStream,
    /// Portaudio cannot read from an output only stream
    PaCanNotReadFromAnOutputOnlyStream,
    /// Portaudio cannot write to an input only stream
    PaCanNotWriteToAnInputOnlyStream,
    /// The stream is not compatible with the host API
    PaIncompatibleStreamHostApi,
    /// Invalid buffer
    PaBadBufferPtr
}

/// Unchanging unique identifiers for each supported host API
#[repr(i32)]
#[deriving(Clone, PartialEq, PartialOrd, Show)]
pub enum PaHostApiTypeId {
    /// In development host
    PaInDevelopment =   ffi::PaInDevelopment,
    /// Direct sound
    PaDirectSound =     ffi::PaDirectSound,
    /// MMe API
    PaMME =             ffi::PaMME,
    /// ASIO API
    PaASIO =            ffi::PaASIO,
    /// Sound manager API
    PaSoundManager =    ffi::PaSoundManager,
    /// Core Audio API
    PaCoreAudio =       ffi::PaCoreAudio,
    /// OSS API
    PaOSS =             ffi::PaOSS,
    /// Alsa API
    PaALSA =            ffi::PaALSA,
    /// AL API
    PaAL =              ffi::PaAL,
    /// BeOS API
    PaBeOS =            ffi::PaBeOS,
    /// WDMKS
    PaWDMKS =           ffi::PaWDMKS,
    /// Jack API
    PaJACK =            ffi::PaJACK,
    /// WASAPI
    PaWASAPI =          ffi::PaWASAPI,
    /// Audio Science HPI
    PaAudioScienceHPI = ffi::PaAudioScienceHPI
}

/// A structure containing information about a particular host API.
pub struct PaHostApiInfo{
    /// The version of the struct
    pub struct_version : int,
    /// The type of the current host
    pub host_type : PaHostApiTypeId,
    /// The name of the host
    pub name : String,
    /// The total count of device in the host
    pub device_count : int,
    /// The index to the default input device
    pub default_input_device : PaDeviceIndex,
    /// The index to the default output device
    pub default_output_device : PaDeviceIndex
}

#[doc(hidden)]
impl PaHostApiInfo {
    pub fn wrap(c_info : *const ffi::C_PaHostApiInfo) -> PaHostApiInfo {
        unsafe {
            PaHostApiInfo {
                struct_version : (*c_info).struct_version as int,
                host_type : transmute(((*c_info).host_type)),
                name : string::raw::from_buf((*c_info).name as *const u8),
                device_count : (*c_info).device_count as int,
                default_input_device : (*c_info).default_input_device,
                default_output_device : (*c_info).default_output_device
            }
        }
    }

    pub fn unwrap(&self) -> ffi::C_PaHostApiInfo {
        ffi::C_PaHostApiInfo {
            struct_version : self.struct_version as i32,
            host_type : self.host_type as i32,
            name : unsafe { self.name.to_c_str().unwrap() },
            device_count : self.device_count as i32,
            default_input_device : self.default_input_device as i32,
            default_output_device : self.default_output_device as i32
        }
    }
}

/// Structure used to return information about a host error condition.
#[deriving(Clone, PartialEq, PartialOrd, Show)]
pub struct PaHostErrorInfo {
    /// The code of the error
    pub error_code : u32,
    /// The string which explain the error
    pub error_text : String
}

#[doc(hidden)]
impl PaHostErrorInfo {
    pub fn wrap(c_error : *const ffi::C_PaHostErrorInfo) -> PaHostErrorInfo {
        PaHostErrorInfo {
            error_code : unsafe { (*c_error).error_code },
            error_text : unsafe { string::raw::from_buf((*c_error).error_text as *const u8) }
        }
    }

    pub fn unwrap(&self) -> ffi::C_PaHostErrorInfo {
        ffi::C_PaHostErrorInfo {
            error_code : self.error_code,
            error_text : unsafe { self.error_text.to_c_str().unwrap() }
        }
    }
}

/// A structure providing information and capabilities of PortAudio devices.
/// Devices may support input, output or both input and output.
#[deriving(Clone, PartialEq, PartialOrd, Show)]
pub struct PaDeviceInfo {
    /// The version of the struct
    pub struct_version : int,
    /// The name of the devie
    pub name : String,
    /// Host API identifier
    pub host_api : PaHostApiIndex,
    /// Maximal number of input channels for this device
    pub max_input_channels : int,
    /// maximal number of output channel for this device
    pub max_output_channels : int,
    /// The default low latency for input with this device
    pub default_low_input_latency : PaTime,
    /// The default low latency for output with this device
    pub default_low_output_latency : PaTime,
    /// The default high latency for input with this device
    pub default_high_input_latency : PaTime,
    /// The default high latency for output with this device
    pub default_high_output_latency : PaTime,
    /// The default sample rate for this device
    pub default_sample_rate : f64
}

#[doc(hidden)]
impl PaDeviceInfo {
    pub fn wrap(c_info : *const ffi::C_PaDeviceInfo) -> PaDeviceInfo {
        unsafe {
            PaDeviceInfo {
                struct_version : (*c_info).struct_version as int,
                name : string::raw::from_buf((*c_info).name as *const u8),
                host_api : (*c_info).host_api,
                max_input_channels : (*c_info).max_input_channels as int,
                max_output_channels : (*c_info).max_output_channels as int,
                default_low_input_latency : (*c_info).default_low_input_latency,
                default_low_output_latency : (*c_info).default_low_output_latency,
                default_high_input_latency : (*c_info).default_high_input_latency,
                default_high_output_latency : (*c_info).default_high_output_latency,
                default_sample_rate : (*c_info).default_sample_rate
            }
        }
    }

    pub fn unwrap(&self) -> ffi::C_PaDeviceInfo {
        ffi::C_PaDeviceInfo {
            struct_version : self.struct_version as i32,
            name : unsafe { self.name.to_c_str().unwrap() },
            host_api : self.host_api,
            max_input_channels : self.max_input_channels as i32,
            max_output_channels : self.max_output_channels as i32,
            default_low_input_latency : self.default_low_input_latency,
            default_low_output_latency : self.default_low_output_latency,
            default_high_input_latency : self.default_high_input_latency,
            default_high_output_latency : self.default_high_output_latency,
            default_sample_rate : self.default_sample_rate
        }
    }
}

/// Parameters for one direction (input or output) of a stream.
#[deriving(Clone, PartialEq, PartialOrd, Show)]
pub struct PaStreamParameters {
    /// Index of the device
    pub device : PaDeviceIndex,
    /// The number of channels for this device
    pub channel_count : i32,
    /// Sample format of the device
    pub sample_format : PaSampleFormat,
    /// The suggested latency for this device
    pub suggested_latency : PaTime,
}

#[doc(hidden)]
impl PaStreamParameters {
    pub fn wrap(c_parameters : *mut ffi::C_PaStreamParameters) -> PaStreamParameters {
        unsafe {
            PaStreamParameters {
                device : (*c_parameters).device,
                channel_count : (*c_parameters).channel_count,
                sample_format : transmute((*c_parameters).sample_format),
                suggested_latency : (*c_parameters).suggested_latency
            }
        }
    }

    pub fn unwrap(&self) -> ffi::C_PaStreamParameters {
        ffi::C_PaStreamParameters {
            device : self.device,
            channel_count : self.channel_count as i32,
            sample_format : self.sample_format as ffi::PaSampleFormat,
            suggested_latency : self.suggested_latency,
            host_api_specific_stream_info : ptr::null_mut()
        }
    }
}

#[doc(hidden)]
#[repr(C)]
pub struct PaStreamCallbackTimeInfo {
    pub input_buffer_adc_time : PaTime,
    pub current_time : PaTime,
    pub output_buffer_dac_time : PaTime
}

/// A structure containing unchanging information about an open stream.
#[deriving(Clone, PartialEq, PartialOrd, Show)]
#[repr(C)]
pub struct PaStreamInfo {
    /// Struct version
    pub struct_version : i32,
    /// The input latency for this open stream
    pub input_latency : PaTime,
    /// The output latency for this open stream
    pub output_latency : PaTime,
    /// The sample rate for this open stream
    pub sample_rate : f64
}

<|endoftext|>


<commit_before>//! Types that specify what is contained in a ZIP.

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum System
{
    Dos = 0,
    Unix = 3,
    Unknown,
    #[doc(hidden)]
    __Nonexhaustive,
}

impl System {
    pub fn from_u8(system: u8) -> System
    {
        use self::System::*;

        match system {
            0 => Dos,
            3 => Unix,
            _ => Unknown,
        }
    }
}

/// A DateTime field to be used for storing timestamps in a zip file
///
/// This structure does bounds checking to ensure the date is able to be stored in a zip file.
#[derive(Debug, Clone, Copy)]
pub struct DateTime {
    year: u16,
    month: u8,
    day: u8,
    hour: u8,
    minute: u8,
    second: u8,
}

impl DateTime {
    /// Constructs an 'default' datetime of 1980-01-01 00:00:00
    pub fn default() -> DateTime {
        DateTime {
            year: 1980,
            month: 1,
            day: 1,
            hour: 0,
            minute: 0,
            second: 0,
        }
    }

    /// Converts an msdos (u16, u16) pair to a DateTime object
    pub fn from_msdos(datepart: u16, timepart: u16) -> DateTime {
        let seconds = (timepart & 0b0000000000011111) << 1;
        let minutes = (timepart & 0b0000011111100000) >> 5;
        let hours =   (timepart & 0b1111100000000000) >> 11;
        let days =    (datepart & 0b0000000000011111) >> 0;
        let months =  (datepart & 0b0000000111100000) >> 5;
        let years =   (datepart & 0b1111111000000000) >> 9;

        DateTime {
            year: (years + 1980) as u16,
            month: months as u8,
            day: days as u8,
            hour: hours as u8,
            minute: minutes as u8,
            second: seconds as u8,
        }
    }

    /// Constructs a DateTime from a specific date and time
    ///
    /// The bounds are:
    /// * year: [1980, 2107]
    /// * month: [1, 12]
    /// * day: [1, 31]
    /// * hour: [0, 23]
    /// * minute: [0, 59]
    /// * second: [0, 60]
    pub fn from_date_and_time(year: u16, month: u8, day: u8, hour: u8, minute: u8, second: u8) -> Result<DateTime, ()> {
        (DateTime { year: 0, month: 0, day: 0, hour: 0, minute: 0, second: 0 })
            .with_date(year, month, day)?
            .with_time(hour, minute, second)
    }

    /// Constructs a DateTime with a specific date set.
    ///
    /// The bounds are:
    /// * year: [1980, 2107]
    /// * month: [1, 12]
    /// * day: [1, 31]
    pub fn with_date(self, year: u16, month: u8, day: u8) -> Result<DateTime, ()> {
        if year >= 1980 && year <= 2107
            && month >= 1 && month <= 12
            && day >= 1 && day <= 31
        {
            Ok(DateTime {
                year: year,
                month: month,
                day: day,
                hour: self.hour,
                minute: self.minute,
                second: self.second,
            })
        }
        else {
            Err(())
        }
    }

    /// Constructs a DateTime with a specific time set.
    ///
    /// The bounds are:
    /// * hour: [0, 23]
    /// * minute: [0, 59]
    /// * second: [0, 60]
    pub fn with_time(self, hour: u8, minute: u8, second: u8) -> Result<DateTime, ()> {
        if hour <= 23 && minute <= 59 && second <= 60 {
            Ok(DateTime {
                year: self.year,
                month: self.month,
                day: self.day,
                hour: hour,
                minute: minute,
                second: second,
            })
        }
        else {
            Err(())
        }
    }

    #[cfg(feature = "time")]
    /// Converts a ::time::Tm object to a DateTime
    ///
    /// Returns `Err` when this object is out of bounds
    pub fn from_time(tm: ::time::Tm) -> Result<DateTime, ()> {
        if tm.tm_year >= 1980 && tm.tm_year <= 2107
            && tm.tm_mon >= 1 && tm.tm_mon <= 31
            && tm.tm_mday >= 1 && tm.tm_mday <= 31
            && tm.tm_hour >= 0 && tm.tm_hour <= 23
            && tm.tm_min >= 0 && tm.tm_min <= 59
            && tm.tm_sec >= 0 && tm.tm_sec <= 60
        {
            Ok(DateTime {
                year: (tm.tm_year + 1900) as u16,
                month: (tm.tm_mon + 1) as u8,
                day: tm.tm_mday as u8,
                hour: tm.tm_hour as u8,
                minute: tm.tm_min as u8,
                second: tm.tm_sec as u8,
            })
        }
        else {
            Err(())
        }
    }

    /// Gets the time portion of this datetime in the msdos representation
    pub fn timepart(&self) -> u16 {
        ((self.second as u16) >> 1) | ((self.minute as u16) << 5) | ((self.hour as u16) << 11)
    }

    /// Gets the date portion of this datetime in the msdos representation
    pub fn datepart(&self) -> u16 {
        (self.day as u16) | ((self.month as u16) << 5) | ((self.year - 1980) << 9)
    }
}

pub const DEFAULT_VERSION: u8 = 46;

/// Structure representing a ZIP file.
#[derive(Debug, Clone)]
pub struct ZipFileData
{
    /// Compatibility of the file attribute information
    pub system: System,
    /// Specification version
    pub version_made_by: u8,
    /// True if the file is encrypted.
    pub encrypted: bool,
    /// Compression method used to store the file
    pub compression_method: ::compression::CompressionMethod,
    /// Last modified time. This will only have a 2 second precision.
    pub last_modified_time: DateTime,
    /// CRC32 checksum
    pub crc32: u32,
    /// Size of the file in the ZIP
    pub compressed_size: u64,
    /// Size of the file when extracted
    pub uncompressed_size: u64,
    /// Name of the file
    pub file_name: String,
    /// Raw file name. To be used when file_name was incorrectly decoded.
    pub file_name_raw: Vec<u8>,
    /// File comment
    pub file_comment: String,
    /// Specifies where the local header of the file starts
    pub header_start: u64,
    /// Specifies where the compressed data of the file starts
    pub data_start: u64,
    /// External file attributes
    pub external_attributes: u32,
}

impl ZipFileData {
    pub fn file_name_sanitized(&self) -> ::std::path::PathBuf {
        let no_null_filename = match self.file_name.find('\0') {
            Some(index) => &self.file_name[0..index],
            None => &self.file_name,
        }.to_string();

        // zip files can contain both / and \ as separators regardless of the OS
        // and as we want to return a sanitized PathBuf that only supports the
        // OS separator let's convert incompatible separators to compatible ones
        let separator = ::std::path::MAIN_SEPARATOR;
        let opposite_separator = match separator {
            '/' => '\\',
            '\\' | _ => '/',
        };
        let filename =
            no_null_filename.replace(&opposite_separator.to_string(), &separator.to_string());

        ::std::path::Path::new(&filename)
            .components()
            .filter(|component| match *component {
                ::std::path::Component::Normal(..) => true,
                _ => false,
            })
            .fold(::std::path::PathBuf::new(), |mut path, ref cur| {
                path.push(cur.as_os_str());
                path
            })
    }

    pub fn version_needed(&self) -> u16 {
        match self.compression_method {
            #[cfg(feature = "bzip2")]
            ::compression::CompressionMethod::Bzip2 => 46,
            _ => 20,
        }
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn system() {
        use super::System;
        assert_eq!(System::Dos as u16, 0u16);
        assert_eq!(System::Unix as u16, 3u16);
        assert_eq!(System::from_u8(0), System::Dos);
        assert_eq!(System::from_u8(3), System::Unix);
    }

    #[test]
    fn sanitize() {
        use super::*;
        let file_name = "/path/../../../../etc/./passwd\0/etc/shadow".to_string();
        let data = ZipFileData {
            system: System::Dos,
            version_made_by: 0,
            encrypted: false,
            compression_method: ::compression::CompressionMethod::Stored,
            last_modified_time: DateTime::default(),
            crc32: 0,
            compressed_size: 0,
            uncompressed_size: 0,
            file_name: file_name.clone(),
            file_name_raw: file_name.into_bytes(),
            file_comment: String::new(),
            header_start: 0,
            data_start: 0,
            external_attributes: 0,
        };
        assert_eq!(data.file_name_sanitized(), ::std::path::PathBuf::from("path/etc/passwd"));
    }

    #[test]
    fn datetime_default() {
        use super::DateTime;
        let dt = DateTime::default();
        assert_eq!(dt.timepart(), 0);
        assert_eq!(dt.datepart(), 0b0000000_0001_00001);
    }

    #[test]
    fn datetime_max() {
        use super::DateTime;
        let dt = DateTime::from_date_and_time(2107, 12, 31, 23, 59, 60).unwrap();
        assert_eq!(dt.timepart(), 0b10111_111011_11110);
        assert_eq!(dt.datepart(), 0b1111111_1100_11111);
    }

    #[test]
    fn datetime_bounds() {
        use super::DateTime;
        let dt = DateTime::default();

        assert!(dt.with_time(23, 59, 60).is_ok());
        assert!(dt.with_time(24, 0, 0).is_err());
        assert!(dt.with_time(0, 60, 0).is_err());
        assert!(dt.with_time(0, 0, 61).is_err());

        assert!(dt.with_date(2107, 12, 31).is_ok());
        assert!(dt.with_date(1980, 1, 1).is_ok());
        assert!(dt.with_date(1979, 1, 1).is_err());
        assert!(dt.with_date(1980, 0, 1).is_err());
        assert!(dt.with_date(1980, 1, 0).is_err());
        assert!(dt.with_date(2108, 12, 31).is_err());
        assert!(dt.with_date(2107, 13, 31).is_err());
        assert!(dt.with_date(2107, 12, 32).is_err());
    }
}
<commit_msg>Update DateTime API<commit_after>//! Types that specify what is contained in a ZIP.

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum System
{
    Dos = 0,
    Unix = 3,
    Unknown,
    #[doc(hidden)]
    __Nonexhaustive,
}

impl System {
    pub fn from_u8(system: u8) -> System
    {
        use self::System::*;

        match system {
            0 => Dos,
            3 => Unix,
            _ => Unknown,
        }
    }
}

/// A DateTime field to be used for storing timestamps in a zip file
///
/// This structure does bounds checking to ensure the date is able to be stored in a zip file.
///
/// When constructed manually from a date and time, it will also check if the input is sensible
/// (e.g. months are from [1, 12]), but when read from a zip some parts may be out of their normal
/// bounds (e.g. month 0, or hour 31).
#[derive(Debug, Clone, Copy)]
pub struct DateTime {
    year: u16,
    month: u8,
    day: u8,
    hour: u8,
    minute: u8,
    second: u8,
}

impl std::default::Default for DateTime {
    /// Constructs an 'default' datetime of 1980-01-01 00:00:00
    fn default() -> DateTime {
        DateTime {
            year: 1980,
            month: 1,
            day: 1,
            hour: 0,
            minute: 0,
            second: 0,
        }
    }
}

impl DateTime {
    /// Converts an msdos (u16, u16) pair to a DateTime object
    pub fn from_msdos(datepart: u16, timepart: u16) -> DateTime {
        let seconds = (timepart & 0b0000000000011111) << 1;
        let minutes = (timepart & 0b0000011111100000) >> 5;
        let hours =   (timepart & 0b1111100000000000) >> 11;
        let days =    (datepart & 0b0000000000011111) >> 0;
        let months =  (datepart & 0b0000000111100000) >> 5;
        let years =   (datepart & 0b1111111000000000) >> 9;

        DateTime {
            year: (years + 1980) as u16,
            month: months as u8,
            day: days as u8,
            hour: hours as u8,
            minute: minutes as u8,
            second: seconds as u8,
        }
    }

    /// Constructs a DateTime from a specific date and time
    ///
    /// The bounds are:
    /// * year: [1980, 2107]
    /// * month: [1, 12]
    /// * day: [1, 31]
    /// * hour: [0, 23]
    /// * minute: [0, 59]
    /// * second: [0, 60]
    pub fn from_date_and_time(year: u16, month: u8, day: u8, hour: u8, minute: u8, second: u8) -> Result<DateTime, ()> {
        if year >= 1980 && year <= 2107
            && month >= 1 && month <= 12
            && day >= 1 && day <= 31
            && hour <= 23
            && minute <= 59
            && second <= 60
        {
            Ok(DateTime {
                year: year,
                month: month,
                day: day,
                hour: hour,
                minute: minute,
                second: second,
            })
        }
        else {
            Err(())
        }
    }

    #[cfg(feature = "time")]
    /// Converts a ::time::Tm object to a DateTime
    ///
    /// Returns `Err` when this object is out of bounds
    pub fn from_time(tm: ::time::Tm) -> Result<DateTime, ()> {
        if tm.tm_year >= 1980 && tm.tm_year <= 2107
            && tm.tm_mon >= 1 && tm.tm_mon <= 31
            && tm.tm_mday >= 1 && tm.tm_mday <= 31
            && tm.tm_hour >= 0 && tm.tm_hour <= 23
            && tm.tm_min >= 0 && tm.tm_min <= 59
            && tm.tm_sec >= 0 && tm.tm_sec <= 60
        {
            Ok(DateTime {
                year: (tm.tm_year + 1900) as u16,
                month: (tm.tm_mon + 1) as u8,
                day: tm.tm_mday as u8,
                hour: tm.tm_hour as u8,
                minute: tm.tm_min as u8,
                second: tm.tm_sec as u8,
            })
        }
        else {
            Err(())
        }
    }

    /// Gets the time portion of this datetime in the msdos representation
    pub fn timepart(&self) -> u16 {
        ((self.second as u16) >> 1) | ((self.minute as u16) << 5) | ((self.hour as u16) << 11)
    }

    /// Gets the date portion of this datetime in the msdos representation
    pub fn datepart(&self) -> u16 {
        (self.day as u16) | ((self.month as u16) << 5) | ((self.year - 1980) << 9)
    }

    #[cfg(feature = "time")]
    /// Converts the datetime to a Tm structure
    ///
    /// The fields `tm_wday`, `tm_yday`, `tm_utcoff` and `tm_nsec` are set to their defaults.
    pub fn to_time(&self) -> ::time::Tm {
        ::time::Tm {
            tm_sec: self.second as i32,
            tm_min: self.minute as i32,
            tm_hour: self.hour as i32,
            tm_mday: self.day as i32,
            tm_mon: self.month as i32 - 1,
            tm_year: self.year as i32 - 1900,
            tm_isdst: -1,
            .. ::time::empty_tm()
        }
    }

    /// Get the year. There is no epoch, i.e. 2018 will be returned as 2018.
    pub fn year(&self) -> u16 {
        self.year
    }

    /// Get the month, where 1 = january and 12 = december
    pub fn month(&self) -> u8 {
        self.month
    }

    /// Get the day
    pub fn day(&self) -> u8 {
        self.day
    }

    /// Get the hour
    pub fn hour(&self) -> u8 {
        self.hour
    }

    /// Get the minute
    pub fn minute(&self) -> u8 {
        self.minute
    }

    /// Get the second
    pub fn second(&self) -> u8 {
        self.second
    }
}

pub const DEFAULT_VERSION: u8 = 46;

/// Structure representing a ZIP file.
#[derive(Debug, Clone)]
pub struct ZipFileData
{
    /// Compatibility of the file attribute information
    pub system: System,
    /// Specification version
    pub version_made_by: u8,
    /// True if the file is encrypted.
    pub encrypted: bool,
    /// Compression method used to store the file
    pub compression_method: ::compression::CompressionMethod,
    /// Last modified time. This will only have a 2 second precision.
    pub last_modified_time: DateTime,
    /// CRC32 checksum
    pub crc32: u32,
    /// Size of the file in the ZIP
    pub compressed_size: u64,
    /// Size of the file when extracted
    pub uncompressed_size: u64,
    /// Name of the file
    pub file_name: String,
    /// Raw file name. To be used when file_name was incorrectly decoded.
    pub file_name_raw: Vec<u8>,
    /// File comment
    pub file_comment: String,
    /// Specifies where the local header of the file starts
    pub header_start: u64,
    /// Specifies where the compressed data of the file starts
    pub data_start: u64,
    /// External file attributes
    pub external_attributes: u32,
}

impl ZipFileData {
    pub fn file_name_sanitized(&self) -> ::std::path::PathBuf {
        let no_null_filename = match self.file_name.find('\0') {
            Some(index) => &self.file_name[0..index],
            None => &self.file_name,
        }.to_string();

        // zip files can contain both / and \ as separators regardless of the OS
        // and as we want to return a sanitized PathBuf that only supports the
        // OS separator let's convert incompatible separators to compatible ones
        let separator = ::std::path::MAIN_SEPARATOR;
        let opposite_separator = match separator {
            '/' => '\\',
            '\\' | _ => '/',
        };
        let filename =
            no_null_filename.replace(&opposite_separator.to_string(), &separator.to_string());

        ::std::path::Path::new(&filename)
            .components()
            .filter(|component| match *component {
                ::std::path::Component::Normal(..) => true,
                _ => false,
            })
            .fold(::std::path::PathBuf::new(), |mut path, ref cur| {
                path.push(cur.as_os_str());
                path
            })
    }

    pub fn version_needed(&self) -> u16 {
        match self.compression_method {
            #[cfg(feature = "bzip2")]
            ::compression::CompressionMethod::Bzip2 => 46,
            _ => 20,
        }
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn system() {
        use super::System;
        assert_eq!(System::Dos as u16, 0u16);
        assert_eq!(System::Unix as u16, 3u16);
        assert_eq!(System::from_u8(0), System::Dos);
        assert_eq!(System::from_u8(3), System::Unix);
    }

    #[test]
    fn sanitize() {
        use super::*;
        let file_name = "/path/../../../../etc/./passwd\0/etc/shadow".to_string();
        let data = ZipFileData {
            system: System::Dos,
            version_made_by: 0,
            encrypted: false,
            compression_method: ::compression::CompressionMethod::Stored,
            last_modified_time: DateTime::default(),
            crc32: 0,
            compressed_size: 0,
            uncompressed_size: 0,
            file_name: file_name.clone(),
            file_name_raw: file_name.into_bytes(),
            file_comment: String::new(),
            header_start: 0,
            data_start: 0,
            external_attributes: 0,
        };
        assert_eq!(data.file_name_sanitized(), ::std::path::PathBuf::from("path/etc/passwd"));
    }

    #[test]
    fn datetime_default() {
        use super::DateTime;
        let dt = DateTime::default();
        assert_eq!(dt.timepart(), 0);
        assert_eq!(dt.datepart(), 0b0000000_0001_00001);
    }

    #[test]
    fn datetime_max() {
        use super::DateTime;
        let dt = DateTime::from_date_and_time(2107, 12, 31, 23, 59, 60).unwrap();
        assert_eq!(dt.timepart(), 0b10111_111011_11110);
        assert_eq!(dt.datepart(), 0b1111111_1100_11111);
    }

    #[test]
    fn datetime_bounds() {
        use super::DateTime;

        assert!(DateTime::from_date_and_time(2000, 1, 1, 23, 59, 60).is_ok());
        assert!(DateTime::from_date_and_time(2000, 1, 1, 24, 0, 0).is_err());
        assert!(DateTime::from_date_and_time(2000, 1, 1, 0, 60, 0).is_err());
        assert!(DateTime::from_date_and_time(2000, 1, 1, 0, 0, 61).is_err());

        assert!(DateTime::from_date_and_time(2107, 12, 31, 0, 0, 0).is_ok());
        assert!(DateTime::from_date_and_time(1980, 1, 1, 0, 0, 0).is_ok());
        assert!(DateTime::from_date_and_time(1979, 1, 1, 0, 0, 0).is_err());
        assert!(DateTime::from_date_and_time(1980, 0, 1, 0, 0, 0).is_err());
        assert!(DateTime::from_date_and_time(1980, 1, 0, 0, 0, 0).is_err());
        assert!(DateTime::from_date_and_time(2108, 12, 31, 0, 0, 0).is_err());
        assert!(DateTime::from_date_and_time(2107, 13, 31, 0, 0, 0).is_err());
        assert!(DateTime::from_date_and_time(2107, 12, 32, 0, 0, 0).is_err());
    }

    #[test]
    fn time_conversion() {
        use super::DateTime;
        let dt = DateTime::from_msdos(0x4D71, 0x54CF);
        assert_eq!(dt.year(), 2018);
        assert_eq!(dt.month(), 11);
        assert_eq!(dt.day(), 17);
        assert_eq!(dt.hour(), 10);
        assert_eq!(dt.minute(), 38);
        assert_eq!(dt.second(), 30);

        #[cfg(feature = "time")]
        assert_eq!(format!("{}", dt.to_time().rfc3339()), "2018-11-17T10:38:30Z");
    }

    #[test]
    fn time_out_of_bounds() {
        use super::DateTime;
        let dt = DateTime::from_msdos(0xFFFF, 0xFFFF);
        assert_eq!(dt.year(), 2107);
        assert_eq!(dt.month(), 15);
        assert_eq!(dt.day(), 31);
        assert_eq!(dt.hour(), 31);
        assert_eq!(dt.minute(), 63);
        assert_eq!(dt.second(), 62);

        #[cfg(feature = "time")]
        assert_eq!(format!("{}", dt.to_time().rfc3339()), "2107-15-31T31:63:62Z");

        let dt = DateTime::from_msdos(0x0000, 0x0000);
        assert_eq!(dt.year(), 1980);
        assert_eq!(dt.month(), 0);
        assert_eq!(dt.day(), 0);
        assert_eq!(dt.hour(), 0);
        assert_eq!(dt.minute(), 0);
        assert_eq!(dt.second(), 0);

        #[cfg(feature = "time")]
        assert_eq!(format!("{}", dt.to_time().rfc3339()), "1980-00-00T00:00:00Z");
    }
}
<|endoftext|>


<commit_before>//! Modules for events in the *m.key.verification* namespace.
//!
//! This module also contains types shared by events in its child namespaces.
//!
//! The MSC for the in-room variants of the `m.key.verification.*` events can be found
//! [here](https://github.com/matrix-org/matrix-doc/pull/2241).

#[cfg(feature = "unstable-pre-spec")]
use std::convert::TryFrom;

#[cfg(feature = "unstable-pre-spec")]
use ruma_identifiers::EventId;
use ruma_serde::StringEnum;
#[cfg(feature = "unstable-pre-spec")]
use serde::{Deserialize, Serialize};

#[cfg(feature = "unstable-pre-spec")]
use crate::room::relationships::{Reference, RelatesToJsonRepr, RelationJsonRepr};

pub mod accept;
pub mod cancel;
#[cfg(feature = "unstable-pre-spec")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
pub mod done;
pub mod key;
pub mod mac;
#[cfg(feature = "unstable-pre-spec")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
pub mod ready;
pub mod request;
pub mod start;

/// A hash algorithm.
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[ruma_enum(rename_all = "snake_case")]
pub enum HashAlgorithm {
    /// The SHA256 hash algorithm.
    Sha256,

    #[doc(hidden)]
    _Custom(String),
}

/// A key agreement protocol.
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[ruma_enum(rename_all = "kebab-case")]
pub enum KeyAgreementProtocol {
    /// The [Curve25519](https://cr.yp.to/ecdh.html) key agreement protocol.
    Curve25519,

    /// The Curve25519 key agreement protocol with check for public keys.
    Curve25519HkdfSha256,

    #[doc(hidden)]
    _Custom(String),
}

/// A message authentication code algorithm.
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[ruma_enum(rename_all = "kebab-case")]
pub enum MessageAuthenticationCode {
    /// The HKDF-HMAC-SHA256 MAC.
    HkdfHmacSha256,

    /// The HMAC-SHA256 MAC.
    HmacSha256,

    #[doc(hidden)]
    _Custom(String),
}

/// A Short Authentication String method.
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[ruma_enum(rename_all = "snake_case")]
pub enum ShortAuthenticationString {
    /// The decimal method.
    Decimal,

    /// The emoji method.
    Emoji,

    #[doc(hidden)]
    _Custom(String),
}

/// The relation that contains info which event the reaction is applying to.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg(feature = "unstable-pre-spec")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(try_from = "RelatesToJsonRepr", into = "RelatesToJsonRepr")]
pub struct Relation {
    /// The event that is being referenced.
    pub event_id: EventId,
}

#[cfg(feature = "unstable-pre-spec")]
impl Relation {
    /// Creates a new `Relation` with the given event ID.
    pub fn new(event_id: EventId) -> Self {
        Self { event_id }
    }
}

#[cfg(feature = "unstable-pre-spec")]
impl From<Relation> for RelatesToJsonRepr {
    fn from(relation: Relation) -> Self {
        RelatesToJsonRepr::Relation(RelationJsonRepr::Reference(Reference {
            event_id: relation.event_id,
        }))
    }
}

#[cfg(feature = "unstable-pre-spec")]
impl TryFrom<RelatesToJsonRepr> for Relation {
    type Error = &'static str;

    fn try_from(value: RelatesToJsonRepr) -> Result<Self, Self::Error> {
        if let RelatesToJsonRepr::Relation(RelationJsonRepr::Reference(r)) = value {
            Ok(Relation { event_id: r.event_id })
        } else {
            Err("Expected a relation with a rel_type of `reference`")
        }
    }
}

/// A Short Authentication String (SAS) verification method.
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
pub enum VerificationMethod {
    /// The *m.sas.v1* verification method.
    #[ruma_enum(rename = "m.sas.v1")]
    SasV1,

    /// The *m.qr_code.scan.v1* verification method.
    #[cfg(feature = "unstable-pre-spec")]
    #[ruma_enum(rename = "m.qr_code.scan.v1")]
    QrCodeScanV1,

    /// The *m.qr_code.show.v1* verification method.
    #[cfg(feature = "unstable-pre-spec")]
    #[ruma_enum(rename = "m.qr_code.show.v1")]
    QrCodeShowV1,

    /// The *m.reciprocate.v1* verification method.
    #[cfg(feature = "unstable-pre-spec")]
    #[ruma_enum(rename = "m.reciprocate.v1")]
    ReciprocateV1,

    #[doc(hidden)]
    _Custom(String),
}

#[cfg(test)]
mod tests {
    use serde_json::{from_value as from_json_value, json};

    use super::{KeyAgreementProtocol, MessageAuthenticationCode};

    #[test]
    fn serialize_key_agreement() {
        let serialized =
            serde_json::to_string(&KeyAgreementProtocol::Curve25519HkdfSha256).unwrap();
        assert_eq!(serialized, "\"curve25519-hkdf-sha256\"");

        let deserialized: KeyAgreementProtocol = serde_json::from_str(&serialized).unwrap();
        assert_eq!(deserialized, KeyAgreementProtocol::Curve25519HkdfSha256);
    }

    #[test]
    fn deserialize_mac_method() {
        let json = json!(["hkdf-hmac-sha256", "hmac-sha256"]);

        let deserialized: Vec<MessageAuthenticationCode> = from_json_value(json).unwrap();
        assert!(deserialized.contains(&MessageAuthenticationCode::HkdfHmacSha256));
    }

    #[test]
    fn serialize_mac_method() {
        let serialized = serde_json::to_string(&MessageAuthenticationCode::HkdfHmacSha256).unwrap();
        let deserialized: MessageAuthenticationCode = serde_json::from_str(&serialized).unwrap();
        assert_eq!(serialized, "\"hkdf-hmac-sha256\"");
        assert_eq!(deserialized, MessageAuthenticationCode::HkdfHmacSha256);

        let serialized = serde_json::to_string(&MessageAuthenticationCode::HmacSha256).unwrap();
        let deserialized: MessageAuthenticationCode = serde_json::from_str(&serialized).unwrap();
        assert_eq!(serialized, "\"hmac-sha256\"");
        assert_eq!(deserialized, MessageAuthenticationCode::HmacSha256);
    }
}
<commit_msg>events: Clean up verification relations<commit_after>//! Modules for events in the *m.key.verification* namespace.
//!
//! This module also contains types shared by events in its child namespaces.
//!
//! The MSC for the in-room variants of the `m.key.verification.*` events can be found
//! [here](https://github.com/matrix-org/matrix-doc/pull/2241).
#[cfg(feature = "unstable-pre-spec")]
use ruma_identifiers::EventId;
use ruma_serde::StringEnum;
#[cfg(feature = "unstable-pre-spec")]
use serde::{Deserialize, Serialize};

pub mod accept;
pub mod cancel;
#[cfg(feature = "unstable-pre-spec")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
pub mod done;
pub mod key;
pub mod mac;
#[cfg(feature = "unstable-pre-spec")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
pub mod ready;
pub mod request;
pub mod start;

/// A hash algorithm.
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[ruma_enum(rename_all = "snake_case")]
pub enum HashAlgorithm {
    /// The SHA256 hash algorithm.
    Sha256,

    #[doc(hidden)]
    _Custom(String),
}

/// A key agreement protocol.
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[ruma_enum(rename_all = "kebab-case")]
pub enum KeyAgreementProtocol {
    /// The [Curve25519](https://cr.yp.to/ecdh.html) key agreement protocol.
    Curve25519,

    /// The Curve25519 key agreement protocol with check for public keys.
    Curve25519HkdfSha256,

    #[doc(hidden)]
    _Custom(String),
}

/// A message authentication code algorithm.
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[ruma_enum(rename_all = "kebab-case")]
pub enum MessageAuthenticationCode {
    /// The HKDF-HMAC-SHA256 MAC.
    HkdfHmacSha256,

    /// The HMAC-SHA256 MAC.
    HmacSha256,

    #[doc(hidden)]
    _Custom(String),
}

/// A Short Authentication String method.
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[ruma_enum(rename_all = "snake_case")]
pub enum ShortAuthenticationString {
    /// The decimal method.
    Decimal,

    /// The emoji method.
    Emoji,

    #[doc(hidden)]
    _Custom(String),
}

/// A relation which associates an `m.key.verification.request` with another key verification event.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg(feature = "unstable-pre-spec")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "rel_type", rename = "m.reference")]
pub struct Relation {
    /// The event ID of a related `m.key.verification.request`.
    pub event_id: EventId,
}

#[cfg(feature = "unstable-pre-spec")]
impl Relation {
    /// Creates a new `Relation` with the given event ID.
    pub fn new(event_id: EventId) -> Self {
        Self { event_id }
    }
}

/// A Short Authentication String (SAS) verification method.
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
pub enum VerificationMethod {
    /// The *m.sas.v1* verification method.
    #[ruma_enum(rename = "m.sas.v1")]
    SasV1,

    /// The *m.qr_code.scan.v1* verification method.
    #[cfg(feature = "unstable-pre-spec")]
    #[ruma_enum(rename = "m.qr_code.scan.v1")]
    QrCodeScanV1,

    /// The *m.qr_code.show.v1* verification method.
    #[cfg(feature = "unstable-pre-spec")]
    #[ruma_enum(rename = "m.qr_code.show.v1")]
    QrCodeShowV1,

    /// The *m.reciprocate.v1* verification method.
    #[cfg(feature = "unstable-pre-spec")]
    #[ruma_enum(rename = "m.reciprocate.v1")]
    ReciprocateV1,

    #[doc(hidden)]
    _Custom(String),
}

#[cfg(test)]
mod tests {
    use serde_json::{from_value as from_json_value, json};

    use super::{KeyAgreementProtocol, MessageAuthenticationCode};

    #[test]
    fn serialize_key_agreement() {
        let serialized =
            serde_json::to_string(&KeyAgreementProtocol::Curve25519HkdfSha256).unwrap();
        assert_eq!(serialized, "\"curve25519-hkdf-sha256\"");

        let deserialized: KeyAgreementProtocol = serde_json::from_str(&serialized).unwrap();
        assert_eq!(deserialized, KeyAgreementProtocol::Curve25519HkdfSha256);
    }

    #[test]
    fn deserialize_mac_method() {
        let json = json!(["hkdf-hmac-sha256", "hmac-sha256"]);

        let deserialized: Vec<MessageAuthenticationCode> = from_json_value(json).unwrap();
        assert!(deserialized.contains(&MessageAuthenticationCode::HkdfHmacSha256));
    }

    #[test]
    fn serialize_mac_method() {
        let serialized = serde_json::to_string(&MessageAuthenticationCode::HkdfHmacSha256).unwrap();
        let deserialized: MessageAuthenticationCode = serde_json::from_str(&serialized).unwrap();
        assert_eq!(serialized, "\"hkdf-hmac-sha256\"");
        assert_eq!(deserialized, MessageAuthenticationCode::HkdfHmacSha256);

        let serialized = serde_json::to_string(&MessageAuthenticationCode::HmacSha256).unwrap();
        let deserialized: MessageAuthenticationCode = serde_json::from_str(&serialized).unwrap();
        assert_eq!(serialized, "\"hmac-sha256\"");
        assert_eq!(deserialized, MessageAuthenticationCode::HmacSha256);
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeSet;
use std::fs;
use std::path;
use crate::features::{collect_lang_features, collect_lib_features, Features, Status};

pub const PATH_STR: &str = "doc/unstable-book/src";

pub const COMPILER_FLAGS_DIR: &str = "compiler-flags";

pub const LANG_FEATURES_DIR: &str = "language-features";

pub const LIB_FEATURES_DIR: &str = "library-features";

/// Builds the path to the Unstable Book source directory from the Rust 'src' directory.
pub fn unstable_book_path(base_src_path: &path::Path) -> path::PathBuf {
    base_src_path.join(PATH_STR)
}

/// Builds the path to the directory where the features are documented within the Unstable Book
/// source directory.
pub fn unstable_book_lang_features_path(base_src_path: &path::Path) -> path::PathBuf {
    unstable_book_path(base_src_path).join(LANG_FEATURES_DIR)
}

/// Builds the path to the directory where the features are documented within the Unstable Book
/// source directory.
pub fn unstable_book_lib_features_path(base_src_path: &path::Path) -> path::PathBuf {
    unstable_book_path(base_src_path).join(LIB_FEATURES_DIR)
}

/// Tests whether `DirEntry` is a file.
fn dir_entry_is_file(dir_entry: &fs::DirEntry) -> bool {
    dir_entry
        .file_type()
        .expect("could not determine file type of directory entry")
        .is_file()
}

/// Retrieves names of all unstable features.
pub fn collect_unstable_feature_names(features: &Features) -> BTreeSet<String> {
    features
        .iter()
        .filter(|&(_, ref f)| f.level == Status::Unstable)
        .map(|(name, _)| name.replace('_', "-"))
        .collect()
}

pub fn collect_unstable_book_section_file_names(dir: &path::Path) -> BTreeSet<String> {
    fs::read_dir(dir)
        .expect("could not read directory")
        .map(|entry| entry.expect("could not read directory entry"))
        .filter(dir_entry_is_file)
        .map(|entry| entry.path())
        .filter(|path| path.extension().map(|e| e.to_str().unwrap()) == Some("md"))
        .map(|path| path.file_stem().unwrap().to_str().unwrap().into())
        .collect()
}

/// Retrieves file names of all library feature sections in the Unstable Book with:
///
/// * hyphens replaced by underscores,
/// * the markdown suffix ('.md') removed.
fn collect_unstable_book_lang_features_section_file_names(base_src_path: &path::Path)
                                                          -> BTreeSet<String> {
    collect_unstable_book_section_file_names(&unstable_book_lang_features_path(base_src_path))
}

/// Retrieves file names of all language feature sections in the Unstable Book with:
///
/// * hyphens replaced by underscores,
/// * the markdown suffix ('.md') removed.
fn collect_unstable_book_lib_features_section_file_names(base_src_path: &path::Path)
                                                         -> BTreeSet<String> {
    collect_unstable_book_section_file_names(&unstable_book_lib_features_path(base_src_path))
}

pub fn check(path: &path::Path, bad: &mut bool) {
    // Library features

    let lang_features = collect_lang_features(path, bad);
    let lib_features = collect_lib_features(path).into_iter().filter(|&(ref name, _)| {
        !lang_features.contains_key(name)
    }).collect();

    let unstable_lib_feature_names = collect_unstable_feature_names(&lib_features);
    let unstable_book_lib_features_section_file_names =
        collect_unstable_book_lib_features_section_file_names(path);

    // Check for Unstable Book sections that don't have a corresponding unstable feature
    for feature_name in &unstable_book_lib_features_section_file_names -
                        &unstable_lib_feature_names {
        tidy_error!(bad,
                    "The Unstable Book has a 'library feature' section '{}' which doesn't \
                     correspond to an unstable library feature",
                    feature_name)
    }

    // Language features

    let unstable_lang_feature_names = collect_unstable_feature_names(&lang_features);
    let unstable_book_lang_features_section_file_names =
        collect_unstable_book_lang_features_section_file_names(path);

    // Check for Unstable Book sections that don't have a corresponding unstable feature.
    for feature_name in &unstable_book_lang_features_section_file_names -
                        &unstable_lang_feature_names {
        tidy_error!(bad,
                    "The Unstable Book has a 'language feature' section '{}' which doesn't \
                     correspond to an unstable language feature",
                    feature_name)
    }

    // List unstable features that don't have Unstable Book sections.
    // Remove the comment marker if you want the list printed.
    /*
    println!("Lib features without unstable book sections:");
    for feature_name in &unstable_lang_feature_names -
                        &unstable_book_lang_features_section_file_names {
        println!("    * {} {:?}", feature_name, lib_features[&feature_name].tracking_issue);
    }

    println!("Lang features without unstable book sections:");
    for feature_name in &unstable_lib_feature_names-
                        &unstable_book_lib_features_section_file_names {
        println!("    * {} {:?}", feature_name, lang_features[&feature_name].tracking_issue);
    }
    // */
}
<commit_msg>Fix tidy check for language and library features<commit_after>use std::collections::BTreeSet;
use std::fs;
use std::path;
use crate::features::{collect_lang_features, collect_lib_features, Features, Status};

pub const PATH_STR: &str = "doc/unstable-book/src";

pub const COMPILER_FLAGS_DIR: &str = "compiler-flags";

pub const LANG_FEATURES_DIR: &str = "language-features";

pub const LIB_FEATURES_DIR: &str = "library-features";

/// Builds the path to the Unstable Book source directory from the Rust 'src' directory.
pub fn unstable_book_path(base_src_path: &path::Path) -> path::PathBuf {
    base_src_path.join(PATH_STR)
}

/// Builds the path to the directory where the features are documented within the Unstable Book
/// source directory.
pub fn unstable_book_lang_features_path(base_src_path: &path::Path) -> path::PathBuf {
    unstable_book_path(base_src_path).join(LANG_FEATURES_DIR)
}

/// Builds the path to the directory where the features are documented within the Unstable Book
/// source directory.
pub fn unstable_book_lib_features_path(base_src_path: &path::Path) -> path::PathBuf {
    unstable_book_path(base_src_path).join(LIB_FEATURES_DIR)
}

/// Tests whether `DirEntry` is a file.
fn dir_entry_is_file(dir_entry: &fs::DirEntry) -> bool {
    dir_entry
        .file_type()
        .expect("could not determine file type of directory entry")
        .is_file()
}

/// Retrieves names of all unstable features.
pub fn collect_unstable_feature_names(features: &Features) -> BTreeSet<String> {
    features
        .iter()
        .filter(|&(_, ref f)| f.level == Status::Unstable)
        .map(|(name, _)| name.replace('_', "-"))
        .collect()
}

pub fn collect_unstable_book_section_file_names(dir: &path::Path) -> BTreeSet<String> {
    fs::read_dir(dir)
        .expect("could not read directory")
        .map(|entry| entry.expect("could not read directory entry"))
        .filter(dir_entry_is_file)
        .map(|entry| entry.path())
        .filter(|path| path.extension().map(|e| e.to_str().unwrap()) == Some("md"))
        .map(|path| path.file_stem().unwrap().to_str().unwrap().into())
        .collect()
}

/// Retrieves file names of all library feature sections in the Unstable Book with:
///
/// * hyphens replaced by underscores,
/// * the markdown suffix ('.md') removed.
fn collect_unstable_book_lang_features_section_file_names(base_src_path: &path::Path)
                                                          -> BTreeSet<String> {
    collect_unstable_book_section_file_names(&unstable_book_lang_features_path(base_src_path))
}

/// Retrieves file names of all language feature sections in the Unstable Book with:
///
/// * hyphens replaced by underscores,
/// * the markdown suffix ('.md') removed.
fn collect_unstable_book_lib_features_section_file_names(base_src_path: &path::Path)
                                                         -> BTreeSet<String> {
    collect_unstable_book_section_file_names(&unstable_book_lib_features_path(base_src_path))
}

pub fn check(path: &path::Path, bad: &mut bool) {
    // Library features

    let lang_features = collect_lang_features(path, bad);
    let lib_features = collect_lib_features(path).into_iter().filter(|&(ref name, _)| {
        !lang_features.contains_key(name)
    }).collect();

    // Library features
    let unstable_lib_feature_names = collect_unstable_feature_names(&lib_features);
    let unstable_book_lib_features_section_file_names =
        collect_unstable_book_lib_features_section_file_names(path);

    // Language features
    let unstable_lang_feature_names = collect_unstable_feature_names(&lang_features);
    let unstable_book_lang_features_section_file_names =
        collect_unstable_book_lang_features_section_file_names(path);

    // Check for Unstable Book sections that don't have a corresponding unstable feature
    for feature_name in &unstable_book_lib_features_section_file_names -
                        &unstable_lib_feature_names {
        if !unstable_lang_feature_names.contains(&feature_name) {
            tidy_error!(bad,
                        "The Unstable Book has a 'library feature' section '{}' which doesn't \
                         correspond to an unstable library feature",
                        feature_name);
        }
    }

    // Check for Unstable Book sections that don't have a corresponding unstable feature.
    for feature_name in &unstable_book_lang_features_section_file_names -
                        &unstable_lang_feature_names {
        tidy_error!(bad,
                    "The Unstable Book has a 'language feature' section '{}' which doesn't \
                     correspond to an unstable language feature",
                    feature_name)
    }

    // List unstable features that don't have Unstable Book sections.
    // Remove the comment marker if you want the list printed.
    /*
    println!("Lib features without unstable book sections:");
    for feature_name in &unstable_lang_feature_names -
                        &unstable_book_lang_features_section_file_names {
        println!("    * {} {:?}", feature_name, lib_features[&feature_name].tracking_issue);
    }

    println!("Lang features without unstable book sections:");
    for feature_name in &unstable_lib_feature_names-
                        &unstable_book_lib_features_section_file_names {
        println!("    * {} {:?}", feature_name, lang_features[&feature_name].tracking_issue);
    }
    // */
}
<|endoftext|>


<commit_before>extern crate sdl2;
use ::subtitles::Color;
use ::sdl2::pixels::Color as SdlColor;
use std::cmp::{max, min};

/// will always return a flat color regardless or alpha
pub fn mix_colors(color1: SdlColor, color2: SdlColor, mix_ratio: f32) -> SdlColor {
    let (r1, g1, b1) = color1.rgb();
    let (r2, g2, b2) = color2.rgb();
    let (r1, g1, b1) = (r1 as i16, g1 as i16, b1 as i16);
    let (r2, g2, b2) = (r2 as i16, g2 as i16, b2 as i16);
    let (r, g, b): (i16, i16, i16) = (((r2 - r1) as f32 * mix_ratio) as i16 + r1,
                                      ((g2 - g1) as f32 * mix_ratio) as i16 + g1,
                                      ((b2 - b1) as f32 * mix_ratio) as i16 + b1);

    let (r, g, b) = (max(min(r, 0xFF), 0) as u8,
                     max(min(g, 0xFF), 0) as u8,
                     max(min(b, 0xFF), 0) as u8);
    SdlColor::RGB(r, g, b)
}

pub fn fade_color(color1: SdlColor, fade_ratio: f32) -> SdlColor {
    let (r, g, b, a): (u8, u8, u8, u8) = match color1 {
        SdlColor::RGB(r, g, b) => (r, g, b, 255),
        SdlColor::RGBA(r, g, b, a) => (r, g, b, a),
    };
    SdlColor::RGBA(r, g, b, (a as f32 * fade_ratio) as u8)
}

pub fn parse_hex(hex:&str) -> Result<u32,String> {
    let mut parsed : u32 = 0 ;
    for character in hex.chars() {
        let char_value : u32 =
            try!(
                character.to_digit(16).ok_or(
                    String::from("failed to parse hexadecimal character")
                )
            );
        parsed = parsed * 0x10 + char_value;
    };
    Ok(parsed)
}

pub fn parse_bgr(bgr : &str) -> Result<Color,String> {
    let bgr = bgr.trim();
    if bgr.len() != 6 {
        Err(String::from("Invalid BGR format"))
    } else {
        let (blue,greenred) = bgr.split_at(2);
        let (green,red) = greenred.split_at(2);
        let blue = try!(parse_hex(blue)) as u8 ;
        let green = try!(parse_hex(green)) as u8 ;
        let red = try!(parse_hex(red)) as u8 ;
        Ok(Color {
            red:red,
            green:green,
            blue:blue
        })
    }
}

#[test]
fn test_bgr(){
    let sample_bgr = "FF0000";
    assert_eq!(parse_bgr(sample_bgr).unwrap(),Color::RGB(0,0,255));
}

#[test]
fn test_parse_hex(){
    let sample_hex = "201";
    assert_eq!(parse_hex(sample_hex).unwrap(),513);
}
<commit_msg>Added utility fn to browse dir recusrively<commit_after>extern crate sdl2;
use ::subtitles::Color;
use ::sdl2::pixels::Color as SdlColor;
use std::cmp::{max, min};

use std::path::{Path,PathBuf};
use std::{io,fs};

/// will always return a flat color regardless or alpha
pub fn mix_colors(color1: SdlColor, color2: SdlColor, mix_ratio: f32) -> SdlColor {
    let (r1, g1, b1) = color1.rgb();
    let (r2, g2, b2) = color2.rgb();
    let (r1, g1, b1) = (r1 as i16, g1 as i16, b1 as i16);
    let (r2, g2, b2) = (r2 as i16, g2 as i16, b2 as i16);
    let (r, g, b): (i16, i16, i16) = (((r2 - r1) as f32 * mix_ratio) as i16 + r1,
                                      ((g2 - g1) as f32 * mix_ratio) as i16 + g1,
                                      ((b2 - b1) as f32 * mix_ratio) as i16 + b1);

    let (r, g, b) = (max(min(r, 0xFF), 0) as u8,
                     max(min(g, 0xFF), 0) as u8,
                     max(min(b, 0xFF), 0) as u8);
    SdlColor::RGB(r, g, b)
}

pub fn fade_color(color1: SdlColor, fade_ratio: f32) -> SdlColor {
    let (r, g, b, a): (u8, u8, u8, u8) = match color1 {
        SdlColor::RGB(r, g, b) => (r, g, b, 255),
        SdlColor::RGBA(r, g, b, a) => (r, g, b, a),
    };
    SdlColor::RGBA(r, g, b, (a as f32 * fade_ratio) as u8)
}

pub fn parse_hex(hex:&str) -> Result<u32,String> {
    let mut parsed : u32 = 0 ;
    for character in hex.chars() {
        let char_value : u32 =
            try!(
                character.to_digit(16).ok_or(
                    String::from("failed to parse hexadecimal character")
                )
            );
        parsed = parsed * 0x10 + char_value;
    };
    Ok(parsed)
}

pub fn parse_bgr(bgr : &str) -> Result<Color,String> {
    let bgr = bgr.trim();
    if bgr.len() != 6 {
        Err(String::from("Invalid BGR format"))
    } else {
        let (blue,greenred) = bgr.split_at(2);
        let (green,red) = greenred.split_at(2);
        let blue = try!(parse_hex(blue)) as u8 ;
        let green = try!(parse_hex(green)) as u8 ;
        let red = try!(parse_hex(red)) as u8 ;
        Ok(Color {
            red:red,
            green:green,
            blue:blue
        })
    }
}

pub fn for_each_in_dir<P:AsRef<Path>,F:Fn(&Path)->bool>(directory:P,recursion_level:u32,filter:F)
     -> (Vec<PathBuf>,Vec<io::Error>) {
    if (recursion_level == 0) {
        return (vec!(),vec!());
    }
    let mut vec_path : Vec<PathBuf> = Vec::new();
    let mut vec_error : Vec<io::Error> = Vec::new();
    let paths = match fs::read_dir(directory) {
        Ok(paths) => paths,
        Err(e) => {
            return (vec!(),vec!(e));
            unreachable!()
        }
    };
    for path in paths {
        match path {
            Ok(path) => {
                let filetype = path.file_type();
                match filetype {
                    Ok(finfo) => {
                        let pathbuf = path.path();
                        if finfo.is_dir() {
                            let (v_p,v_e) =
                                for_each_in_dir(&pathbuf,recursion_level - 1,&filter);
                            vec_path.extend(v_p);
                            vec_error.extend(v_e);
                        } else if filter(&pathbuf) {
                            vec_path.push(pathbuf);
                        }
                    },
                    Err(e) => {
                        vec_error.push(e);
                    }
                }
            },
            Err(e) => {
                vec_error.push(e);
            }
        }
    };
    (vec_path,vec_error)
}

#[test]
fn test_bgr(){
    let sample_bgr = "FF0000";
    assert_eq!(parse_bgr(sample_bgr).unwrap(),Color::RGB(0,0,255));
}

#[test]
fn test_parse_hex(){
    let sample_hex = "201";
    assert_eq!(parse_hex(sample_hex).unwrap(),513);
}
<|endoftext|>


<commit_before>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Common utilities.

use std::cmp;
use num::Float;

/// Remove a trailing newline from the given string in place.
pub fn trim_newline(s: &mut String) {
    if s.ends_with('\n') {
        s.pop();
    }
}

/// In place implementation of scan over a slice.
pub fn scan<T: Copy, F: Fn(T, T) -> T>(a: &mut [T], op: F) {
    let mut s = a[0];
    for v in a.iter_mut().skip(1) {
        s = op(s, *v);
        *v = s;
    }
}

// Inplace implementation of prescan over a slice.
pub fn prescan<T: Copy, F: Fn(T, T) -> T>(a: &mut [T], neutral: T, op: F) {
    let mut s = neutral;
    for v in a.iter_mut() {
        let t = *v;
        *v = s;
        s = op(s, t);
    }
}

#[derive(PartialOrd, PartialEq, Debug, Copy, Clone)]
pub struct NonNaNFloat<F: Float>(F);

impl<F: Float> NonNaNFloat<F> {
    pub fn new(v: F) -> Option<Self> {
        if v.is_nan() {
            Some(NonNaNFloat(v))
        } else {
            None
        }
    }

    pub fn unwrap(&self) -> F {
        let &NonNaNFloat(v) = self;
        v
    }
}

impl<F: Float> Eq for NonNaNFloat<F> {}

impl<F: Float> Ord for NonNaNFloat<F> {
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        self.partial_cmp(other).unwrap()
    }
}

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

    #[test]
    fn test_scan() {
        let mut a = vec![1, 0, 0, 1];
        scan(&mut a[..], |a, b| a + b);
        assert_eq!(a, vec![1, 1, 1, 2]);
    }

    #[test]
    fn test_prescan() {
        let mut a = vec![1, 0, 0, 1];
        prescan(&mut a[..], 0, |a, b| a + b);
        assert_eq!(a, vec![0, 1, 1, 1]);
    }

    #[test]
    fn test_nonnanfloat() {
        let mut v = [NonNaNFloat(5.1), NonNaNFloat(1.3)];
        v.sort();
        assert_eq!(v, [NonNaNFloat(1.3), NonNaNFloat(5.1)]);
    }
}
<commit_msg>Add type aliases for simplified dealing with sequences.<commit_after>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Common utilities.

use std::cmp;
use num::Float;

/// Type alias for an owned sequence.
pub type Sequence = Vec<u8>;
/// Type alias for a sequence slice.
pub type SequenceSlice<'a> = &'a [u8];

/// Type alias for an iterator over a sequence.
pub trait SequenceIterator<'a>: Iterator<Item=&'a u8> {}
impl<'a, I: Iterator<Item=&'a u8>> SequenceIterator<'a> for I {}

/// Type alias for a type that can be coerced into a ``SequenceIterator``.
pub trait IntoSequenceIterator<'a>: IntoIterator<Item=&'a u8> {}
impl<'a, T: IntoIterator<Item=&'a u8>> IntoSequenceIterator<'a> for T {}

/// Remove a trailing newline from the given string in place.
pub fn trim_newline(s: &mut String) {
    if s.ends_with('\n') {
        s.pop();
    }
}

/// In place implementation of scan over a slice.
pub fn scan<T: Copy, F: Fn(T, T) -> T>(a: &mut [T], op: F) {
    let mut s = a[0];
    for v in a.iter_mut().skip(1) {
        s = op(s, *v);
        *v = s;
    }
}

// Inplace implementation of prescan over a slice.
pub fn prescan<T: Copy, F: Fn(T, T) -> T>(a: &mut [T], neutral: T, op: F) {
    let mut s = neutral;
    for v in a.iter_mut() {
        let t = *v;
        *v = s;
        s = op(s, t);
    }
}

#[derive(PartialOrd, PartialEq, Debug, Copy, Clone)]
pub struct NonNaNFloat<F: Float>(F);

impl<F: Float> NonNaNFloat<F> {
    pub fn new(v: F) -> Option<Self> {
        if v.is_nan() {
            Some(NonNaNFloat(v))
        } else {
            None
        }
    }

    pub fn unwrap(&self) -> F {
        let &NonNaNFloat(v) = self;
        v
    }
}

impl<F: Float> Eq for NonNaNFloat<F> {}

impl<F: Float> Ord for NonNaNFloat<F> {
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        self.partial_cmp(other).unwrap()
    }
}

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

    #[test]
    fn test_scan() {
        let mut a = vec![1, 0, 0, 1];
        scan(&mut a[..], |a, b| a + b);
        assert_eq!(a, vec![1, 1, 1, 2]);
    }

    #[test]
    fn test_prescan() {
        let mut a = vec![1, 0, 0, 1];
        prescan(&mut a[..], 0, |a, b| a + b);
        assert_eq!(a, vec![0, 1, 1, 1]);
    }

    #[test]
    fn test_nonnanfloat() {
        let mut v = [NonNaNFloat(5.1), NonNaNFloat(1.3)];
        v.sort();
        assert_eq!(v, [NonNaNFloat(1.3), NonNaNFloat(5.1)]);
    }

    /// This function demonstrates the use of the IntoSequenceIterator alias, which takes both
    /// slices and iterators.
    fn print_sequence<'a, I: IntoSequenceIterator<'a>>(sequence: I) {
        for c in sequence {
            println!("{}", c);
        }
    }

    #[test]
    fn test_print_sequence() {
        let s = b"ACGT";
        print_sequence(&s);
    }
}
<|endoftext|>


<commit_before>#[derive(Clone, Debug, PartialEq)]
pub enum Integer {
    /// Every non-negative integer is treated as u64, even if it fits in i64.
    U64(u64),
    /// Every negative integer is treated as i64.
    I64(i64),
}

#[derive(Clone, Debug, PartialEq)]
pub enum Float {
    F32(f32),
    F64(f64),
}

#[derive(Clone, Debug, PartialEq)]
pub enum Value {
    /// Nil represents nil.
    Nil,
    /// Boolean represents true or false.
    Boolean(bool),
    /// Integer represents an integer.
    Integer(Integer),
    /// Float represents a floating point number.
    Float(Float),
    /// String extending Raw type represents a UTF-8 string.
    String(String),
    /// Binary extending Raw type represents a byte array.
    Binary(Vec<u8>),
    /// Array represents a sequence of objects.
    Array(Vec<Value>),
    /// Map represents key-value pairs of objects.
    Map(Vec<(Value, Value)>),
    /// Extended implements Extension interface: represents a tuple of type information and a byte
    /// array where type information is an integer whose meaning is defined by applications.
    Ext(i8, Vec<u8>),
}
<commit_msg>[Value] ValueRef prototype.<commit_after>#[derive(Clone, Debug, PartialEq)]
pub enum Integer {
    /// Every non-negative integer is treated as u64, even if it fits in i64.
    U64(u64),
    /// Every negative integer is treated as i64.
    I64(i64),
}

#[derive(Clone, Debug, PartialEq)]
pub enum Float {
    F32(f32),
    F64(f64),
}

#[derive(Clone, Debug, PartialEq)]
pub enum Value {
    /// Nil represents nil.
    Nil,
    /// Boolean represents true or false.
    Boolean(bool),
    /// Integer represents an integer.
    Integer(Integer),
    /// Float represents a floating point number.
    Float(Float),
    /// String extending Raw type represents a UTF-8 string.
    String(String),
    /// Binary extending Raw type represents a byte array.
    Binary(Vec<u8>),
    /// Array represents a sequence of objects.
    Array(Vec<Value>),
    /// Map represents key-value pairs of objects.
    Map(Vec<(Value, Value)>),
    /// Extended implements Extension interface: represents a tuple of type information and a byte
    /// array where type information is an integer whose meaning is defined by applications.
    Ext(i8, Vec<u8>),
}

#[derive(Clone, Debug, PartialEq)]
pub enum ValueRef<'a> {
    /// Nil represents nil.
    Nil,
    /// Boolean represents true or false.
    Boolean(bool),
    /// Integer represents an integer.
    Integer(Integer),
    /// Float represents a floating point number.
    Float(Float),
    /// String extending Raw type represents a UTF-8 string.
    String(&'a str),
    /// Binary extending Raw type represents a byte array.
    Binary(&'a [u8]),
    /// Array represents a sequence of objects.
    Array(&'a [ValueRef<'a>]),
    /// Map represents key-value pairs of objects.
    Map(&'a [(ValueRef<'a>, ValueRef<'a>)]),
    /// Extended implements Extension interface: represents a tuple of type information and a byte
    /// array where type information is an integer whose meaning is defined by applications.
    Ext(i8, &'a [u8]),
}
<|endoftext|>


<commit_before>
use ::TryInto;

use std::fmt;

/// Parses a String into a Value, first attempting bool, i64, and f64.
///
/// Examples:
/// ```
/// match parse_into_value("32.3") {
///     Value::Float(f) => println!("value is float: {}", f),
///     _ => panic!("it's broke yo"),
/// }
///
/// match parse_into_value("something silly") {
///     Value::String(s) => println!("none of the above: {}", s),
///     _ => panic!("it's really broke yo")
/// }
/// ```
pub fn parse_into_value(into: String) -> Value {
    match into.parse::<bool>() {
        Ok(b) => return Value::Bool(b),
        Err(_) => {},
    }

    match into.parse::<i64>() {
        Ok(i) => return Value::Integer(i),
        Err(_) => {},
    }

    match into.parse::<f64>() {
        Ok(f) => return Value::Float(f),
        Err(_) => {},
    }

    Value::String(into)
}

#[derive(Debug, PartialEq, Clone)]
/// Wrapper type for possible types in nccl configuration.
pub enum Value {
    String(String),
    Bool(bool),
    Integer(i64),
    Float(f64),
}

impl Value {
    fn into_string(self) -> Result<String, ()> {
        match self {
            Value::String(s) => Ok(s),
            _ => Err(())
        }
    }

    fn into_bool(self) -> Result<bool, ()> {
        match self {
            Value::Bool(b) => Ok(b),
            _ => Err(())
        }
    }

    fn into_integer(self) -> Result<i64, ()> {
        match self {
            Value::Integer(i) => Ok(i),
            _ => Err(())
        }
    }

    fn into_float(self) -> Result<f64, ()> {
        match self {
            Value::Float(f) => Ok(f),
            _ => Err(())
        }
    }
}

impl TryInto<String> for Value {
    type Error = ();
    fn try_into(self) -> Result<String, Self::Error> {
        self.into_string()
    }
}

impl TryInto<bool> for Value {
    type Error = ();
    fn try_into(self) -> Result<bool, Self::Error> {
        self.into_bool()
    }
}

impl TryInto<i64> for Value {
    type Error = ();
    fn try_into(self) -> Result<i64, Self::Error> {
        self.into_integer()
    }
}

impl TryInto<f64> for Value {
    type Error = ();
    fn try_into(self) -> Result<f64, Self::Error> {
        self.into_float()
    }
}

impl<'a> From<&'a Value> for Value {
    fn from(v: &'a Value) -> Self {
        v.clone()
    }
}

impl From<String> for Value {
    fn from(s: String) -> Self {
        Value::String(s)
    }
}

impl<'a> From<&'a String> for Value {
    fn from(s: &'a String) -> Self {
        Value::String(s.to_owned())
    }
}

impl<'a> From<&'a str> for Value {
    fn from(s: &'a str) -> Self {
        Value::String(s.to_owned())
    }
}

impl From<bool> for Value {
    fn from(b: bool) -> Self {
        Value::Bool(b)
    }
}

impl From<i64> for Value {
    fn from(i: i64) -> Self {
        Value::Integer(i)
    }
}

impl From<f64> for Value {
    fn from(f: f64) -> Self {
        Value::Float(f)
    }
}

impl Into<String> for Value {
    fn into(self) -> String {
        self.into_string().unwrap()
    }
}

impl Into<bool> for Value {
    fn into(self) -> bool {
        self.into_bool().unwrap()
    }
}

impl Into<i64> for Value {
    fn into(self) -> i64 {
        self.into_integer().unwrap()
    }
}

impl Into<f64> for Value {
    fn into(self) -> f64 {
        self.into_float().unwrap()
    }
}

impl fmt::Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Value::Bool(b) => write!(f, "{}", b),
            &Value::String(ref s) => write!(f, "{}", s),
            &Value::Float(fl) => write!(f, "{}", fl),
            &Value::Integer(i) => write!(f, "{}", i),
        }
    }
}

<commit_msg>make docs look better<commit_after>
use ::TryInto;

use std::fmt;

/// Parses a String into a Value, first attempting bool, i64, and f64.
///
/// Examples:
///
/// ```
/// match parse_into_value("32.3") {
///     Value::Float(f) => println!("value is float: {}", f),
///     _ => panic!("it's broke yo"),
/// }
///
/// match parse_into_value("something silly") {
///     Value::String(s) => println!("none of the above: {}", s),
///     _ => panic!("it's really broke yo")
/// }
/// ```
pub fn parse_into_value(into: String) -> Value {
    match into.parse::<bool>() {
        Ok(b) => return Value::Bool(b),
        Err(_) => {},
    }

    match into.parse::<i64>() {
        Ok(i) => return Value::Integer(i),
        Err(_) => {},
    }

    match into.parse::<f64>() {
        Ok(f) => return Value::Float(f),
        Err(_) => {},
    }

    Value::String(into)
}

#[derive(Debug, PartialEq, Clone)]
/// Wrapper type for possible types in nccl configuration.
pub enum Value {
    String(String),
    Bool(bool),
    Integer(i64),
    Float(f64),
}

impl Value {
    fn into_string(self) -> Result<String, ()> {
        match self {
            Value::String(s) => Ok(s),
            _ => Err(())
        }
    }

    fn into_bool(self) -> Result<bool, ()> {
        match self {
            Value::Bool(b) => Ok(b),
            _ => Err(())
        }
    }

    fn into_integer(self) -> Result<i64, ()> {
        match self {
            Value::Integer(i) => Ok(i),
            _ => Err(())
        }
    }

    fn into_float(self) -> Result<f64, ()> {
        match self {
            Value::Float(f) => Ok(f),
            _ => Err(())
        }
    }
}

impl TryInto<String> for Value {
    type Error = ();
    fn try_into(self) -> Result<String, Self::Error> {
        self.into_string()
    }
}

impl TryInto<bool> for Value {
    type Error = ();
    fn try_into(self) -> Result<bool, Self::Error> {
        self.into_bool()
    }
}

impl TryInto<i64> for Value {
    type Error = ();
    fn try_into(self) -> Result<i64, Self::Error> {
        self.into_integer()
    }
}

impl TryInto<f64> for Value {
    type Error = ();
    fn try_into(self) -> Result<f64, Self::Error> {
        self.into_float()
    }
}

impl<'a> From<&'a Value> for Value {
    fn from(v: &'a Value) -> Self {
        v.clone()
    }
}

impl From<String> for Value {
    fn from(s: String) -> Self {
        Value::String(s)
    }
}

impl<'a> From<&'a String> for Value {
    fn from(s: &'a String) -> Self {
        Value::String(s.to_owned())
    }
}

impl<'a> From<&'a str> for Value {
    fn from(s: &'a str) -> Self {
        Value::String(s.to_owned())
    }
}

impl From<bool> for Value {
    fn from(b: bool) -> Self {
        Value::Bool(b)
    }
}

impl From<i64> for Value {
    fn from(i: i64) -> Self {
        Value::Integer(i)
    }
}

impl From<f64> for Value {
    fn from(f: f64) -> Self {
        Value::Float(f)
    }
}

impl Into<String> for Value {
    fn into(self) -> String {
        self.into_string().unwrap()
    }
}

impl Into<bool> for Value {
    fn into(self) -> bool {
        self.into_bool().unwrap()
    }
}

impl Into<i64> for Value {
    fn into(self) -> i64 {
        self.into_integer().unwrap()
    }
}

impl Into<f64> for Value {
    fn into(self) -> f64 {
        self.into_float().unwrap()
    }
}

impl fmt::Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Value::Bool(b) => write!(f, "{}", b),
            &Value::String(ref s) => write!(f, "{}", s),
            &Value::Float(fl) => write!(f, "{}", fl),
            &Value::Integer(i) => write!(f, "{}", i),
        }
    }
}

<|endoftext|>