<commit_before>/*
 * Copyright (c) 2017-2019 Boucher, Antoni <bouanto@zoho.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.
 */

/// Connect events to sending a message.
///
/// ## Rules
/// 1. Send `$msg` to `$other_component` when the GTK+ `$event` is emitted on `$widget`.
///
/// 2. Optionally send `$msg.0` when the GTK+ `$event` is emitted on `$widget`.
/// Return `$msg.1` in the GTK+ callback.
/// This variant gives more control to the caller since it expects a `$msg` returning `(Option<MSG>,
/// ReturnValue)` where the `ReturnValue` is the value to return in the GTK+ callback.
/// Option<MSG> can be None if no message needs to be emitted.
///
/// 3. Send `$msg` when the GTK+ `$event` is emitted on `$widget`.
///
/// 4. Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect {
    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_component:expr, $msg:expr) => {
        connect_stream!($widget, $event($($args),*), $other_component.stream(), $msg);
    };

    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), return $msg:expr) => {{
        connect_stream!(return $relm.stream(), $widget, $event($($args),*), $msg);
    }};

    // Connect to a GTK+ widget event.
    ($relm:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $relm.stream().clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    }};

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_component:ident @ $message:pat, $dst_component:expr, $msg:expr) => {
        let stream = $src_component.stream().clone();
        connect_stream!(stream@$message, $dst_component.stream(), $msg);
    };
}

/// Connect events to sending a message.
/// Similar to `connect!` but wants a stream instead of a component.
///
/// ## Rules
/// 1. Send `$msg` to `$other_stream` when the GTK+ `$event` is emitted on `$widget`.
///
/// 2. Send `$msg` to `$widget` when the `$message` is received on `$stream`.
#[macro_export]
macro_rules! connect_stream {
    // Connect to a GTK+ widget event.
    // This variant gives more control to the caller since it expects a `$msg` returning (Option<MSG>,
    // ReturnValue) where the ReturnValue is the value to return in the GTK+ callback.
    // Option<MSG> can be None if no message needs to be emitted.
    (return $stream:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
        let stream = $stream.clone();
        let _ = $widget.$event(move |$($args),*| {
            let (msg, return_value) = $crate::IntoPair::into_pair($msg);
            let msg: Option<_> = $crate::IntoOption::into_option(msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
            return_value
        });
    }};

    // Connect to a GTK+ widget event, sending a message to another widget.
    ($widget:expr, $event:ident($($args:pat),*), $other_stream:expr, $msg:expr) => {
        let stream = $other_stream.clone();
        let _ = $widget.$event(move |$($args),*| {
            let msg: Option<_> = $crate::IntoOption::into_option($msg);
            if let Some(msg) = msg {
                stream.emit(msg);
            }
        });
    };

    // Connect to a message reception.
    // TODO: create another macro rule accepting multiple patterns.
    ($src_stream:ident @ $message:pat, $dst_stream:expr, $msg:expr) => {
        let stream = $dst_stream.clone();
        $src_stream.observe(move |msg| {
            #[allow(unreachable_patterns)]
            match msg {
                &$message =>  {
                    let msg: Option<_> = $crate::IntoOption::into_option($msg);
                    if let Some(msg) = msg {
                        stream.emit(msg);
                    }
                },
                _ => (),
            }
        });
    };
}

/// Connect an asynchronous method call to send a message.
/// The variants with `$fail_msg` will send this message when there's an error.
/// Those without this argument will ignore the error.
#[macro_export]
macro_rules! connect_async {
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr) => {
        connect_async!($object, $async_method(), $relm, $msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        // TODO: remove any use of Fragile when gio callbacks stop requiring Send.
        let stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* None, move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
    }};
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async!($object, $async_method(), $relm, $msg, $fail_msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        let fail_event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* None, move |result| {
            match result {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });
    }};
}

/// Connect an asynchronous function call to send a message.
/// The variants with `$fail_msg` will send this message when there's an error.
/// Those without this argument will ignore the error.
#[macro_export]
macro_rules! connect_async_func {
    ($class:ident :: $async_function:ident, $relm:expr, $msg:expr) => {
        connect_async_func!($class::$async_func(), $relm, $msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* None, move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
    }};
    ($class:ident :: $async_func:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async_func!($class::$async_func(), $relm, $msg, $fail_msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        let fail_event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* None, move |result| {
            match result {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });

    }};
}

/// Like `connect_async!`, but also return a `Cancellable` to control the asynchronous request.
#[macro_export]
macro_rules! connect_async_full {
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr) => {
        connect_async_full!($object, $async_method(), $relm, $msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* Some(&cancellable), move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
        cancellable
    }};
    ($object:expr, $async_method:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async_full!($object, $async_method(), $relm, $msg, $fail_msg)
    };
    ($object:expr, $async_method:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        let fail_event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $object.$async_method($($args,)* Some(&cancellable), move |result| {
            match result {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });

        cancellable
    }};
}

/// Like `connect_async_func!`, but also return a `Cancellable` to control the asynchronous request.
#[macro_export]
macro_rules! connect_async_func_full {
    ($class:ident :: $async_function:ident, $relm:expr, $msg:expr) => {
        connect_async!($async_func(), $relm, $msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* Some(&cancellable), move |result| {
            if let Ok(result) = result {
                stream.into_inner().emit($msg(result));
            }
        });
        cancellable
    }};
    ($class:ident :: $async_func:ident, $relm:expr, $msg:expr, $fail_msg:expr) => {
        connect_async!($async_func(), $relm, $msg, $fail_msg)
    };
    ($class:ident :: $async_func:ident ( $($args:expr),* ), $relm:expr, $msg:expr, $fail_msg:expr) => {{
        let cancellable = ::gio::Cancellable::new();
        let event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        let fail_event_stream = ::relm::vendor::fragile::Fragile::new($relm.stream().clone());
        $class::$async_func($($args,)* Some(&cancellable), move |result| {
            match result {
                Ok(value) => event_stream.into_inner().emit($msg(value)),
                Err(error) => fail_event_stream.into_inner().emit($fail_msg(error)),
            }
        });

        cancellable
    }};
}
<commit_msg>Revert "Temporary fix to publish the crate"<commit_after>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.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.
 */

include!("../relm-state/src/macros.rs");
<|endoftext|>


<commit_before>/// Implements conversion traits on a type wrapping a three-rs type. Useful for when you wrap a
/// three-rs type with your own struct. Allows you to use that struct in place of any three-rs
/// object.
///
/// Implements the following traits:
///
/// * `AsRef<NodePointer>`
/// * `Deref<Target=Object>`
/// * `DerefMut<Object>`
///
/// ```
/// // Implements conversion traits for MyStruct using field `internal_three_type`
/// three_object_wrapper!(MyStruct#internal_three_type);
/// // If field is omitted, it defaults to `object`
/// three_object_wrapper!(MyStruct); // equivalent to three_object_wrapper!(MyStruct#object);
/// ```
#[macro_export]
macro_rules! three_object_wrapper {
    ($($name:ident),*) => {
        three_object_wrapper!($($name#object),*);
    };
    ($($name:ident # $field:ident),*) => {
        $(
            impl AsRef<$crate::NodePointer> for $name {
                fn as_ref(&self) -> &$crate::NodePointer {
                    self.$field.as_ref()
                }
            }

            impl ::std::ops::Deref for $name {
                type Target = Object;
                fn deref(&self) -> &Object {
                    &self.$field
                }
            }

            impl ::std::ops::DerefMut for $name {
                fn deref_mut(&mut self) -> &mut Object {
                    &mut self.$field
                }
            }
        )*
    };
}
<commit_msg>changing # to :: in macro syntax and ignoring doctest which will not work (without a lot of extra effort)<commit_after>/// Implements conversion traits on a type wrapping a three-rs type. Useful for when you wrap a
/// three-rs type with your own struct. Allows you to use that struct in place of any three-rs
/// object.
///
/// Implements the following traits:
///
/// * `AsRef<NodePointer>`
/// * `Deref<Target=Object>`
/// * `DerefMut<Object>`
///
/// ```rust,ignore
/// // Implements conversion traits for MyStruct using field `internal_three_type`
/// three_object_wrapper!(MyStruct::internal_three_type);
/// // If field is omitted, it defaults to `object`
/// three_object_wrapper!(MyStruct); // equivalent to three_object_wrapper!(MyStruct::object);
/// ```
#[macro_export]
macro_rules! three_object_wrapper {
    ($($name:ident),*) => {
        three_object_wrapper!($($name::object),*);
    };
    ($($name:ident::$field:ident),*) => {
        $(
            impl AsRef<$crate::NodePointer> for $name {
                fn as_ref(&self) -> &$crate::NodePointer {
                    self.$field.as_ref()
                }
            }

            impl ::std::ops::Deref for $name {
                type Target = Object;
                fn deref(&self) -> &Object {
                    &self.$field
                }
            }

            impl ::std::ops::DerefMut for $name {
                fn deref_mut(&mut self) -> &mut Object {
                    &mut self.$field
                }
            }
        )*
    };
}
<|endoftext|>


<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.

/*!
* Minimal binding for OpenAL.
* Bind only functions which are needed by lib sailor
*/

#![allow(dead_code, non_snake_case)]

#[link(name = "openal")]
extern {}

pub mod ffi {

    use libc::{c_char, c_void, intptr_t };

    /// OpenAL types
    pub type ALboolean = c_char;
    pub type ALCboolean = c_char;
    pub type ALCdevicePtr = intptr_t;
    pub type ALCcontextPtr = intptr_t;
    pub const AL_TRUE:                ALboolean  = 1;
    pub const AL_FALSE:               ALboolean  = 0;
    pub const ALC_TRUE:               ALCboolean  = 1;
    pub const ALC_FALSE:              ALCboolean  = 0;

    /// Sound modifier
    pub const AL_GAIN:                i32         = 0x100A;
    pub const AL_PITCH:               i32         = 0x1003;
    pub const AL_SOURCE_RELATIVE:     i32         = 0x202;
    pub const AL_POSITION:            i32         = 0x1004;
    pub const AL_ORIENTATION:         i32         = 0x100F;
    pub const AL_DIRECTION:           i32         = 0x1005;
    pub const AL_LOOPING:             i32         = 0x1007;
    pub const AL_MIN_GAIN:            i32         = 0x100D;
    pub const AL_MAX_GAIN:            i32         = 0x100E;
    pub const AL_MAX_DISTANCE:        i32         = 0x1023;
    pub const AL_REFERENCE_DISTANCE:  i32         = 0x1020;
    pub const AL_ROLLOFF_FACTOR:      i32         = 0x1021;

    /// Sound format
    pub const AL_FORMAT_MONO16:       i32         = 0x1101;
    pub const AL_FORMAT_STEREO16:     i32         = 0x1103;
    pub const AL_FORMAT_51CHN16:      i32         = 0x120B;
    pub const AL_FORMAT_61CHN16:      i32         = 0x120E;
    pub const AL_FORMAT_71CHN16:      i32         = 0x1211;
    pub const AL_FORMAT_QUAD16:       i32         = 0x1205;

    /// Source params
    pub const AL_BUFFER:              i32         = 0x1009;
    pub const AL_BUFFERS_PROCESSED:   i32         = 0x1016;
    pub const AL_BUFFERS_QUEUED:      i32         = 0x1015;
    pub const AL_DIRECT_CHANNELS_SOFT:i32         = 0x1033;

    /// Error identifiers
    pub const AL_NO_ERROR:            i32         = 0;
    pub const AL_INVALID_NAME:        i32         = 0xA001;
    pub const AL_INVALID_ENUM:        i32         = 0xA002;
    pub const AL_INVALID_VALUE:       i32         = 0xA003;
    pub const AL_INVALID_OPERATION:   i32         = 0xA004;
    pub const AL_OUT_OF_MEMORY :      i32         = 0xA005;

    /// Source states
    pub const AL_SOURCE_STATE:        i32         = 0x1010;
    pub const AL_INITIAL:             i32         = 0x1011;
    pub const AL_PLAYING:             i32         = 0x1012;
    pub const AL_PAUSED:              i32         = 0x1013;
    pub const AL_STOPPED:             i32         = 0x1014;

    /// ALC
    pub const ALC_CAPTURE_SAMPLES :    i32         = 0x312;

    extern "C" {
        /// Context functions
        pub fn alcCreateContext(device: ALCdevicePtr, attrlist: *mut i32) -> ALCcontextPtr;
        pub fn alcMakeContextCurrent(context: ALCcontextPtr) -> ALCboolean;
        pub fn alcDestroyContext(context: ALCcontextPtr);
        pub fn alcGetCurrentContext() -> ALCcontextPtr;

        /// Device functions
        pub fn alcOpenDevice(devicename: *mut c_char) -> ALCdevicePtr;
        pub fn alcCloseDevice(device: ALCdevicePtr) -> ALCboolean;

        /// Listener functions
        pub fn alListenerf(param: i32, value: f32) -> ();
        pub fn alListener3f(param: i32, value1: f32, value2: f32, value3: f32) -> ();
        pub fn alGetListenerf(param: i32, value: *mut f32) -> ();
        pub fn alGetListener3f(param: f32, value1: *mut f32, value2: *mut f32, value3: *mut f32) -> ();
        pub fn alListenerfv(param: i32, values: *const f32) -> ();
        pub fn alGetListenerfv(param: i32, values: *mut f32) -> ();

        /// Sources functions
        pub fn alGenSources(n: i32, sources: *mut u32) -> ();
        pub fn alDeleteSources(n: i32, buffers: *mut u32) -> ();
        pub fn alSourcei(source: u32, param: i32, value: i32) -> ();
        pub fn alSourcef(source: u32, param: i32, value: f32) -> ();
        pub fn alSourcePlay(source: u32) -> ();
        pub fn alSourcePause(source: u32) -> ();
        pub fn alSourceStop(source: u32) -> ();
        pub fn alGetSourcei(source: u32, param: i32, value: *mut i32) -> ();
        pub fn alGetSourcef(source: u32, param: i32, value: *mut f32) -> ();
        pub fn alSourcefv(source: u32, param: i32, value: *const f32) -> ();
        pub fn alGetSourcefv(source: u32, param: i32, value: *mut f32) -> ();
        pub fn alSourceQueueBuffers(source: u32, nb: i32, buffers: *const u32) -> ();
        pub fn alSourceUnqueueBuffers(source: u32, nb: i32, buffers: *mut u32) -> ();

        /// Sound capture functions
        pub fn alcCaptureCloseDevice(device: ALCdevicePtr) -> ALCboolean;
        pub fn alcCaptureOpenDevice(device: *mut c_char, sample_rate: i32, format: i32, buffer_size: i32) -> ALCdevicePtr;
        pub fn alcCaptureStart(devide: ALCdevicePtr);
        pub fn alcCaptureStop(devide: ALCdevicePtr);
        pub fn alcGetIntegerv(devide: ALCdevicePtr, param: i32,  size: i32, values: *mut i32);
        pub fn alcCaptureSamples(devide: ALCdevicePtr, buffer: *mut c_void,sample: i32);

        /// extension check
        pub fn alcIsExtensionPresent(device: ALCdevicePtr, extension: *const c_char) -> ALCboolean;

        /// Buffers functions
        pub fn alGenBuffers(n: i32, buffers: *mut u32) -> ();
        pub fn alDeleteBuffers(n: i32, buffers: *mut u32);
        pub fn alBufferData(buffer: u32, format: i32, data: *mut c_void, size: i32, freq: i32) -> ();

        /// Error
        pub fn alGetError() -> i32;
    }

    #[repr(C)]
    pub struct ALCdevice;
    #[repr(C)]
    pub struct ALCcontext;
}

pub mod al {

    use super::ffi;
    use libc::c_void;

    pub fn alBufferData(buffer: u32, format: i32, data: *mut c_void, size: i32, freq: i32) -> () {
        unsafe { ffi::alBufferData(buffer, format, data, size, freq); }
    }

    pub fn alSourceQueueBuffers(source: u32, nb: i32, buffers: *const u32) -> () {
        unsafe { ffi::alSourceQueueBuffers(source, nb, buffers); }
    }

    pub fn alSourcePlay(source: u32) -> () {
        unsafe { ffi::alSourcePlay(source); }
    }

    pub fn alGetSourcei(source: u32, param: i32, value: *mut i32) -> () {
        unsafe { ffi::alGetSourcei(source, param, value); }
    }

    pub fn alGetSourcef(source: u32, param: i32, value: *mut f32) -> () {
        unsafe { ffi::alGetSourcef(source, param, value); }
    }

    pub fn alGetState(source: u32) -> i32 {
        let mut i = 0;
        unsafe { ffi::alGetSourcei(source, ffi::AL_SOURCE_STATE, &mut i); }
        i
    }

    pub fn alSourcei(source: u32, param: i32, value: i32) -> () {
        unsafe { ffi::alSourcei(source, param, value); }
    }

    pub fn alSourcef(source: u32, param: i32, value: f32) -> () {
        unsafe { ffi::alSourcef(source, param, value); }
    }

    pub fn alSourcePause(source: u32) -> () {
        unsafe { ffi::alSourcePause(source); }
    }

    pub fn alSourceStop(source: u32) -> () {
        unsafe { ffi::alSourceStop(source); }
    }

    pub fn alSourceUnqueueBuffers(source: u32, nb: i32, buffers: *mut u32) -> () {
        unsafe { ffi::alSourceUnqueueBuffers(source, nb, buffers); }
    }

    pub fn alGenSources(n: i32, sources: *mut u32) -> () {
        unsafe {ffi::alGenSources(n, sources); }
    }

    pub fn alSourcefv(source: u32, param: i32, value: *const f32) -> () {
        unsafe { ffi::alSourcefv(source, param, value); }
    }

    pub fn alGetSourcefv(source: u32, param: i32, value: *mut f32) -> () {
        unsafe { ffi::alGetSourcefv(source, param, value); }
    }

    pub fn alGenBuffers(n: i32, buffers: *mut u32) -> () {
        unsafe { ffi::alGenBuffers(n, buffers); }
    }

    pub fn alListenerf(param: i32, value: f32) -> () {
        unsafe { ffi::alListenerf(param, value); }
    }

    pub fn alListener3f(param: i32, value1: f32, value2: f32, value3: f32) -> () {
        unsafe { ffi::alListener3f(param, value1, value2, value3); }
    }

    pub fn alGetListenerf(param: i32, value: *mut f32) -> () {
        unsafe { ffi::alGetListenerf(param, value); }
    }

    pub fn alGetListener3f(param: f32, value1: *mut f32, value2: *mut f32, value3: *mut f32) -> () {
        unsafe { ffi::alGetListener3f(param, value1, value2, value3); }
    }

    pub fn alListenerfv(param: i32, values: *const f32) -> () {
        unsafe { ffi::alListenerfv(param, values); }
    }

    pub fn alGetListenerfv(param: i32, values: *mut f32) -> () {
        unsafe { ffi::alGetListenerfv(param, values); }
    }

    pub fn openal_has_error() -> Option<String> {
         match unsafe { ffi::alGetError() } {
            ffi::AL_NO_ERROR          => None,
            ffi::AL_INVALID_NAME      => Some("OpenAL error : Invalid name paramater passed to AL call.".to_string()),
            ffi::AL_INVALID_ENUM      => Some("OpenAL error : Invalid enum parameter passed to AL call.".to_string()),
            ffi::AL_INVALID_VALUE     => Some("OpenAL error : Invalid value parameter passed to AL call.".to_string()),
            ffi::AL_INVALID_OPERATION => Some("OpenAL error : Illegal AL call.".to_string()),
            ffi::AL_OUT_OF_MEMORY     => Some("OpenAL error : Not enough memory.".to_string()),
            _                         => Some("OpenAL internal error : Unknow error.".to_string())
        }
    }

    pub fn get_channels_format(channels : i32) -> Option<i32> {
        match channels {
            1 => Some(ffi::AL_FORMAT_MONO16),
            2 => Some(ffi::AL_FORMAT_STEREO16),
            4 => Some(ffi::AL_FORMAT_QUAD16),
            5 => Some(ffi::AL_FORMAT_51CHN16),
            6 => Some(ffi::AL_FORMAT_61CHN16),
            7 => Some(ffi::AL_FORMAT_71CHN16),
            _ => return None
        }
    }
}
<commit_msg>Add ffi binding for alIsExtensionPresent<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.

/*!
* Minimal binding for OpenAL.
* Bind only functions which are needed by lib sailor
*/

#![allow(dead_code, non_snake_case)]

#[link(name = "openal")]
extern {}

pub mod ffi {

    use libc::{c_char, c_void, intptr_t };

    /// OpenAL types
    pub type ALboolean = c_char;
    pub type ALCboolean = c_char;
    pub type ALCdevicePtr = intptr_t;
    pub type ALCcontextPtr = intptr_t;
    pub const AL_TRUE:                ALboolean  = 1;
    pub const AL_FALSE:               ALboolean  = 0;
    pub const ALC_TRUE:               ALCboolean  = 1;
    pub const ALC_FALSE:              ALCboolean  = 0;

    /// Sound modifier
    pub const AL_GAIN:                i32         = 0x100A;
    pub const AL_PITCH:               i32         = 0x1003;
    pub const AL_SOURCE_RELATIVE:     i32         = 0x202;
    pub const AL_POSITION:            i32         = 0x1004;
    pub const AL_ORIENTATION:         i32         = 0x100F;
    pub const AL_DIRECTION:           i32         = 0x1005;
    pub const AL_LOOPING:             i32         = 0x1007;
    pub const AL_MIN_GAIN:            i32         = 0x100D;
    pub const AL_MAX_GAIN:            i32         = 0x100E;
    pub const AL_MAX_DISTANCE:        i32         = 0x1023;
    pub const AL_REFERENCE_DISTANCE:  i32         = 0x1020;
    pub const AL_ROLLOFF_FACTOR:      i32         = 0x1021;

    /// Sound format
    pub const AL_FORMAT_MONO16:       i32         = 0x1101;
    pub const AL_FORMAT_STEREO16:     i32         = 0x1103;
    pub const AL_FORMAT_51CHN16:      i32         = 0x120B;
    pub const AL_FORMAT_61CHN16:      i32         = 0x120E;
    pub const AL_FORMAT_71CHN16:      i32         = 0x1211;
    pub const AL_FORMAT_QUAD16:       i32         = 0x1205;

    /// Source params
    pub const AL_BUFFER:              i32         = 0x1009;
    pub const AL_BUFFERS_PROCESSED:   i32         = 0x1016;
    pub const AL_BUFFERS_QUEUED:      i32         = 0x1015;
    pub const AL_DIRECT_CHANNELS_SOFT:i32         = 0x1033;

    /// Error identifiers
    pub const AL_NO_ERROR:            i32         = 0;
    pub const AL_INVALID_NAME:        i32         = 0xA001;
    pub const AL_INVALID_ENUM:        i32         = 0xA002;
    pub const AL_INVALID_VALUE:       i32         = 0xA003;
    pub const AL_INVALID_OPERATION:   i32         = 0xA004;
    pub const AL_OUT_OF_MEMORY :      i32         = 0xA005;

    /// Source states
    pub const AL_SOURCE_STATE:        i32         = 0x1010;
    pub const AL_INITIAL:             i32         = 0x1011;
    pub const AL_PLAYING:             i32         = 0x1012;
    pub const AL_PAUSED:              i32         = 0x1013;
    pub const AL_STOPPED:             i32         = 0x1014;

    /// ALC
    pub const ALC_CAPTURE_SAMPLES :    i32         = 0x312;

    extern "C" {
        /// Context functions
        pub fn alcCreateContext(device: ALCdevicePtr, attrlist: *mut i32) -> ALCcontextPtr;
        pub fn alcMakeContextCurrent(context: ALCcontextPtr) -> ALCboolean;
        pub fn alcDestroyContext(context: ALCcontextPtr);
        pub fn alcGetCurrentContext() -> ALCcontextPtr;

        /// Device functions
        pub fn alcOpenDevice(devicename: *mut c_char) -> ALCdevicePtr;
        pub fn alcCloseDevice(device: ALCdevicePtr) -> ALCboolean;

        /// Listener functions
        pub fn alListenerf(param: i32, value: f32) -> ();
        pub fn alListener3f(param: i32, value1: f32, value2: f32, value3: f32) -> ();
        pub fn alGetListenerf(param: i32, value: *mut f32) -> ();
        pub fn alGetListener3f(param: f32, value1: *mut f32, value2: *mut f32, value3: *mut f32) -> ();
        pub fn alListenerfv(param: i32, values: *const f32) -> ();
        pub fn alGetListenerfv(param: i32, values: *mut f32) -> ();

        /// Sources functions
        pub fn alGenSources(n: i32, sources: *mut u32) -> ();
        pub fn alDeleteSources(n: i32, buffers: *mut u32) -> ();
        pub fn alSourcei(source: u32, param: i32, value: i32) -> ();
        pub fn alSourcef(source: u32, param: i32, value: f32) -> ();
        pub fn alSourcePlay(source: u32) -> ();
        pub fn alSourcePause(source: u32) -> ();
        pub fn alSourceStop(source: u32) -> ();
        pub fn alGetSourcei(source: u32, param: i32, value: *mut i32) -> ();
        pub fn alGetSourcef(source: u32, param: i32, value: *mut f32) -> ();
        pub fn alSourcefv(source: u32, param: i32, value: *const f32) -> ();
        pub fn alGetSourcefv(source: u32, param: i32, value: *mut f32) -> ();
        pub fn alSourceQueueBuffers(source: u32, nb: i32, buffers: *const u32) -> ();
        pub fn alSourceUnqueueBuffers(source: u32, nb: i32, buffers: *mut u32) -> ();

        /// Sound capture functions
        pub fn alcCaptureCloseDevice(device: ALCdevicePtr) -> ALCboolean;
        pub fn alcCaptureOpenDevice(device: *mut c_char, sample_rate: i32, format: i32, buffer_size: i32) -> ALCdevicePtr;
        pub fn alcCaptureStart(devide: ALCdevicePtr);
        pub fn alcCaptureStop(devide: ALCdevicePtr);
        pub fn alcGetIntegerv(devide: ALCdevicePtr, param: i32,  size: i32, values: *mut i32);
        pub fn alcCaptureSamples(devide: ALCdevicePtr, buffer: *mut c_void,sample: i32);

        /// extension check
        pub fn alIsExtensionPresent(extension: *const c_char) -> ALboolean;
        pub fn alcIsExtensionPresent(device: ALCdevicePtr, extension: *const c_char) -> ALCboolean;

        /// Buffers functions
        pub fn alGenBuffers(n: i32, buffers: *mut u32) -> ();
        pub fn alDeleteBuffers(n: i32, buffers: *mut u32);
        pub fn alBufferData(buffer: u32, format: i32, data: *mut c_void, size: i32, freq: i32) -> ();

        /// Error
        pub fn alGetError() -> i32;
    }

    #[repr(C)]
    pub struct ALCdevice;
    #[repr(C)]
    pub struct ALCcontext;
}

pub mod al {

    use super::ffi;
    use libc::c_void;

    pub fn alBufferData(buffer: u32, format: i32, data: *mut c_void, size: i32, freq: i32) -> () {
        unsafe { ffi::alBufferData(buffer, format, data, size, freq); }
    }

    pub fn alSourceQueueBuffers(source: u32, nb: i32, buffers: *const u32) -> () {
        unsafe { ffi::alSourceQueueBuffers(source, nb, buffers); }
    }

    pub fn alSourcePlay(source: u32) -> () {
        unsafe { ffi::alSourcePlay(source); }
    }

    pub fn alGetSourcei(source: u32, param: i32, value: *mut i32) -> () {
        unsafe { ffi::alGetSourcei(source, param, value); }
    }

    pub fn alGetSourcef(source: u32, param: i32, value: *mut f32) -> () {
        unsafe { ffi::alGetSourcef(source, param, value); }
    }

    pub fn alGetState(source: u32) -> i32 {
        let mut i = 0;
        unsafe { ffi::alGetSourcei(source, ffi::AL_SOURCE_STATE, &mut i); }
        i
    }

    pub fn alSourcei(source: u32, param: i32, value: i32) -> () {
        unsafe { ffi::alSourcei(source, param, value); }
    }

    pub fn alSourcef(source: u32, param: i32, value: f32) -> () {
        unsafe { ffi::alSourcef(source, param, value); }
    }

    pub fn alSourcePause(source: u32) -> () {
        unsafe { ffi::alSourcePause(source); }
    }

    pub fn alSourceStop(source: u32) -> () {
        unsafe { ffi::alSourceStop(source); }
    }

    pub fn alSourceUnqueueBuffers(source: u32, nb: i32, buffers: *mut u32) -> () {
        unsafe { ffi::alSourceUnqueueBuffers(source, nb, buffers); }
    }

    pub fn alGenSources(n: i32, sources: *mut u32) -> () {
        unsafe {ffi::alGenSources(n, sources); }
    }

    pub fn alSourcefv(source: u32, param: i32, value: *const f32) -> () {
        unsafe { ffi::alSourcefv(source, param, value); }
    }

    pub fn alGetSourcefv(source: u32, param: i32, value: *mut f32) -> () {
        unsafe { ffi::alGetSourcefv(source, param, value); }
    }

    pub fn alGenBuffers(n: i32, buffers: *mut u32) -> () {
        unsafe { ffi::alGenBuffers(n, buffers); }
    }

    pub fn alListenerf(param: i32, value: f32) -> () {
        unsafe { ffi::alListenerf(param, value); }
    }

    pub fn alListener3f(param: i32, value1: f32, value2: f32, value3: f32) -> () {
        unsafe { ffi::alListener3f(param, value1, value2, value3); }
    }

    pub fn alGetListenerf(param: i32, value: *mut f32) -> () {
        unsafe { ffi::alGetListenerf(param, value); }
    }

    pub fn alGetListener3f(param: f32, value1: *mut f32, value2: *mut f32, value3: *mut f32) -> () {
        unsafe { ffi::alGetListener3f(param, value1, value2, value3); }
    }

    pub fn alListenerfv(param: i32, values: *const f32) -> () {
        unsafe { ffi::alListenerfv(param, values); }
    }

    pub fn alGetListenerfv(param: i32, values: *mut f32) -> () {
        unsafe { ffi::alGetListenerfv(param, values); }
    }

    pub fn openal_has_error() -> Option<String> {
         match unsafe { ffi::alGetError() } {
            ffi::AL_NO_ERROR          => None,
            ffi::AL_INVALID_NAME      => Some("OpenAL error : Invalid name paramater passed to AL call.".to_string()),
            ffi::AL_INVALID_ENUM      => Some("OpenAL error : Invalid enum parameter passed to AL call.".to_string()),
            ffi::AL_INVALID_VALUE     => Some("OpenAL error : Invalid value parameter passed to AL call.".to_string()),
            ffi::AL_INVALID_OPERATION => Some("OpenAL error : Illegal AL call.".to_string()),
            ffi::AL_OUT_OF_MEMORY     => Some("OpenAL error : Not enough memory.".to_string()),
            _                         => Some("OpenAL internal error : Unknow error.".to_string())
        }
    }

    pub fn get_channels_format(channels : i32) -> Option<i32> {
        match channels {
            1 => Some(ffi::AL_FORMAT_MONO16),
            2 => Some(ffi::AL_FORMAT_STEREO16),
            4 => Some(ffi::AL_FORMAT_QUAD16),
            5 => Some(ffi::AL_FORMAT_51CHN16),
            6 => Some(ffi::AL_FORMAT_61CHN16),
            7 => Some(ffi::AL_FORMAT_71CHN16),
            _ => return None
        }
    }
}
<|endoftext|>


<commit_before>extern crate glm;
extern crate sdl2;

use std::error::Error;
use self::sdl2::rect;

use self::sdl2::render::{Renderer, Texture};

pub struct Meteor {
    texture: Texture,
    center: glm::Vector2<f64>,
    dims: glm::Vector2<u32>,
    max_coords: glm::Vector2<u32>,
    velocity: glm::Vector2<f64>,
    launched: bool,
}

impl Meteor {
    pub fn new(texture: Texture, max_coords: glm::Vector2<u32>) -> Self {
        let query = texture.query();
        let center = glm::dvec2(0., 0.);
        let dims = glm::uvec2(query.width, query.height);

        Meteor {
            texture: texture,
            center: center,
            dims: dims,
            max_coords: max_coords,
            velocity: glm::dvec2(0., 0.),
            launched: false,
        }
    }

    pub fn launch(&mut self, target: glm::Vector2<f64>) {
        const FACTOR: f64 = 85.;
        let offset = target - self.center;
        self.velocity = glm::dvec2(offset.x as f64 / FACTOR, offset.y as f64 / FACTOR);
        self.launched = true;
    }

    pub fn update(&mut self) {
        self.center.y += self.velocity.y;
        self.center.x += self.velocity.x;

        let max_height = self.max_coords.y as f64;
        let max_width = self.max_coords.x as f64;

        self.center.y = (self.center.y + max_height) % max_height;
        self.center.x = (self.center.x + max_width) % max_width;
    }

    pub fn is_launched(&self) -> bool {
        self.launched
    }

    pub fn draw(&self, renderer: &mut Renderer) -> Result<(), Box<Error>> {
        let rects = self.drawing_rectangles();
        let results = rects.iter()
            .filter(|r| r.is_some())
            .map(|r| renderer.copy(&self.texture, None, *r));

        for result in results {
            try!(result)
        }

        Ok(())
    }

    fn drawing_rectangles(&self) -> [Option<rect::Rect>; 4] {
        let top = self.center.y as i32 - self.dims.y as i32 / 2;
        let bottom = self.center.y as i32 + self.dims.y as i32 / 2;
        let left = self.center.x as i32 - self.dims.x as i32 / 2;
        let right = self.center.x as i32 + self.dims.x as i32 / 2;

        let rect = rect::Rect::new(left, top, self.dims.x, self.dims.y);
        let mut rects: [Option<rect::Rect>; 4] = [Some(rect), None, None, None];
        let mut count = 1;

        let max_height = self.max_coords.y as i32;
        let max_width = self.max_coords.x as i32;

        if top < 0 {
            let mut rect = rect.clone();
            rect.set_y(top + max_height);
            rects[count] = Some(rect);
            count += 1;

            if left < 0 {
                rect.set_x(left + max_width);
                rects[count] = Some(rect);
                count += 1;
            } else if right > max_width {
                rect.set_right(right % max_width);
                rects[count] = Some(rect);
                count += 1;
            }
        } else if bottom > max_height {
            let mut rect = rect.clone();
            rect.set_bottom(bottom % max_height);
            rects[count] = Some(rect);
            count += 1;

            if left < 0 {
                rect.set_x(left + max_width);
                rects[count] = Some(rect);
                count += 1;
            } else if right > max_width {
                rect.set_right(right % max_width);
                rects[count] = Some(rect);
                count += 1;
            }
        }

        if left < 0 {
            let mut rect = rect.clone();
            rect.set_x(left + max_width);
            rects[count] = Some(rect);
        } else if right > max_width {
            let mut rect = rect.clone();
            rect.set_right(right % max_width);
            rects[count] = Some(rect);
        }

        rects
    }
}
<commit_msg>refactor drawing of meteor rectangles to use only iterators<commit_after>extern crate glm;
extern crate sdl2;

use self::sdl2::rect;
use self::sdl2::render::{Renderer, Texture};

pub struct Meteor {
    texture: Texture,
    center: glm::Vector2<f64>,
    dims: glm::Vector2<u32>,
    max_coords: glm::Vector2<u32>,
    velocity: glm::Vector2<f64>,
    launched: bool,
}

impl Meteor {
    pub fn new(texture: Texture, max_coords: glm::Vector2<u32>) -> Self {
        let query = texture.query();
        let center = glm::dvec2(0., 0.);
        let dims = glm::uvec2(query.width, query.height);

        Meteor {
            texture: texture,
            center: center,
            dims: dims,
            max_coords: max_coords,
            velocity: glm::dvec2(0., 0.),
            launched: false,
        }
    }

    pub fn launch(&mut self, target: glm::Vector2<f64>) {
        const FACTOR: f64 = 85.;
        let offset = target - self.center;
        self.velocity = glm::dvec2(offset.x as f64 / FACTOR, offset.y as f64 / FACTOR);
        self.launched = true;
    }

    pub fn update(&mut self) {
        self.center.y += self.velocity.y;
        self.center.x += self.velocity.x;

        let max_height = self.max_coords.y as f64;
        let max_width = self.max_coords.x as f64;

        self.center.y = (self.center.y + max_height) % max_height;
        self.center.x = (self.center.x + max_width) % max_width;
    }

    pub fn is_launched(&self) -> bool {
        self.launched
    }

    pub fn draw(&self, renderer: &mut Renderer) -> Result<(), String> {
        self.drawing_rectangles()
            .iter()
            .filter(|r| r.is_some())
            .map(|&r| renderer.copy(&self.texture, None, r))
            .fold(Ok(()), |res, x| { if res.is_err() { res } else { x } })
    }

    fn drawing_rectangles(&self) -> [Option<rect::Rect>; 4] {
        let top = self.center.y as i32 - self.dims.y as i32 / 2;
        let bottom = self.center.y as i32 + self.dims.y as i32 / 2;
        let left = self.center.x as i32 - self.dims.x as i32 / 2;
        let right = self.center.x as i32 + self.dims.x as i32 / 2;

        let rect = rect::Rect::new(left, top, self.dims.x, self.dims.y);
        let mut rects: [Option<rect::Rect>; 4] = [Some(rect), None, None, None];
        let mut count = 1;

        let max_height = self.max_coords.y as i32;
        let max_width = self.max_coords.x as i32;

        if top < 0 {
            let mut rect = rect.clone();
            rect.set_y(top + max_height);
            rects[count] = Some(rect);
            count += 1;

            if left < 0 {
                rect.set_x(left + max_width);
                rects[count] = Some(rect);
                count += 1;
            } else if right > max_width {
                rect.set_right(right % max_width);
                rects[count] = Some(rect);
                count += 1;
            }
        } else if bottom > max_height {
            let mut rect = rect.clone();
            rect.set_bottom(bottom % max_height);
            rects[count] = Some(rect);
            count += 1;

            if left < 0 {
                rect.set_x(left + max_width);
                rects[count] = Some(rect);
                count += 1;
            } else if right > max_width {
                rect.set_right(right % max_width);
                rects[count] = Some(rect);
                count += 1;
            }
        }

        if left < 0 {
            let mut rect = rect.clone();
            rect.set_x(left + max_width);
            rects[count] = Some(rect);
        } else if right > max_width {
            let mut rect = rect.clone();
            rect.set_right(right % max_width);
            rects[count] = Some(rect);
        }

        rects
    }
}
<|endoftext|>


<commit_before>use std::str::from_utf8;
use std::result::Result;
use nom::IResult;

#[derive(Debug,PartialEq,Eq)]
pub struct TarEntry<'a> {
    pub header:   PosixHeader<'a>,
    pub contents: &'a str
}

#[derive(Debug,PartialEq,Eq)]
pub struct PosixHeader<'a> {
    pub name:     &'a str,
    pub mode:     &'a str,
    pub uid:      u64,
    pub gid:      u64,
    pub size:     u64,
    pub mtime:    u64,
    pub chksum:   &'a str,
    pub typeflag: TypeFlag,
    pub linkname: &'a str,
    pub ustar:    ExtraHeader<'a>
}

/* TODO: support vendor specific + sparse */
#[derive(Debug,PartialEq,Eq,Clone,Copy)]
pub enum TypeFlag {
    NormalFile,
    HardLink,
    SymbolicLink,
    CharacterSpecial,
    BlockSpecial,
    Directory,
    FIFO,
    ContiguousFile,
    PaxInterexchangeFormat,
    PaxExtendedAttributes,
    VendorSpecific
}

#[derive(Debug,PartialEq,Eq)]
pub enum ExtraHeader<'a> {
    UStar(UStarHeader<'a>),
    Padding
}

#[derive(Debug,PartialEq,Eq)]
pub struct UStarHeader<'a> {
    pub magic:    &'a str,
    pub version:  &'a str,
    pub uname:    &'a str,
    pub gname:    &'a str,
    pub devmajor: u64,
    pub devminor: u64,
    pub extra:    UStarExtraHeader<'a>
}

#[derive(Debug,PartialEq,Eq)]
pub enum UStarExtraHeader<'a> {
    PosixUStar(PosixUStarHeader<'a>),
    Pax(PaxHeader<'a>)
}

#[derive(Debug,PartialEq,Eq)]
pub struct PosixUStarHeader<'a> {
    pub prefix: &'a str
}

#[derive(Debug,PartialEq,Eq)]
pub struct PaxHeader<'a> {
    pub atime:      u64,
    pub ctime:      u64,
    pub offset:     u64,
    pub longnames:  &'a str,
    pub sparse:     [Sparse; 4],
    pub isextended: bool,
    pub realsize:   u64
}

#[derive(Debug,PartialEq,Eq,Clone,Copy)]
pub struct Sparse {
    pub offset:   u64,
    pub numbytes: u64
}

#[derive(Debug,PartialEq,Eq)]
pub struct Padding;

pub fn octal_to_u64(s: &str) -> Result<u64, &'static str> {
    let mut u = 0;

    for c in s.chars() {
        if c < '0' || c > '7' {
            return Err("invalid octal string received");
        }
        u *= 8;
        u += (c as u64) - ('0' as u64);
    }

    Ok(u)
}

fn char_to_type_flag(c: char) -> TypeFlag {
    match c {
        '0' | '\0' => TypeFlag::NormalFile,
        '1' => TypeFlag::HardLink,
        '2' => TypeFlag::SymbolicLink,
        '3' => TypeFlag::CharacterSpecial,
        '4' => TypeFlag::BlockSpecial,
        '5' => TypeFlag::Directory,
        '6' => TypeFlag::FIFO,
        '7' => TypeFlag::ContiguousFile,
        'g' => TypeFlag::PaxInterexchangeFormat,
        'x' => TypeFlag::PaxExtendedAttributes,
        'A' ... 'Z' => TypeFlag::VendorSpecific,
        _ => TypeFlag::NormalFile
    }
}

fn parse_type_flag(i: &[u8]) -> Result<TypeFlag, &'static str> {
    Ok(char_to_type_flag(i[0] as char))
}

macro_rules! take_str_eat_garbage (
    ( $i:expr, $size:expr ) => (
        chain!($i,
            s: map_res!(take_until!("\0"), from_utf8) ~
            take!($size - s.len()),
            ||{
                s
            }
        )
    );
);

fn parse_one_sparse(i: &[u8]) -> IResult<&[u8], Sparse> {
    chain!(i,
        offset:   map_res!(take_str_eat_garbage!(12), octal_to_u64) ~
        numbytes: map_res!(take_str_eat_garbage!(12), octal_to_u64),
        ||{
            Sparse {
                offset:   offset,
                numbytes: numbytes
            }
        }
    )
}

fn parse_sparse(i: &[u8]) -> IResult<&[u8], [Sparse; 4]> {
    count!(i, parse_one_sparse, Sparse, 4)
}

fn to_bool(i: &[u8]) -> Result<bool, &'static str> {
    Ok(i[0] != 0)
}

fn parse_ustar00_extra_pax(i: &[u8]) -> IResult<&[u8], UStarExtraHeader> {
    chain!(i,
        atime:      map_res!(take_str_eat_garbage!(12), octal_to_u64) ~
        ctime:      map_res!(take_str_eat_garbage!(12), octal_to_u64) ~
        offset:     map_res!(take_str_eat_garbage!(12), octal_to_u64) ~
        longnames:  take_str_eat_garbage!(4)                          ~
        take!(1)                                                      ~
        sparse:     parse_sparse                                      ~
        isextended: map_res!(take!(1), to_bool)                       ~
        realsize:   map_res!(take_str_eat_garbage!(12), octal_to_u64) ~
        take!(17), /* padding to 512 */
        ||{
            UStarExtraHeader::Pax(PaxHeader {
                atime:      atime,
                ctime:      ctime,
                offset:     offset,
                longnames:  longnames,
                sparse:     sparse,
                isextended: isextended,
                realsize:   realsize
            })
        }
    )
}

fn parse_ustar00_extra_posix(i: &[u8]) -> IResult<&[u8], UStarExtraHeader> {
    chain!(i,
        prefix: take_str_eat_garbage!(155) ~
        take!(12),
        ||{
            UStarExtraHeader::PosixUStar(PosixUStarHeader {
                prefix: prefix
            })
        }
    )
}

fn parse_ustar00_extra(i: &[u8], flag: TypeFlag) -> IResult<&[u8], UStarExtraHeader> {
    match flag {
        TypeFlag::PaxInterexchangeFormat => parse_ustar00_extra_pax(i),
        _ => parse_ustar00_extra_posix(i)
    }
}

fn parse_ustar00(i: &[u8], flag: TypeFlag) -> IResult<&[u8], ExtraHeader> {
    chain!(i,
        tag!("00")                                                 ~
        uname:    take_str_eat_garbage!(32)                        ~
        gname:    take_str_eat_garbage!(32)                        ~
        devmajor: map_res!(take_str_eat_garbage!(8), octal_to_u64) ~
        devminor: map_res!(take_str_eat_garbage!(8), octal_to_u64) ~
        extra:    apply!(parse_ustar00_extra, flag),
        ||{
            ExtraHeader::UStar(UStarHeader {
                magic:    "ustar\0",
                version:  "00",
                uname:    uname,
                gname:    gname,
                devmajor: devmajor,
                devminor: devminor,
                extra:    extra
            })
        }
    )
}

fn parse_ustar(i: &[u8], flag: TypeFlag) -> IResult<&[u8], ExtraHeader> {
    chain!(i,
        tag!("ustar\0") ~
        ustar: apply!(parse_ustar00, flag),
        ||{
            ustar
        }
    )
}

fn parse_posix(i: &[u8]) -> IResult<&[u8], ExtraHeader> {
    chain!(i,
        take!(255), /* padding to 512 */
        ||{
            ExtraHeader::Padding
        }
    )
}

fn parse_header(i: &[u8]) -> IResult<&[u8], PosixHeader> {
    chain!(i,
        name:     take_str_eat_garbage!(100)                        ~
        mode:     take_str_eat_garbage!(8)                          ~
        uid:      map_res!(take_str_eat_garbage!(8),  octal_to_u64) ~
        gid:      map_res!(take_str_eat_garbage!(8),  octal_to_u64) ~
        size:     map_res!(take_str_eat_garbage!(12), octal_to_u64) ~
        mtime:    map_res!(take_str_eat_garbage!(12), octal_to_u64) ~
        chksum:   take_str_eat_garbage!(8)                          ~
        typeflag: map_res!(take!(1), parse_type_flag)               ~
        linkname: take_str_eat_garbage!(100)                        ~
        ustar:    alt!(apply!(parse_ustar, typeflag) | parse_posix),
        ||{
            PosixHeader {
                name:     name,
                mode:     mode,
                uid:      uid,
                gid:      gid,
                size:     size,
                mtime:    mtime,
                chksum:   chksum,
                typeflag: typeflag,
                linkname: linkname,
                ustar:    ustar
            }
        }
    )
}

fn parse_contents(i: &[u8], size: u64) -> IResult<&[u8], &str> {
    let trailing = size % 512;
    let padding = match trailing {
        0 => 0,
        t => 512 - t
    };
    chain!(i,
        contents: take_str!(size as usize) ~
        take!(padding as usize),
        ||{
            contents
        }
    )
}

fn parse_entry(i: &[u8]) -> IResult<&[u8], TarEntry> {
    chain!(i,
        header:   parse_header ~
        contents: apply!(parse_contents, header.size),
        ||{
            TarEntry {
                header: header,
                contents: contents
            }
        }
    )
}

fn filter_entries(entries: Vec<TarEntry>) -> Result<Vec<TarEntry>, &'static str> {
    Ok(entries.into_iter().filter(|e| e.header.name != "").collect::<Vec<TarEntry>>())
}

// TODO: eof
pub fn parse_tar(i: &[u8]) -> IResult<&[u8], Vec<TarEntry>> {
    map_res!(i, many0!(parse_entry), filter_entries)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::str::from_utf8;
    use nom::IResult;

    #[test]
    fn octal_to_u64_ok_test() {
        assert_eq!(octal_to_u64("756"), Ok(494));
        assert_eq!(octal_to_u64(""), Ok(0));
    }

    #[test]
    fn octal_to_u64_error_test() {
        assert_eq!(octal_to_u64("1238"), Err("invalid octal string received"));
        assert_eq!(octal_to_u64("a"), Err("invalid octal string received"));
        assert_eq!(octal_to_u64("A"), Err("invalid octal string received"));
    }

    #[test]
    fn take_str_eat_garbage_test() {
        let s = b"foobar\0\0\0\0baz";
        let baz = b"baz";
        assert_eq!(take_str_eat_garbage!(&s[..], 10), IResult::Done(&baz[..], "foobar"));
    }
}
<commit_msg>add helper parsers, reorder stuff<commit_after>use std::str::from_utf8;
use std::result::Result;
use nom::IResult;

/*
 * Core structs
 */

#[derive(Debug,PartialEq,Eq)]
pub struct TarEntry<'a> {
    pub header:   PosixHeader<'a>,
    pub contents: &'a str
}

#[derive(Debug,PartialEq,Eq)]
pub struct PosixHeader<'a> {
    pub name:     &'a str,
    pub mode:     &'a str,
    pub uid:      u64,
    pub gid:      u64,
    pub size:     u64,
    pub mtime:    u64,
    pub chksum:   &'a str,
    pub typeflag: TypeFlag,
    pub linkname: &'a str,
    pub ustar:    ExtraHeader<'a>
}

/* TODO: support vendor specific + sparse */
#[derive(Debug,PartialEq,Eq,Clone,Copy)]
pub enum TypeFlag {
    NormalFile,
    HardLink,
    SymbolicLink,
    CharacterSpecial,
    BlockSpecial,
    Directory,
    FIFO,
    ContiguousFile,
    PaxInterexchangeFormat,
    PaxExtendedAttributes,
    VendorSpecific
}

#[derive(Debug,PartialEq,Eq)]
pub enum ExtraHeader<'a> {
    UStar(UStarHeader<'a>),
    Padding
}

#[derive(Debug,PartialEq,Eq)]
pub struct UStarHeader<'a> {
    pub magic:    &'a str,
    pub version:  &'a str,
    pub uname:    &'a str,
    pub gname:    &'a str,
    pub devmajor: u64,
    pub devminor: u64,
    pub extra:    UStarExtraHeader<'a>
}

#[derive(Debug,PartialEq,Eq)]
pub enum UStarExtraHeader<'a> {
    PosixUStar(PosixUStarHeader<'a>),
    Pax(PaxHeader<'a>)
}

#[derive(Debug,PartialEq,Eq)]
pub struct PosixUStarHeader<'a> {
    pub prefix: &'a str
}

#[derive(Debug,PartialEq,Eq)]
pub struct PaxHeader<'a> {
    pub atime:      u64,
    pub ctime:      u64,
    pub offset:     u64,
    pub longnames:  &'a str,
    pub sparse:     [Sparse; 4],
    pub isextended: bool,
    pub realsize:   u64
}

#[derive(Debug,PartialEq,Eq,Clone,Copy)]
pub struct Sparse {
    pub offset:   u64,
    pub numbytes: u64
}

#[derive(Debug,PartialEq,Eq)]
pub struct Padding;

/*
 * Useful macros
 */

macro_rules! take_str_eat_garbage (
    ( $i:expr, $size:expr ) => (
        chain!($i,
            s: map_res!(take_until!("\0"), from_utf8) ~
            take!($size - s.len()),
            ||{
                s
            }
        )
    );
);

named!(parse_str4<&[u8], &str>, take_str_eat_garbage!(4));
named!(parse_str8<&[u8], &str>, take_str_eat_garbage!(8));
named!(parse_str32<&[u8], &str>, take_str_eat_garbage!(32));
named!(parse_str100<&[u8], &str>, take_str_eat_garbage!(100));
named!(parse_str155<&[u8], &str>, take_str_eat_garbage!(155));

/*
 * Octal string parsing
 */

pub fn octal_to_u64(s: &str) -> Result<u64, &'static str> {
    let mut u = 0;

    for c in s.chars() {
        if c < '0' || c > '7' {
            return Err("invalid octal string received");
        }
        u *= 8;
        u += (c as u64) - ('0' as u64);
    }

    Ok(u)
}

fn parse_octal(i: &[u8], n: usize) -> IResult<&[u8], u64> {
    map_res!(i, take_str_eat_garbage!(n), octal_to_u64)
}

named!(parse_octal8<&[u8], u64>, apply!(parse_octal, 8));
named!(parse_octal12<&[u8], u64>, apply!(parse_octal, 12));

/*
 * TypeFlag parsing
 */

fn char_to_type_flag(c: char) -> TypeFlag {
    match c {
        '0' | '\0' => TypeFlag::NormalFile,
        '1' => TypeFlag::HardLink,
        '2' => TypeFlag::SymbolicLink,
        '3' => TypeFlag::CharacterSpecial,
        '4' => TypeFlag::BlockSpecial,
        '5' => TypeFlag::Directory,
        '6' => TypeFlag::FIFO,
        '7' => TypeFlag::ContiguousFile,
        'g' => TypeFlag::PaxInterexchangeFormat,
        'x' => TypeFlag::PaxExtendedAttributes,
        'A' ... 'Z' => TypeFlag::VendorSpecific,
        _ => TypeFlag::NormalFile
    }
}

fn bytes_to_type_flag(i: &[u8]) -> Result<TypeFlag, &'static str> {
    Ok(char_to_type_flag(i[0] as char))
}

named!(parse_type_flag<&[u8], TypeFlag>, map_res!(take!(1), bytes_to_type_flag));

/*
 * Sparse parsing
 */

fn parse_one_sparse(i: &[u8]) -> IResult<&[u8], Sparse> {
    chain!(i,
        offset:   parse_octal12 ~
        numbytes: parse_octal12,
        ||{
            Sparse {
                offset:   offset,
                numbytes: numbytes
            }
        }
    )
}

fn parse_sparse(i: &[u8]) -> IResult<&[u8], [Sparse; 4]> {
    count!(i, parse_one_sparse, Sparse, 4)
}

/*
 * Boolean parsing
 */

fn to_bool(i: &[u8]) -> Result<bool, &'static str> {
    Ok(i[0] != 0)
}

named!(parse_bool<&[u8], bool>, map_res!(take!(1), to_bool));

/*
 * UStar PAX extended parsing
 */

fn parse_ustar00_extra_pax(i: &[u8]) -> IResult<&[u8], UStarExtraHeader> {
    chain!(i,
        atime:      parse_octal12 ~
        ctime:      parse_octal12 ~
        offset:     parse_octal12 ~
        longnames:  parse_str4    ~
        take!(1)                  ~
        sparse:     parse_sparse  ~
        isextended: parse_bool    ~
        realsize:   parse_octal12 ~
        take!(17), /* padding to 512 */
        ||{
            UStarExtraHeader::Pax(PaxHeader {
                atime:      atime,
                ctime:      ctime,
                offset:     offset,
                longnames:  longnames,
                sparse:     sparse,
                isextended: isextended,
                realsize:   realsize
            })
        }
    )
}

/*
 * UStar Posix parsing
 */

fn parse_ustar00_extra_posix(i: &[u8]) -> IResult<&[u8], UStarExtraHeader> {
    chain!(i,
        prefix: parse_str155 ~
        take!(12),
        ||{
            UStarExtraHeader::PosixUStar(PosixUStarHeader {
                prefix: prefix
            })
        }
    )
}

fn parse_ustar00_extra(i: &[u8], flag: TypeFlag) -> IResult<&[u8], UStarExtraHeader> {
    match flag {
        TypeFlag::PaxInterexchangeFormat => parse_ustar00_extra_pax(i),
        _ => parse_ustar00_extra_posix(i)
    }
}

fn parse_ustar00(i: &[u8], flag: TypeFlag) -> IResult<&[u8], ExtraHeader> {
    chain!(i,
        tag!("00")             ~
        uname:    parse_str32  ~
        gname:    parse_str32  ~
        devmajor: parse_octal8 ~
        devminor: parse_octal8 ~
        extra:    apply!(parse_ustar00_extra, flag),
        ||{
            ExtraHeader::UStar(UStarHeader {
                magic:    "ustar\0",
                version:  "00",
                uname:    uname,
                gname:    gname,
                devmajor: devmajor,
                devminor: devminor,
                extra:    extra
            })
        }
    )
}

fn parse_ustar(i: &[u8], flag: TypeFlag) -> IResult<&[u8], ExtraHeader> {
    chain!(i,
        tag!("ustar\0") ~
        ustar: apply!(parse_ustar00, flag),
        ||{
            ustar
        }
    )
}

/*
 * Posix tar archive header parsing
 */

fn parse_posix(i: &[u8]) -> IResult<&[u8], ExtraHeader> {
    chain!(i,
        take!(255), /* padding to 512 */
        ||{
            ExtraHeader::Padding
        }
    )
}

fn parse_header(i: &[u8]) -> IResult<&[u8], PosixHeader> {
    chain!(i,
        name:     parse_str100    ~
        mode:     parse_str8      ~
        uid:      parse_octal8    ~
        gid:      parse_octal8    ~
        size:     parse_octal12   ~
        mtime:    parse_octal12   ~
        chksum:   parse_str8      ~
        typeflag: parse_type_flag ~
        linkname: parse_str100    ~
        ustar:    alt!(apply!(parse_ustar, typeflag) | parse_posix),
        ||{
            PosixHeader {
                name:     name,
                mode:     mode,
                uid:      uid,
                gid:      gid,
                size:     size,
                mtime:    mtime,
                chksum:   chksum,
                typeflag: typeflag,
                linkname: linkname,
                ustar:    ustar
            }
        }
    )
}

/*
 * Contents parsing
 */

fn parse_contents(i: &[u8], size: u64) -> IResult<&[u8], &str> {
    let trailing = size % 512;
    let padding = match trailing {
        0 => 0,
        t => 512 - t
    };
    chain!(i,
        contents: take_str!(size as usize) ~
        take!(padding as usize),
        ||{
            contents
        }
    )
}

/*
 * Tar entry header + contents parsing
 */

fn parse_entry(i: &[u8]) -> IResult<&[u8], TarEntry> {
    chain!(i,
        header:   parse_header ~
        contents: apply!(parse_contents, header.size),
        ||{
            TarEntry {
                header: header,
                contents: contents
            }
        }
    )
}

/*
 * Tar archive parsing
 */

fn filter_entries(entries: Vec<TarEntry>) -> Result<Vec<TarEntry>, &'static str> {
    /* Filter out empty entries */
    Ok(entries.into_iter().filter(|e| e.header.name != "").collect::<Vec<TarEntry>>())
}

// TODO: eof
pub fn parse_tar(i: &[u8]) -> IResult<&[u8], Vec<TarEntry>> {
    map_res!(i, many0!(parse_entry), filter_entries)
}

/*
 * Tests
 */

#[cfg(test)]
mod tests {
    use super::*;
    use std::str::from_utf8;
    use nom::IResult;

    #[test]
    fn octal_to_u64_ok_test() {
        assert_eq!(octal_to_u64("756"), Ok(494));
        assert_eq!(octal_to_u64(""), Ok(0));
    }

    #[test]
    fn octal_to_u64_error_test() {
        assert_eq!(octal_to_u64("1238"), Err("invalid octal string received"));
        assert_eq!(octal_to_u64("a"), Err("invalid octal string received"));
        assert_eq!(octal_to_u64("A"), Err("invalid octal string received"));
    }

    #[test]
    fn take_str_eat_garbage_test() {
        let s = b"foobar\0\0\0\0baz";
        let baz = b"baz";
        assert_eq!(take_str_eat_garbage!(&s[..], 10), IResult::Done(&baz[..], "foobar"));
    }
}
<|endoftext|>


<commit_before>extern crate r2pipe;

use std::io;
use std::io::prelude::*;
use self::r2pipe::R2Pipe;

pub struct Radeco {
    filename: String,
    r2p: Option<R2Pipe>,
}

impl Radeco {
    /* TODO: use readline, dietline or any other rust-friendly prompt library */
    pub fn shell(&mut self) -> bool {
        println!("shellify {:?}", self.filename);
        let mut stdin = io::stdin();
        'mainloop: loop {
            let mut input = String::new();
            print!("> ");
            io::stdout().flush().ok();
            stdin.read_line(&mut input).ok();
            if input == "" || input == "exit\n" {
                break 'mainloop;
            }
            match self.r2p.as_mut() {
                Some(p) => println!("{}", p.cmd(input.trim())),
                None => println!("No r2p")
            }
        }
        true
    }

    pub fn close(&mut self) -> bool {
        match self.r2p.as_mut() {
            Some(p) => p.close(),
            None => println!("")
        }
        true
    }

    pub fn file(filename: String) -> Result<Radeco,&'static str> {
        let mut r = Radeco{filename: filename.to_owned(), r2p: None};
	let r2p = R2Pipe::spawn (&*filename).unwrap();
	r.r2p = Some(r2p);
        // Err("[r2pipe] initialization error")
        Ok(r)
    }

    pub fn pipe() -> Result<Radeco,&'static str> {
        let mut r = Radeco{filename: "".to_owned(), r2p: None};
	let r2p = R2Pipe::open ().unwrap();
	r.r2p = Some(r2p);
        // Err("[r2pipe] initialization error")
        Ok(r)
    }
}
<commit_msg>Update for radeco-lib::r2<commit_after>extern crate r2pipe;
extern crate radeco_lib;

use std::io;
use std::io::prelude::*;
use self::r2pipe::R2Pipe;
use self::radeco_lib::frontend::r2::R2;

pub struct Radeco {
    filename: String,
    r2p: Option<R2Pipe>,
    r2p2: Option<R2>,
}

impl Radeco {
    /* TODO: use readline, dietline or any other rust-friendly prompt library */
    pub fn shell(&mut self) -> bool {
        println!("shellify {:?}", self.filename);
        let mut stdin = io::stdin();
        'mainloop: loop {
            let mut input = String::new();
            print!("> ");
            io::stdout().flush().ok();
            stdin.read_line(&mut input).ok();
            if input == "" || input == "exit\n" {
                break 'mainloop;
            }
            match self.r2p.as_mut() {
                Some(p) => println!("{}", p.cmd(input.trim())),
                None => println!("No r2p")
            }
        }
        true
    }

    pub fn close(&mut self) -> bool {
        match self.r2p.as_mut() {
            Some(p) => p.close(),
            None => println!("")
        }
        true
    }

    pub fn file(filename: String) -> Result<Radeco,&'static str> {
        let mut r = Radeco{filename: filename.to_owned(), r2p: None, r2p2: None};
	let r2p = R2Pipe::spawn (&*filename).unwrap();
	r.r2p = Some(r2p);
        // Err("[r2pipe] initialization error")
        Ok(r)
    }

    pub fn pipe() -> Result<Radeco,&'static str> {
        let mut r = Radeco{filename: "".to_owned(), r2p: None, r2p2: None};
	let r2p = R2Pipe::open ().unwrap();
	r.r2p = Some(r2p);
        // Err("[r2pipe] initialization error")
        Ok(r)
    }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::convert::{From, Into};
use std::error::Error as StdError;
use std::fmt;
use std::io;
use std::result::Result as StdResult;
use std::str::Utf8Error;

use httparse;
use mio;
#[cfg(feature = "ssl")]
use openssl::ssl::{Error as SslError, HandshakeError as SslHandshakeError};
#[cfg(feature = "nativetls")]
use native_tls::{Error as SslError, HandshakeError as SslHandshakeError};
#[cfg(any(feature = "ssl", feature = "nativetls"))]
type HandshakeError = SslHandshakeError<mio::tcp::TcpStream>;

use communication::Command;

pub type Result<T> = StdResult<T, Error>;

/// The type of an error, which may indicate other kinds of errors as the underlying cause.
#[derive(Debug)]
pub enum Kind {
    /// Indicates an internal application error.
    /// If panic_on_internal is true, which is the default, then the application will panic.
    /// Otherwise the WebSocket will automatically attempt to send an Error (1011) close code.
    Internal,
    /// Indicates a state where some size limit has been exceeded, such as an inability to accept
    /// any more new connections.
    /// If a Connection is active, the WebSocket will automatically attempt to send
    /// a Size (1009) close code.
    Capacity,
    /// Indicates a violation of the WebSocket protocol.
    /// The WebSocket will automatically attempt to send a Protocol (1002) close code, or if
    /// this error occurs during a handshake, an HTTP 400 response will be generated.
    Protocol,
    /// Indicates that the WebSocket received data that should be utf8 encoded but was not.
    /// The WebSocket will automatically attempt to send a Invalid Frame Payload Data (1007) close
    /// code.
    Encoding(Utf8Error),
    /// Indicates an underlying IO Error.
    /// This kind of error will result in a WebSocket Connection disconnecting.
    Io(io::Error),
    /// Indicates a failure to parse an HTTP message.
    /// This kind of error should only occur during a WebSocket Handshake, and a HTTP 500 response
    /// will be generated.
    Http(httparse::Error),
    /// Indicates a failure to send a signal on the internal EventLoop channel. This means that
    /// the WebSocket is overloaded. In order to avoid this error, it is important to set
    /// `Settings::max_connections` and `Settings:queue_size` high enough to handle the load.
    /// If encountered, retuning from a handler method and waiting for the EventLoop to consume
    /// the queue may relieve the situation.
    Queue(mio::channel::SendError<Command>),
    /// Indicates a failure to perform SSL encryption.
    #[cfg(any(feature = "ssl", feature = "nativetls"))]
    Ssl(SslError),
    /// Indicates a failure to perform SSL encryption.
    #[cfg(any(feature = "ssl", feature = "nativetls"))]
    SslHandshake(HandshakeError),
    /// A custom error kind for use by applications. This error kind involves extra overhead
    /// because it will allocate the memory on the heap. The WebSocket ignores such errors by
    /// default, simply passing them to the Connection Handler.
    Custom(Box<StdError + Send + Sync>),
}

/// A struct indicating the kind of error that has occurred and any precise details of that error.
pub struct Error {
    pub kind: Kind,
    pub details: Cow<'static, str>,
}

impl Error {
    pub fn new<I>(kind: Kind, details: I) -> Error
    where
        I: Into<Cow<'static, str>>,
    {
        Error {
            kind,
            details: details.into(),
        }
    }

    pub fn into_box(self) -> Box<StdError> {
        match self.kind {
            Kind::Custom(err) => err,
            _ => Box::new(self),
        }
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.details.len() > 0 {
            write!(f, "WS Error <{:?}>: {}", self.kind, self.details)
        } else {
            write!(f, "WS Error <{:?}>", self.kind)
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.details.len() > 0 {
            write!(f, "{}: {}", self.description(), self.details)
        } else {
            write!(f, "{}", self.description())
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self.kind {
            Kind::Internal => "Internal Application Error",
            Kind::Capacity => "WebSocket at Capacity",
            Kind::Protocol => "WebSocket Protocol Error",
            Kind::Encoding(ref err) => err.description(),
            Kind::Io(ref err) => err.description(),
            Kind::Http(_) => "Unable to parse HTTP",
            #[cfg(any(feature = "ssl", feature = "nativetls"))]
            Kind::Ssl(ref err) => err.description(),
            #[cfg(any(feature = "ssl", feature = "nativetls"))]
            Kind::SslHandshake(ref err) => err.description(),
            Kind::Queue(_) => "Unable to send signal on event loop",
            Kind::Custom(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match self.kind {
            Kind::Encoding(ref err) => Some(err),
            Kind::Io(ref err) => Some(err),
            #[cfg(any(feature = "ssl", feature = "nativetls"))]
            Kind::Ssl(ref err) => Some(err),
            #[cfg(any(feature = "ssl", feature = "nativetls"))]
            Kind::SslHandshake(ref err) => err.cause(),
            Kind::Custom(ref err) => Some(err.as_ref()),
            _ => None,
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::new(Kind::Io(err), "")
    }
}

impl From<httparse::Error> for Error {
    fn from(err: httparse::Error) -> Error {
        let details = match err {
            httparse::Error::HeaderName => "Invalid byte in header name.",
            httparse::Error::HeaderValue => "Invalid byte in header value.",
            httparse::Error::NewLine => "Invalid byte in new line.",
            httparse::Error::Status => "Invalid byte in Response status.",
            httparse::Error::Token => "Invalid byte where token is required.",
            httparse::Error::TooManyHeaders => {
                "Parsed more headers than provided buffer can contain."
            }
            httparse::Error::Version => "Invalid byte in HTTP version.",
        };

        Error::new(Kind::Http(err), details)
    }
}

impl From<mio::channel::SendError<Command>> for Error {
    fn from(err: mio::channel::SendError<Command>) -> Error {
        match err {
            mio::channel::SendError::Io(err) => Error::from(err),
            _ => Error::new(Kind::Queue(err), ""),
        }
    }
}

impl From<Utf8Error> for Error {
    fn from(err: Utf8Error) -> Error {
        Error::new(Kind::Encoding(err), "")
    }
}

#[cfg(any(feature = "ssl", feature = "nativetls"))]
impl From<SslError> for Error {
    fn from(err: SslError) -> Error {
        Error::new(Kind::Ssl(err), "")
    }
}

#[cfg(any(feature = "ssl", feature = "nativetls"))]
impl From<HandshakeError> for Error {
    fn from(err: HandshakeError) -> Error {
        Error::new(Kind::SslHandshake(err), "")
    }
}

impl<B> From<Box<B>> for Error
where
    B: StdError + Send + Sync + 'static,
{
    fn from(err: Box<B>) -> Error {
        Error::new(Kind::Custom(err), "")
    }
}
<commit_msg>Silence three warnings<commit_after>use std::borrow::Cow;
use std::convert::{From, Into};
use std::error::Error as StdError;
use std::fmt;
use std::io;
use std::result::Result as StdResult;
use std::str::Utf8Error;

use httparse;
use mio;
#[cfg(feature = "ssl")]
use openssl::ssl::{Error as SslError, HandshakeError as SslHandshakeError};
#[cfg(feature = "nativetls")]
use native_tls::{Error as SslError, HandshakeError as SslHandshakeError};
#[cfg(any(feature = "ssl", feature = "nativetls"))]
type HandshakeError = SslHandshakeError<mio::tcp::TcpStream>;

use communication::Command;

pub type Result<T> = StdResult<T, Error>;

/// The type of an error, which may indicate other kinds of errors as the underlying cause.
#[derive(Debug)]
pub enum Kind {
    /// Indicates an internal application error.
    /// If panic_on_internal is true, which is the default, then the application will panic.
    /// Otherwise the WebSocket will automatically attempt to send an Error (1011) close code.
    Internal,
    /// Indicates a state where some size limit has been exceeded, such as an inability to accept
    /// any more new connections.
    /// If a Connection is active, the WebSocket will automatically attempt to send
    /// a Size (1009) close code.
    Capacity,
    /// Indicates a violation of the WebSocket protocol.
    /// The WebSocket will automatically attempt to send a Protocol (1002) close code, or if
    /// this error occurs during a handshake, an HTTP 400 response will be generated.
    Protocol,
    /// Indicates that the WebSocket received data that should be utf8 encoded but was not.
    /// The WebSocket will automatically attempt to send a Invalid Frame Payload Data (1007) close
    /// code.
    Encoding(Utf8Error),
    /// Indicates an underlying IO Error.
    /// This kind of error will result in a WebSocket Connection disconnecting.
    Io(io::Error),
    /// Indicates a failure to parse an HTTP message.
    /// This kind of error should only occur during a WebSocket Handshake, and a HTTP 500 response
    /// will be generated.
    Http(httparse::Error),
    /// Indicates a failure to send a signal on the internal EventLoop channel. This means that
    /// the WebSocket is overloaded. In order to avoid this error, it is important to set
    /// `Settings::max_connections` and `Settings:queue_size` high enough to handle the load.
    /// If encountered, retuning from a handler method and waiting for the EventLoop to consume
    /// the queue may relieve the situation.
    Queue(mio::channel::SendError<Command>),
    /// Indicates a failure to perform SSL encryption.
    #[cfg(any(feature = "ssl", feature = "nativetls"))]
    Ssl(SslError),
    /// Indicates a failure to perform SSL encryption.
    #[cfg(any(feature = "ssl", feature = "nativetls"))]
    SslHandshake(HandshakeError),
    /// A custom error kind for use by applications. This error kind involves extra overhead
    /// because it will allocate the memory on the heap. The WebSocket ignores such errors by
    /// default, simply passing them to the Connection Handler.
    Custom(Box<dyn StdError + Send + Sync>),
}

/// A struct indicating the kind of error that has occurred and any precise details of that error.
pub struct Error {
    pub kind: Kind,
    pub details: Cow<'static, str>,
}

impl Error {
    pub fn new<I>(kind: Kind, details: I) -> Error
    where
        I: Into<Cow<'static, str>>,
    {
        Error {
            kind,
            details: details.into(),
        }
    }

    pub fn into_box(self) -> Box<dyn StdError> {
        match self.kind {
            Kind::Custom(err) => err,
            _ => Box::new(self),
        }
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.details.len() > 0 {
            write!(f, "WS Error <{:?}>: {}", self.kind, self.details)
        } else {
            write!(f, "WS Error <{:?}>", self.kind)
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.details.len() > 0 {
            write!(f, "{}: {}", self.description(), self.details)
        } else {
            write!(f, "{}", self.description())
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self.kind {
            Kind::Internal => "Internal Application Error",
            Kind::Capacity => "WebSocket at Capacity",
            Kind::Protocol => "WebSocket Protocol Error",
            Kind::Encoding(ref err) => err.description(),
            Kind::Io(ref err) => err.description(),
            Kind::Http(_) => "Unable to parse HTTP",
            #[cfg(any(feature = "ssl", feature = "nativetls"))]
            Kind::Ssl(ref err) => err.description(),
            #[cfg(any(feature = "ssl", feature = "nativetls"))]
            Kind::SslHandshake(ref err) => err.description(),
            Kind::Queue(_) => "Unable to send signal on event loop",
            Kind::Custom(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&dyn StdError> {
        match self.kind {
            Kind::Encoding(ref err) => Some(err),
            Kind::Io(ref err) => Some(err),
            #[cfg(any(feature = "ssl", feature = "nativetls"))]
            Kind::Ssl(ref err) => Some(err),
            #[cfg(any(feature = "ssl", feature = "nativetls"))]
            Kind::SslHandshake(ref err) => err.cause(),
            Kind::Custom(ref err) => Some(err.as_ref()),
            _ => None,
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::new(Kind::Io(err), "")
    }
}

impl From<httparse::Error> for Error {
    fn from(err: httparse::Error) -> Error {
        let details = match err {
            httparse::Error::HeaderName => "Invalid byte in header name.",
            httparse::Error::HeaderValue => "Invalid byte in header value.",
            httparse::Error::NewLine => "Invalid byte in new line.",
            httparse::Error::Status => "Invalid byte in Response status.",
            httparse::Error::Token => "Invalid byte where token is required.",
            httparse::Error::TooManyHeaders => {
                "Parsed more headers than provided buffer can contain."
            }
            httparse::Error::Version => "Invalid byte in HTTP version.",
        };

        Error::new(Kind::Http(err), details)
    }
}

impl From<mio::channel::SendError<Command>> for Error {
    fn from(err: mio::channel::SendError<Command>) -> Error {
        match err {
            mio::channel::SendError::Io(err) => Error::from(err),
            _ => Error::new(Kind::Queue(err), ""),
        }
    }
}

impl From<Utf8Error> for Error {
    fn from(err: Utf8Error) -> Error {
        Error::new(Kind::Encoding(err), "")
    }
}

#[cfg(any(feature = "ssl", feature = "nativetls"))]
impl From<SslError> for Error {
    fn from(err: SslError) -> Error {
        Error::new(Kind::Ssl(err), "")
    }
}

#[cfg(any(feature = "ssl", feature = "nativetls"))]
impl From<HandshakeError> for Error {
    fn from(err: HandshakeError) -> Error {
        Error::new(Kind::SslHandshake(err), "")
    }
}

impl<B> From<Box<B>> for Error
where
    B: StdError + Send + Sync + 'static,
{
    fn from(err: Box<B>) -> Error {
        Error::new(Kind::Custom(err), "")
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::hashmap::{Occupied, Vacant};
use http::method::Method;
use http::method;
use iron::{Request, Response, Handler, IronResult, Error, IronError};
use iron::status;
use typemap::Assoc;
use recognizer::Router as Recognizer;
use recognizer::{Match, Params};

/// `Router` provides an interface for creating complex routes as middleware
/// for the Iron framework.
pub struct Router {
    // The routers, specialized by method.
    routers: HashMap<Method, Recognizer<Box<Handler + Send + Sync>>>,
    error: Option<Box<Handler + Send + Sync>>
}

#[deriving(Show)]
/// The error thrown by router if there is no matching route.
pub struct NoRoute;

impl Error for NoRoute {
    fn name(&self) -> &'static str { "No Route" }
}

impl Router {
    /// `new` constructs a new, blank `Router`.
    pub fn new() -> Router { Router { routers: HashMap::new(), error: None } }
    /// Add a new route to a `Router`, matching both a method and glob pattern.
    ///
    /// `route` supports glob patterns: `*` for a single wildcard segment and
    /// `:param` for matching storing that segment of the request url in the `Params`
    /// object, which is stored in the request `extensions`.
    ///
    /// For instance, to route `Get` requests on any route matching
    /// `/users/:userid/:friend` and store `userid` and `friend` in
    /// the exposed Params object:
    ///
    /// ```ignore
    /// router.route(http::method::Get, "/users/:userid/:friendid", controller);
    /// ```
    ///
    /// The controller provided to route can be any `Middleware`, which allows
    /// extreme flexibility when handling routes. For instance, you could provide
    /// a `Chain`, a `Middleware`, which contains an authorization middleware and
    /// a controller function, so that you can confirm that the request is
    /// authorized for this route before handling it.
    pub fn route<'a, H: Handler, S: Str>(&mut self, method: Method, glob: S, handler: H) -> &mut Router {
        match self.routers
            .entry(method) {
                Vacant(entry)   => entry.set(Recognizer::new()),
                Occupied(entry) => entry.into_mut()
            }
        .add(glob.as_slice(), box handler as Box<Handler + Send + Sync>);
        self
    }

    /// Like route, but specialized to the `Get` method.
    pub fn get<'a, H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Get, glob, handler)
    }

    /// Like route, but specialized to the `Post` method.
    pub fn post<'a, H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Post, glob, handler)
    }

    /// Like route, but specialized to the `Put` method.
    pub fn put<'a, H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Put, glob, handler)
    }

    /// Like route, but specialized to the `Delete` method.
    pub fn delete<'a, H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Delete, glob, handler)
    }

    /// Like route, but specialized to the `Head` method.
    pub fn head<'a, H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Head, glob, handler)
    }

    /// Like route, but specialized to the `Patch` method.
    pub fn patch<'a, H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Patch, glob, handler)
    }

    /// Like route, but specialized to the `Options` method.
    pub fn options<'a, H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Options, glob, handler)
    }

    /// Add a Handler to be used for this Router's `catch` method.
    pub fn error<H: Handler>(&mut self, handler: H) -> &mut Router {
        self.error = Some(box handler as Box<Handler + Send + Sync>);
        self
    }

    fn recognize<'a>(&'a self, method: &Method, path: &str)
                     -> Option<Match<&'a Box<Handler + Send + Sync>>> {
        self.routers.find(method).and_then(|router| router.recognize(path).ok())
    }
}

impl Assoc<Params> for Router {}

impl Handler for Router {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        let matched = match self.recognize(&req.method, req.url.path.connect("/").as_slice()) {
            Some(matched) => matched,
            // No match.
            None => return Err(NoRoute.abstract())
        };

        req.extensions.insert::<Router, Params>(matched.params);
        matched.handler.call(req)
    }

    fn catch(&self, req: &mut Request, err: IronError) -> (Response, IronResult<()>) {
        match self.error {
            Some(ref error_handler) => error_handler.catch(req, err),
            // Error that is not caught by anything!
            None => (Response::status(status::InternalServerError), Err(err))
        }
    }
}
<commit_msg>Format the match expression.<commit_after>use std::collections::HashMap;
use std::collections::hashmap::{Occupied, Vacant};
use http::method::Method;
use http::method;
use iron::{Request, Response, Handler, IronResult, Error, IronError};
use iron::status;
use typemap::Assoc;
use recognizer::Router as Recognizer;
use recognizer::{Match, Params};

/// `Router` provides an interface for creating complex routes as middleware
/// for the Iron framework.
pub struct Router {
    // The routers, specialized by method.
    routers: HashMap<Method, Recognizer<Box<Handler + Send + Sync>>>,
    error: Option<Box<Handler + Send + Sync>>
}

#[deriving(Show)]
/// The error thrown by router if there is no matching route.
pub struct NoRoute;

impl Error for NoRoute {
    fn name(&self) -> &'static str { "No Route" }
}

impl Router {
    /// `new` constructs a new, blank `Router`.
    pub fn new() -> Router { Router { routers: HashMap::new(), error: None } }
    /// Add a new route to a `Router`, matching both a method and glob pattern.
    ///
    /// `route` supports glob patterns: `*` for a single wildcard segment and
    /// `:param` for matching storing that segment of the request url in the `Params`
    /// object, which is stored in the request `extensions`.
    ///
    /// For instance, to route `Get` requests on any route matching
    /// `/users/:userid/:friend` and store `userid` and `friend` in
    /// the exposed Params object:
    ///
    /// ```ignore
    /// router.route(http::method::Get, "/users/:userid/:friendid", controller);
    /// ```
    ///
    /// The controller provided to route can be any `Middleware`, which allows
    /// extreme flexibility when handling routes. For instance, you could provide
    /// a `Chain`, a `Middleware`, which contains an authorization middleware and
    /// a controller function, so that you can confirm that the request is
    /// authorized for this route before handling it.
    pub fn route<'a, H: Handler, S: Str>(&mut self, method: Method, glob: S, handler: H) -> &mut Router {
        match self.routers.entry(method) {
            Vacant(entry)   => entry.set(Recognizer::new()),
            Occupied(entry) => entry.into_mut()
        }.add(glob.as_slice(), box handler as Box<Handler + Send + Sync>);
        self
    }

    /// Like route, but specialized to the `Get` method.
    pub fn get<'a, H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Get, glob, handler)
    }

    /// Like route, but specialized to the `Post` method.
    pub fn post<'a, H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Post, glob, handler)
    }

    /// Like route, but specialized to the `Put` method.
    pub fn put<'a, H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Put, glob, handler)
    }

    /// Like route, but specialized to the `Delete` method.
    pub fn delete<'a, H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Delete, glob, handler)
    }

    /// Like route, but specialized to the `Head` method.
    pub fn head<'a, H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Head, glob, handler)
    }

    /// Like route, but specialized to the `Patch` method.
    pub fn patch<'a, H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Patch, glob, handler)
    }

    /// Like route, but specialized to the `Options` method.
    pub fn options<'a, H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Options, glob, handler)
    }

    /// Add a Handler to be used for this Router's `catch` method.
    pub fn error<H: Handler>(&mut self, handler: H) -> &mut Router {
        self.error = Some(box handler as Box<Handler + Send + Sync>);
        self
    }

    fn recognize<'a>(&'a self, method: &Method, path: &str)
                     -> Option<Match<&'a Box<Handler + Send + Sync>>> {
        self.routers.find(method).and_then(|router| router.recognize(path).ok())
    }
}

impl Assoc<Params> for Router {}

impl Handler for Router {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        let matched = match self.recognize(&req.method, req.url.path.connect("/").as_slice()) {
            Some(matched) => matched,
            // No match.
            None => return Err(NoRoute.abstract())
        };

        req.extensions.insert::<Router, Params>(matched.params);
        matched.handler.call(req)
    }

    fn catch(&self, req: &mut Request, err: IronError) -> (Response, IronResult<()>) {
        match self.error {
            Some(ref error_handler) => error_handler.catch(req, err),
            // Error that is not caught by anything!
            None => (Response::status(status::InternalServerError), Err(err))
        }
    }
}
<|endoftext|>