<commit_before>use std::os::raw::{c_int, c_double, c_void};
use std::{ptr, slice};

use ffi;
use base::*;

macro_rules! write_stream {
    ($name:ident, $t:ty) => (
        /// Expects a vector of `channel_count` channel `buffers`
        /// containing audio data that are written into
        /// the output device buffer.
        /// Returns the number of actually written frames.
        /// If the provided buffers contain less frames
        /// than `min_frame_count`, or less buffers
        /// as `channel_count` are provided,
        /// then a `ffi::SioError::Invalid` is returned.
        pub fn $name(&self, min_frame_count: i32, buffers: &Vec<Vec<$t>>) -> SioResult<i32> {
            let channel_count = self.get_layout().channel_count();
            // check if buffer contains frames for all channels
            if buffers.len() < channel_count as usize {
                return Err(ffi::SioError::Invalid);
            }
            // check if there are at least min_frame_count frames for all channels
            if !buffers.iter().map(|c| c.len()).all(|l| l >= min_frame_count as usize) {
                return Err(ffi::SioError::Invalid);
            }

            // assuming that every channel buffer has the same length
            let mut frame_count = buffers[0].len() as c_int;
            let mut raw_areas: *mut ffi::SoundIoChannelArea = ptr::null_mut();
            let actual_frame_count = try!(self.begin_write(&mut raw_areas, &frame_count));
            let areas = unsafe { slice::from_raw_parts_mut(raw_areas, channel_count as usize) };
            for idx in 0..actual_frame_count as usize {
                for channel in 0..channel_count as usize {
                    let area = areas[channel];
                    let addr = (area.ptr as usize + area.step as usize * idx) as *mut $t;
                    unsafe { *addr = buffers[channel][idx] }
                }
            }
            self.end_write().map_or(Ok(actual_frame_count), |err| Err(err))
        }
    )
}

extern "C" fn write_wrapper<W>(raw_out: *mut ffi::SoundIoOutStream, min: c_int, max: c_int)
    where W: Fn(OutStream, i32, i32)
{
    let out = OutStream::new(raw_out);
    let callbacks_ptr = unsafe { (*out.stream).userdata as *const Box<OutStreamCallbacks> };
    let callbacks: &Box<OutStreamCallbacks> = unsafe { &*callbacks_ptr };
    callbacks.write.as_ref().map(|ref f| f(out, min as i32, max as i32));
}

extern "C" fn underflow_wrapper<U>(raw_out: *mut ffi::SoundIoOutStream)
    where U: Fn(OutStream)
{
    let out = OutStream::new(raw_out);
    let callbacks_ptr = unsafe { (*out.stream).userdata as *const Box<OutStreamCallbacks> };
    let callbacks: &Box<OutStreamCallbacks> = unsafe { &*callbacks_ptr };
    callbacks.underflow.as_ref().map(|ref f| f(out));
}

extern "C" fn error_wrapper<E>(raw_out: *mut ffi::SoundIoOutStream, error: ffi::SioError)
    where E: Fn(OutStream, ffi::SioError)
{
    let out = OutStream::new(raw_out);
    let callbacks_ptr = unsafe { (*out.stream).userdata as *const Box<OutStreamCallbacks> };
    let callbacks: &Box<OutStreamCallbacks> = unsafe { &*callbacks_ptr };
    callbacks.error.as_ref().map(|ref f| f(out, error));
}

struct OutStreamCallbacks<'a> {
    write: Option<Box<Fn(OutStream, i32, i32) + 'a>>,
    underflow: Option<Box<Fn(OutStream) + 'a>>,
    error: Option<Box<Fn(OutStream, ffi::SioError) + 'a>>,
}
impl<'a> Default for OutStreamCallbacks<'a> {
    fn default() -> Self {
        OutStreamCallbacks {
            write: None,
            underflow: None,
            error: None,
        }
    }
}
impl<'a> Drop for OutStreamCallbacks<'a> {
    fn drop(&mut self) {}
}

/// An audio output stream, returned from a `Device`.
pub struct OutStream<'a> {
    stream: *mut ffi::SoundIoOutStream,
    callbacks: Box<OutStreamCallbacks<'a>>,
}
impl<'a> OutStream<'a> {
    pub fn new(raw_stream: *mut ffi::SoundIoOutStream) -> Self {
        let callbacks = Box::new(OutStreamCallbacks::default());
        OutStream {
            stream: raw_stream,
            callbacks: callbacks,
        }
    }

    /// Change settings (e.g. `set_format`) **before** calling `open`.
    /// After you call this function, `OutStream::software_latency` is set to
    /// the correct value.
    ///
    /// The next thing to do is call `outstream_start`.
    /// If this function returns an error, the outstream is in an invalid state and
    /// you must call `destroy` on it.
    ///
    /// Possible errors:
    ///
    /// - `ffi::SioErrorInvalid`
    ///     - device is not an *output* device
    ///     - format is not valid
    ///     - `channel_count` is greater than 24
    /// - `ffi::SioError::NoMem`
    /// - `ffi::SioError::OpeningDevice`
    /// - `ffi::SioError::BackendDisconnected`
    /// - `ffi::SioError::SystemResources`
    /// - `ffi::SioError::NoSuchClient` - when JACK returns `JackNoSuchClient`
    /// - `ffi::SioErrorOpeningDevice`
    /// - `ffi::SioErrorIncompatibleBackend` - `OutStream::channel_count` is
    ///   greater than the number of channels the backend can handle.
    /// - `ffi::SioErrorIncompatibleDevice` - stream parameters requested are not
    ///   compatible with the chosen device.
    pub fn open(&self) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_outstream_open(self.stream) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    /// After you call this function, the registered `write_callback` will be called.
    ///
    /// This function might directly call the `write_callback`.
    ///
    /// Possible errors:
    ///
    /// - `ffi::SioError::Streaming`
    /// - `ffi::SioError::NoMem`
    /// - `ffi::SioError::SystemResources`
    /// - `ffi::SioError::BackendDisconnected`
    pub fn start(&self) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_outstream_start(self.stream) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    /// Registers the given callback as `write_callback` that is called as soon as you call `start`.
    ///
    /// In this callback, you call `OutStream::write_stream_FMT` where `FMT` is one of the supported
    /// format, `u16`, `f32` etc.
    ///
    /// `frame_count_max` will always be greater than 0. Note that you
    /// should write as many frames as you can; `frame_count_min` might be 0 and
    /// you can still get a buffer underflow if you always write
    /// `frame_count_min` frames.
    ///
    /// For Dummy, ALSA, and PulseAudio, `frame_count_min` will be 0. For JACK
    /// and CoreAudio `frame_count_min` will be equal to `frame_count_max`.
    ///
    /// The code in the supplied function must be suitable for real-time
    /// execution. That means that it cannot call functions that might block
    /// for a long time. This includes all I/O functions (disk, TTY, network),
    /// malloc, free, printf, pthread_mutex_lock, sleep, wait, poll, select,
    /// pthread_join, pthread_cond_wait, etc.
    pub fn register_write_callback<W>(&mut self, callback: Box<W>)
        where W: Fn(OutStream, i32, i32) + 'a
    {
        // stored box reference to callback closure
        self.callbacks.write = Some(callback);
        unsafe {
            // register wrapper for write_callback
            (*self.stream).write_callback = Some(write_wrapper::<W>);
            // store reference to callbacks struct in userdata pointer
            (*self.stream).userdata =
                &self.callbacks as *const Box<OutStreamCallbacks> as *mut c_void
        }
    }

    /// Registers the given callback as `underflow_callback`.
    /// This *optional* callback happens when the sound device runs out of buffered audio data to play.
    /// After this occurs, the outstream waits until the buffer is full to resume playback.
    /// This is called from the `OutStream::write_callback` thread context.
    pub fn register_underflow_callback<U>(&mut self, callback: Box<U>)
        where U: Fn(OutStream) + 'a
    {
        self.callbacks.underflow = Some(callback);
        unsafe {
            // register wrapper for write_callback
            (*self.stream).underflow_callback = Some(underflow_wrapper::<U>);
            // store reference to callbacks struct in userdata pointer
            (*self.stream).userdata =
                &self.callbacks as *const Box<OutStreamCallbacks> as *mut c_void
        }
    }

    /// *Optional* callback. `err` is always `ffi::SioError::ErrorStreaming`.
    /// This is an unrecoverable error. The stream is in an
    /// invalid state and must be destroyed, call `OutStream::destroy`.
    /// If you do not supply `error_callback`, the default callback will print
    /// a message to stderr and then call `abort`.
    /// This is called from the `OutStream::write_callback` thread context.
    pub fn register_error_callback<E>(&mut self, callback: Box<E>)
        where E: Fn(OutStream, ffi::SioError) + 'a
    {
        self.callbacks.error = Some(callback);
        unsafe {
            // register wrapper for write_callback
            (*self.stream).error_callback = Some(error_wrapper::<E>);
            // store reference to callbacks struct in userdata pointer
            (*self.stream).userdata =
                &self.callbacks as *const Box<OutStreamCallbacks> as *mut c_void
        }
    }

    write_stream!(write_stream_i8, i8);
    write_stream!(write_stream_u8, u8);
    write_stream!(write_stream_i16, i16);
    write_stream!(write_stream_u16, u16);
    write_stream!(write_stream_i32, i32);
    write_stream!(write_stream_u32, u32);
    write_stream!(write_stream_f32, f32);
    write_stream!(write_stream_f64, f64);

    fn begin_write(&self,
                   areas: *mut *mut ffi::SoundIoChannelArea,
                   frame_count: &i32)
                   -> SioResult<i32> {
        let mut actual_frame_count = *frame_count as c_int;
        match unsafe {
            ffi::soundio_outstream_begin_write(self.stream,
                                               areas,
                                               &mut actual_frame_count as *mut c_int)
        } {
            ffi::SioError::None => Ok(actual_frame_count),
            err @ _ => Err(err),
        }
    }

    fn end_write(&self) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_outstream_end_write(self.stream) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    /// Clears the output stream buffer.
    /// This function can be called from any thread.
    /// This function can be called regardless of whether the outstream is paused
    /// or not.
    /// Some backends do not support clearing the buffer. On these backends this
    /// function will return `ffi::SioError::IncompatibleBackend`.
    /// Some devices do not support clearing the buffer. On these devices this
    /// function might return `ffi::SioError::IncompatibleDevice`.
    /// Possible errors:
    ///
    /// - `ffi::SioError::Streaming`
    /// - `ffi::SioError::IncompatibleBackend`
    /// - `ffi::SioError::IncompatibleDevice`
    pub fn clear_buffer(&self) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_outstream_clear_buffer(self.stream) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    /// If the underlying backend and device support pausing, this pauses the
    /// stream. `OutStream::write_callback` may be called a few more times if
    /// the buffer is not full.
    /// Pausing might put the hardware into a low power state which is ideal if your
    /// software is silent for some time.
    /// This function may be called from any thread context, including
    /// `OutStream::write_callback`.
    /// Pausing when already paused or unpausing when already unpaused has no
    /// effect and returns `None`.
    ///
    /// Possible errors:
    ///
    /// - `ffi::SioError::BackendDisconnected`
    /// - `ffi::SioError::Streaming`
    /// - `ffi::SioError::IncompatibleDevice` - device does not support
    ///   pausing/unpausing. This error code might not be returned even if the
    ///   device does not support pausing/unpausing.
    /// - `ffi::SioError::IncompatibleBackend` - backend does not support
    ///   pausing/unpausing.
    /// - `ffi::SioError::Invalid` - outstream not opened and started
    pub fn pause(&self, pause: bool) -> Option<ffi::SioError> {
        let pause_c_bool = match pause {
            true => 1u8,
            false => 0u8,
        };
        match unsafe { ffi::soundio_outstream_pause(self.stream, pause_c_bool) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    /// Obtain the total number of seconds that the next frame written after the
    /// last frame written will take to become
    /// audible.
    /// This includes both software and hardware latency.
    ///
    /// This function must be called only from within `OutStream::write_callback`.
    ///
    /// Possible errors:
    ///
    /// - `ffi::SioError::Streaming`
    pub fn get_latency(&self) -> SioResult<f64> {
        let mut latency = 0.0f64;
        match unsafe {
            ffi::soundio_outstream_get_latency(self.stream, &mut latency as *mut c_double)
        } {
            ffi::SioError::None => Ok(latency),
            err @ _ => Err(err),
        }

    }

    /// Returns the current `format` or a `ffi::SioError::Invalid` if
    /// the format is not set.
    pub fn current_format(&self) -> SioResult<ffi::SioFormat> {
        match unsafe { (*self.stream).format } {
            ffi::SioFormat::Invalid => Err(ffi::SioError::Invalid),
            fmt @ _ => Ok(fmt),
        }
    }

    /// Returns the channel layout of the output stream.
    pub fn get_layout(&self) -> ChannelLayout {
        ChannelLayout::new(unsafe { &(*self.stream).layout })
    }

    /// Returns the sample rate of the output stream.
    pub fn get_sample_rate(&self) -> i32 {
        unsafe { (*self.stream).sample_rate as i32 }
    }

    /// Returns the underlying device of the output stream.
    pub fn get_device(&self) -> Device {
        let dev = Device::new(unsafe { (*self.stream).device });
        dev.inc_ref();
        dev
    }

    /// Destroys the output stream.
    /// Calls this when your application shuts down.
    /// NOTE: This can break if a callback is still active.
    pub fn destroy(&self) {
        unsafe { ffi::soundio_outstream_destroy(self.stream) }
    }
}
impl<'a> Drop for OutStream<'a> {
    fn drop(&mut self) {
        // TODO: call destroy manually.
        // OutStream will get dropped each time a new
        // struct is created from the same *mut pointer.
    }
}
<commit_msg>Implement `set_format` for OutStream<commit_after>use std::os::raw::{c_int, c_double, c_void};
use std::{ptr, slice};

use ffi;
use base::*;

macro_rules! write_stream {
    ($name:ident, $t:ty) => (
        /// Expects a vector of `channel_count` channel `buffers`
        /// containing audio data that are written into
        /// the output device buffer.
        /// Returns the number of actually written frames.
        /// If the provided buffers contain less frames
        /// than `min_frame_count`, or less buffers
        /// as `channel_count` are provided,
        /// then a `ffi::SioError::Invalid` is returned.
        pub fn $name(&self, min_frame_count: i32, buffers: &Vec<Vec<$t>>) -> SioResult<i32> {
            let channel_count = self.get_layout().channel_count();
            // check if buffer contains frames for all channels
            if buffers.len() < channel_count as usize {
                return Err(ffi::SioError::Invalid);
            }
            // check if there are at least min_frame_count frames for all channels
            if !buffers.iter().map(|c| c.len()).all(|l| l >= min_frame_count as usize) {
                return Err(ffi::SioError::Invalid);
            }

            // assuming that every channel buffer has the same length
            let mut frame_count = buffers[0].len() as c_int;
            let mut raw_areas: *mut ffi::SoundIoChannelArea = ptr::null_mut();
            let actual_frame_count = try!(self.begin_write(&mut raw_areas, &frame_count));
            let areas = unsafe { slice::from_raw_parts_mut(raw_areas, channel_count as usize) };
            for idx in 0..actual_frame_count as usize {
                for channel in 0..channel_count as usize {
                    let area = areas[channel];
                    let addr = (area.ptr as usize + area.step as usize * idx) as *mut $t;
                    unsafe { *addr = buffers[channel][idx] }
                }
            }
            self.end_write().map_or(Ok(actual_frame_count), |err| Err(err))
        }
    )
}

extern "C" fn write_wrapper<W>(raw_out: *mut ffi::SoundIoOutStream, min: c_int, max: c_int)
    where W: Fn(OutStream, i32, i32)
{
    let out = OutStream::new(raw_out);
    let callbacks_ptr = unsafe { (*out.stream).userdata as *const Box<OutStreamCallbacks> };
    let callbacks: &Box<OutStreamCallbacks> = unsafe { &*callbacks_ptr };
    callbacks.write.as_ref().map(|ref f| f(out, min as i32, max as i32));
}

extern "C" fn underflow_wrapper<U>(raw_out: *mut ffi::SoundIoOutStream)
    where U: Fn(OutStream)
{
    let out = OutStream::new(raw_out);
    let callbacks_ptr = unsafe { (*out.stream).userdata as *const Box<OutStreamCallbacks> };
    let callbacks: &Box<OutStreamCallbacks> = unsafe { &*callbacks_ptr };
    callbacks.underflow.as_ref().map(|ref f| f(out));
}

extern "C" fn error_wrapper<E>(raw_out: *mut ffi::SoundIoOutStream, error: ffi::SioError)
    where E: Fn(OutStream, ffi::SioError)
{
    let out = OutStream::new(raw_out);
    let callbacks_ptr = unsafe { (*out.stream).userdata as *const Box<OutStreamCallbacks> };
    let callbacks: &Box<OutStreamCallbacks> = unsafe { &*callbacks_ptr };
    callbacks.error.as_ref().map(|ref f| f(out, error));
}

struct OutStreamCallbacks<'a> {
    write: Option<Box<Fn(OutStream, i32, i32) + 'a>>,
    underflow: Option<Box<Fn(OutStream) + 'a>>,
    error: Option<Box<Fn(OutStream, ffi::SioError) + 'a>>,
}
impl<'a> Default for OutStreamCallbacks<'a> {
    fn default() -> Self {
        OutStreamCallbacks {
            write: None,
            underflow: None,
            error: None,
        }
    }
}
impl<'a> Drop for OutStreamCallbacks<'a> {
    fn drop(&mut self) {}
}

/// An audio output stream, returned from a `Device`.
pub struct OutStream<'a> {
    stream: *mut ffi::SoundIoOutStream,
    callbacks: Box<OutStreamCallbacks<'a>>,
}
impl<'a> OutStream<'a> {
    pub fn new(raw_stream: *mut ffi::SoundIoOutStream) -> Self {
        let callbacks = Box::new(OutStreamCallbacks::default());
        OutStream {
            stream: raw_stream,
            callbacks: callbacks,
        }
    }

    /// Change settings (e.g. `set_format`) **before** calling `open`.
    /// After you call this function, `OutStream::software_latency` is set to
    /// the correct value.
    ///
    /// The next thing to do is call `outstream_start`.
    /// If this function returns an error, the outstream is in an invalid state and
    /// you must call `destroy` on it.
    ///
    /// Possible errors:
    ///
    /// - `ffi::SioErrorInvalid`
    ///     - device is not an *output* device
    ///     - format is not valid
    ///     - `channel_count` is greater than 24
    /// - `ffi::SioError::NoMem`
    /// - `ffi::SioError::OpeningDevice`
    /// - `ffi::SioError::BackendDisconnected`
    /// - `ffi::SioError::SystemResources`
    /// - `ffi::SioError::NoSuchClient` - when JACK returns `JackNoSuchClient`
    /// - `ffi::SioErrorOpeningDevice`
    /// - `ffi::SioErrorIncompatibleBackend` - `OutStream::channel_count` is
    ///   greater than the number of channels the backend can handle.
    /// - `ffi::SioErrorIncompatibleDevice` - stream parameters requested are not
    ///   compatible with the chosen device.
    pub fn open(&self) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_outstream_open(self.stream) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    /// After you call this function, the registered `write_callback` will be called.
    ///
    /// This function might directly call the `write_callback`.
    ///
    /// Possible errors:
    ///
    /// - `ffi::SioError::Streaming`
    /// - `ffi::SioError::NoMem`
    /// - `ffi::SioError::SystemResources`
    /// - `ffi::SioError::BackendDisconnected`
    pub fn start(&self) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_outstream_start(self.stream) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    /// Registers the given callback as `write_callback` that is called as soon as you call `start`.
    ///
    /// In this callback, you call `OutStream::write_stream_FMT` where `FMT` is one of the supported
    /// format, `u16`, `f32` etc.
    ///
    /// `frame_count_max` will always be greater than 0. Note that you
    /// should write as many frames as you can; `frame_count_min` might be 0 and
    /// you can still get a buffer underflow if you always write
    /// `frame_count_min` frames.
    ///
    /// For Dummy, ALSA, and PulseAudio, `frame_count_min` will be 0. For JACK
    /// and CoreAudio `frame_count_min` will be equal to `frame_count_max`.
    ///
    /// The code in the supplied function must be suitable for real-time
    /// execution. That means that it cannot call functions that might block
    /// for a long time. This includes all I/O functions (disk, TTY, network),
    /// malloc, free, printf, pthread_mutex_lock, sleep, wait, poll, select,
    /// pthread_join, pthread_cond_wait, etc.
    pub fn register_write_callback<W>(&mut self, callback: Box<W>)
        where W: Fn(OutStream, i32, i32) + 'a
    {
        // stored box reference to callback closure
        self.callbacks.write = Some(callback);
        unsafe {
            // register wrapper for write_callback
            (*self.stream).write_callback = Some(write_wrapper::<W>);
            // store reference to callbacks struct in userdata pointer
            (*self.stream).userdata =
                &self.callbacks as *const Box<OutStreamCallbacks> as *mut c_void
        }
    }

    /// Registers the given callback as `underflow_callback`.
    /// This *optional* callback happens when the sound device runs out of buffered audio data to play.
    /// After this occurs, the outstream waits until the buffer is full to resume playback.
    /// This is called from the `OutStream::write_callback` thread context.
    pub fn register_underflow_callback<U>(&mut self, callback: Box<U>)
        where U: Fn(OutStream) + 'a
    {
        self.callbacks.underflow = Some(callback);
        unsafe {
            // register wrapper for write_callback
            (*self.stream).underflow_callback = Some(underflow_wrapper::<U>);
            // store reference to callbacks struct in userdata pointer
            (*self.stream).userdata =
                &self.callbacks as *const Box<OutStreamCallbacks> as *mut c_void
        }
    }

    /// *Optional* callback. `err` is always `ffi::SioError::ErrorStreaming`.
    /// This is an unrecoverable error. The stream is in an
    /// invalid state and must be destroyed, call `OutStream::destroy`.
    /// If you do not supply `error_callback`, the default callback will print
    /// a message to stderr and then call `abort`.
    /// This is called from the `OutStream::write_callback` thread context.
    pub fn register_error_callback<E>(&mut self, callback: Box<E>)
        where E: Fn(OutStream, ffi::SioError) + 'a
    {
        self.callbacks.error = Some(callback);
        unsafe {
            // register wrapper for write_callback
            (*self.stream).error_callback = Some(error_wrapper::<E>);
            // store reference to callbacks struct in userdata pointer
            (*self.stream).userdata =
                &self.callbacks as *const Box<OutStreamCallbacks> as *mut c_void
        }
    }

    write_stream!(write_stream_i8, i8);
    write_stream!(write_stream_u8, u8);
    write_stream!(write_stream_i16, i16);
    write_stream!(write_stream_u16, u16);
    write_stream!(write_stream_i32, i32);
    write_stream!(write_stream_u32, u32);
    write_stream!(write_stream_f32, f32);
    write_stream!(write_stream_f64, f64);

    fn begin_write(&self,
                   areas: *mut *mut ffi::SoundIoChannelArea,
                   frame_count: &i32)
                   -> SioResult<i32> {
        let mut actual_frame_count = *frame_count as c_int;
        match unsafe {
            ffi::soundio_outstream_begin_write(self.stream,
                                               areas,
                                               &mut actual_frame_count as *mut c_int)
        } {
            ffi::SioError::None => Ok(actual_frame_count),
            err @ _ => Err(err),
        }
    }

    fn end_write(&self) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_outstream_end_write(self.stream) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    /// Clears the output stream buffer.
    /// This function can be called from any thread.
    /// This function can be called regardless of whether the outstream is paused
    /// or not.
    /// Some backends do not support clearing the buffer. On these backends this
    /// function will return `ffi::SioError::IncompatibleBackend`.
    /// Some devices do not support clearing the buffer. On these devices this
    /// function might return `ffi::SioError::IncompatibleDevice`.
    /// Possible errors:
    ///
    /// - `ffi::SioError::Streaming`
    /// - `ffi::SioError::IncompatibleBackend`
    /// - `ffi::SioError::IncompatibleDevice`
    pub fn clear_buffer(&self) -> Option<ffi::SioError> {
        match unsafe { ffi::soundio_outstream_clear_buffer(self.stream) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    /// If the underlying backend and device support pausing, this pauses the
    /// stream. `OutStream::write_callback` may be called a few more times if
    /// the buffer is not full.
    /// Pausing might put the hardware into a low power state which is ideal if your
    /// software is silent for some time.
    /// This function may be called from any thread context, including
    /// `OutStream::write_callback`.
    /// Pausing when already paused or unpausing when already unpaused has no
    /// effect and returns `None`.
    ///
    /// Possible errors:
    ///
    /// - `ffi::SioError::BackendDisconnected`
    /// - `ffi::SioError::Streaming`
    /// - `ffi::SioError::IncompatibleDevice` - device does not support
    ///   pausing/unpausing. This error code might not be returned even if the
    ///   device does not support pausing/unpausing.
    /// - `ffi::SioError::IncompatibleBackend` - backend does not support
    ///   pausing/unpausing.
    /// - `ffi::SioError::Invalid` - outstream not opened and started
    pub fn pause(&self, pause: bool) -> Option<ffi::SioError> {
        let pause_c_bool = match pause {
            true => 1u8,
            false => 0u8,
        };
        match unsafe { ffi::soundio_outstream_pause(self.stream, pause_c_bool) } {
            ffi::SioError::None => None,
            err @ _ => Some(err),
        }
    }

    /// Obtain the total number of seconds that the next frame written after the
    /// last frame written will take to become
    /// audible.
    /// This includes both software and hardware latency.
    ///
    /// This function must be called only from within `OutStream::write_callback`.
    ///
    /// Possible errors:
    ///
    /// - `ffi::SioError::Streaming`
    pub fn get_latency(&self) -> SioResult<f64> {
        let mut latency = 0.0f64;
        match unsafe {
            ffi::soundio_outstream_get_latency(self.stream, &mut latency as *mut c_double)
        } {
            ffi::SioError::None => Ok(latency),
            err @ _ => Err(err),
        }

    }

    /// Returns the current `format` or a `ffi::SioError::Invalid` if
    /// the format is not set.
    pub fn current_format(&self) -> SioResult<ffi::SioFormat> {
        match unsafe { (*self.stream).format } {
            ffi::SioFormat::Invalid => Err(ffi::SioError::Invalid),
            fmt @ _ => Ok(fmt),
        }
    }

    /// Sets the stream format to `format`.
    /// **Must** be called before `open`ing the stream.
    ///
    /// If the device doesn't support the format
    /// `ffi::SioError::IncompatibleDevice` is returned.
    pub fn set_format(&self, format: ffi::SioFormat) -> SioResult<()> {
        let dev = self.get_device();
        if dev.supports_format(format) {
            unsafe { (*self.stream).format = format };
            Ok(())
        } else {
            Err(ffi::SioError::IncompatibleDevice)
        }
    }

    /// Returns the channel layout of the output stream.
    pub fn get_layout(&self) -> ChannelLayout {
        ChannelLayout::new(unsafe { &(*self.stream).layout })
    }

    /// Returns the sample rate of the output stream.
    pub fn get_sample_rate(&self) -> i32 {
        unsafe { (*self.stream).sample_rate as i32 }
    }

    /// Returns the underlying device of the output stream.
    pub fn get_device(&self) -> Device {
        let dev = Device::new(unsafe { (*self.stream).device });
        dev.inc_ref();
        dev
    }

    /// Destroys the output stream.
    /// Calls this when your application shuts down.
    /// NOTE: This can break if a callback is still active.
    pub fn destroy(&self) {
        unsafe { ffi::soundio_outstream_destroy(self.stream) }
    }
}
impl<'a> Drop for OutStream<'a> {
    fn drop(&mut self) {
        // TODO: call destroy manually.
        // OutStream will get dropped each time a new
        // struct is created from the same *mut pointer.
    }
}
<|endoftext|>


<commit_before>// Copyright 2018, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ffi as glib_ffi;
use gobject_ffi;
use std::borrow;
use std::convert;
use std::fmt;
use std::mem;
use std::ops;
use std::ptr;
use std::slice;
use std::str;
use translate::*;

glib_wrapper! {
    /// A mutable text buffer that grows automatically.
    pub struct String(Boxed<glib_ffi::GString>);

    match fn {
        copy => |ptr| gobject_ffi::g_boxed_copy(glib_ffi::g_gstring_get_type(), ptr as *mut _) as *mut glib_ffi::GString,
        free => |ptr| gobject_ffi::g_boxed_free(glib_ffi::g_gstring_get_type(), ptr as *mut _),
        get_type => || glib_ffi::g_gstring_get_type(),
    }
}

impl String {
    pub fn new<T: AsRef<[u8]>>(data: T) -> String {
        let bytes = data.as_ref();
        unsafe { from_glib_full(glib_ffi::g_string_new_len(
                    bytes.as_ptr() as *const _,
                    bytes.len() as isize)) }
    }

    pub fn append(&mut self, val: &str) -> &mut Self {
        unsafe { glib_ffi::g_string_append_len(
                    self.to_glib_none_mut().0,
                    val.to_glib_none().0,
                    val.len() as isize); }
        self
    }

    pub fn hash(&self) -> u32 {
        unsafe {
            glib_ffi::g_string_hash(self.to_glib_none().0)
        }
    }

    pub fn insert(&mut self, pos: isize, val: &str) -> &mut Self {
        unsafe { glib_ffi::g_string_insert_len(
                    self.to_glib_none_mut().0,
                    pos,
                    val.to_glib_none().0,
                    val.len() as isize); }
        self
    }

    pub fn overwrite(&mut self, pos: usize, val: &str) -> &mut Self {
        unsafe { glib_ffi::g_string_overwrite_len(
                    self.to_glib_none_mut().0,
                    pos,
                    val.to_glib_none().0,
                    val.len() as isize); }
        self
    }

    pub fn prepend(&mut self, val: &str) -> &mut Self {
        unsafe { glib_ffi::g_string_prepend_len(
                    self.to_glib_none_mut().0,
                    val.to_glib_none().0,
                    val.len() as isize); }
        self
    }

    pub fn truncate(&mut self, len: usize) -> &mut Self {
        unsafe { glib_ffi::g_string_truncate(self.to_glib_none_mut().0, len); }
        self
    }

    /// Returns `&str` slice when contained data is valid UTF-8 string, or an error otherwise.
    pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
        str::from_utf8(self.as_ref())
    }

    /// Returns `Cow<str>` containing UTF-8 data. Invalid UTF-8 sequences are replaced with
    /// replacement character.
    pub fn to_string_lossy(&self) -> borrow::Cow<str> {
        ::std::string::String::from_utf8_lossy(self.as_ref())
    }
}

impl Default for String {
    /// Creates a new empty string.
    fn default() -> String {
        unsafe { from_glib_full(glib_ffi::g_string_new(ptr::null())) }
    }
}

impl fmt::Display for String {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string_lossy())
    }
}

impl PartialEq for String {
    fn eq(&self, other: &Self) -> bool {
        unsafe {
            from_glib(glib_ffi::g_string_equal(self.to_glib_none().0,
                                               other.to_glib_none().0))
        }
    }
}

impl Eq for String {}

impl convert::AsRef<[u8]> for String {
    fn as_ref(&self) -> &[u8] {
        let ptr: *const u8 = (*self.0).str as _;
        let len: usize = (*self.0).len;
        unsafe { slice::from_raw_parts(ptr, len) }
    }
}

impl ops::Deref for String {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        let ptr: *const u8 = (*self.0).str as _;
        let len: usize = (*self.0).len;
        unsafe { slice::from_raw_parts(ptr, len) }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn append() {
        let mut s = ::String::new("");
        s.append("Hello").append(" ").append("there!");
        assert_eq!(&*s, b"Hello there!");
    }

    #[test]
    fn insert() {
        let mut s = ::String::new("foobaz");
        s.insert(3, "bar");
        assert_eq!(&*s, b"foobarbaz");
    }

    #[test]
    fn overwrite() {
        let mut s = ::String::new("abc");
        s.overwrite(2, "de");
        assert_eq!(&*s, b"abde");
    }

    #[test]
    fn prepend() {
        let mut s = ::String::new("456");
        s.prepend("123");
        assert_eq!(&*s, b"123456");
    }

    #[test]
    fn truncate() {
        let mut s = ::String::new("12345");
        s.truncate(10);
        assert_eq!(&*s, b"12345");
        s.truncate(2);
        assert_eq!(&*s, b"12");
    }

    #[test]
    fn default() {
        let s1: ::String = Default::default();
        assert_eq!(&*s1, b"");
    }

    #[test]
    fn display() {
        let s: ::String = ::String::new("This is a string.");
        assert_eq!(
            &format!("{}", s),
            "This is a string.");
    }

    #[test]
    fn eq() {
        let a1 = ::String::new("a");
        let a2 = ::String::new("a");
        let b = ::String::new("b");
        assert_eq!(a1, a1);
        assert_eq!(a1, a2);
        assert_ne!(a1, b);
        assert_ne!(a2, b);
    }

    #[test]
    fn invalid_utf8() {
        let s = ::String::new(b"Hello \xF0\x90\x80World");
        assert!(s.to_str().is_err());
        assert_eq!(s.to_string_lossy(), "Hello �World");
    }
}
<commit_msg>Implement Hash and Debug in a meaningful way for String<commit_after>// Copyright 2018, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use ffi as glib_ffi;
use gobject_ffi;
use std::borrow;
use std::convert;
use std::fmt;
use std::mem;
use std::ops;
use std::ptr;
use std::slice;
use std::hash;
use std::str;
use translate::*;

glib_wrapper! {
    /// A mutable text buffer that grows automatically.
    pub struct String(Boxed<glib_ffi::GString>);

    match fn {
        copy => |ptr| gobject_ffi::g_boxed_copy(glib_ffi::g_gstring_get_type(), ptr as *mut _) as *mut glib_ffi::GString,
        free => |ptr| gobject_ffi::g_boxed_free(glib_ffi::g_gstring_get_type(), ptr as *mut _),
        get_type => || glib_ffi::g_gstring_get_type(),
    }
}

impl String {
    pub fn new<T: AsRef<[u8]>>(data: T) -> String {
        let bytes = data.as_ref();
        unsafe { from_glib_full(glib_ffi::g_string_new_len(
                    bytes.as_ptr() as *const _,
                    bytes.len() as isize)) }
    }

    pub fn append(&mut self, val: &str) -> &mut Self {
        unsafe { glib_ffi::g_string_append_len(
                    self.to_glib_none_mut().0,
                    val.to_glib_none().0,
                    val.len() as isize); }
        self
    }

    pub fn hash(&self) -> u32 {
        unsafe {
            glib_ffi::g_string_hash(self.to_glib_none().0)
        }
    }

    pub fn insert(&mut self, pos: isize, val: &str) -> &mut Self {
        unsafe { glib_ffi::g_string_insert_len(
                    self.to_glib_none_mut().0,
                    pos,
                    val.to_glib_none().0,
                    val.len() as isize); }
        self
    }

    pub fn overwrite(&mut self, pos: usize, val: &str) -> &mut Self {
        unsafe { glib_ffi::g_string_overwrite_len(
                    self.to_glib_none_mut().0,
                    pos,
                    val.to_glib_none().0,
                    val.len() as isize); }
        self
    }

    pub fn prepend(&mut self, val: &str) -> &mut Self {
        unsafe { glib_ffi::g_string_prepend_len(
                    self.to_glib_none_mut().0,
                    val.to_glib_none().0,
                    val.len() as isize); }
        self
    }

    pub fn truncate(&mut self, len: usize) -> &mut Self {
        unsafe { glib_ffi::g_string_truncate(self.to_glib_none_mut().0, len); }
        self
    }

    /// Returns `&str` slice when contained data is valid UTF-8 string, or an error otherwise.
    pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
        str::from_utf8(self.as_ref())
    }

    /// Returns `Cow<str>` containing UTF-8 data. Invalid UTF-8 sequences are replaced with
    /// replacement character.
    pub fn to_string_lossy(&self) -> borrow::Cow<str> {
        ::std::string::String::from_utf8_lossy(self.as_ref())
    }
}

impl Default for String {
    /// Creates a new empty string.
    fn default() -> String {
        unsafe { from_glib_full(glib_ffi::g_string_new(ptr::null())) }
    }
}

impl fmt::Debug for String {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string_lossy())
    }
}

impl fmt::Display for String {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_string_lossy())
    }
}

impl PartialEq for String {
    fn eq(&self, other: &Self) -> bool {
        unsafe {
            from_glib(glib_ffi::g_string_equal(self.to_glib_none().0,
                                               other.to_glib_none().0))
        }
    }
}

impl Eq for String {}

impl hash::Hash for String {
    fn hash<H>(&self, state: &mut H) where H: hash::Hasher {
        hash::Hash::hash_slice(self.as_ref(), state)
    }
}

impl convert::AsRef<[u8]> for String {
    fn as_ref(&self) -> &[u8] {
        let ptr: *const u8 = (*self.0).str as _;
        let len: usize = (*self.0).len;
        unsafe { slice::from_raw_parts(ptr, len) }
    }
}

impl ops::Deref for String {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        let ptr: *const u8 = (*self.0).str as _;
        let len: usize = (*self.0).len;
        unsafe { slice::from_raw_parts(ptr, len) }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn append() {
        let mut s = ::String::new("");
        s.append("Hello").append(" ").append("there!");
        assert_eq!(&*s, b"Hello there!");
    }

    #[test]
    fn insert() {
        let mut s = ::String::new("foobaz");
        s.insert(3, "bar");
        assert_eq!(&*s, b"foobarbaz");
    }

    #[test]
    fn overwrite() {
        let mut s = ::String::new("abc");
        s.overwrite(2, "de");
        assert_eq!(&*s, b"abde");
    }

    #[test]
    fn prepend() {
        let mut s = ::String::new("456");
        s.prepend("123");
        assert_eq!(&*s, b"123456");
    }

    #[test]
    fn truncate() {
        let mut s = ::String::new("12345");
        s.truncate(10);
        assert_eq!(&*s, b"12345");
        s.truncate(2);
        assert_eq!(&*s, b"12");
    }

    #[test]
    fn default() {
        let s1: ::String = Default::default();
        assert_eq!(&*s1, b"");
    }

    #[test]
    fn display() {
        let s: ::String = ::String::new("This is a string.");
        assert_eq!(
            &format!("{}", s),
            "This is a string.");
    }

    #[test]
    fn eq() {
        let a1 = ::String::new("a");
        let a2 = ::String::new("a");
        let b = ::String::new("b");
        assert_eq!(a1, a1);
        assert_eq!(a1, a2);
        assert_ne!(a1, b);
        assert_ne!(a2, b);
    }

    #[test]
    fn invalid_utf8() {
        let s = ::String::new(b"Hello \xF0\x90\x80World");
        assert!(s.to_str().is_err());
        assert_eq!(s.to_string_lossy(), "Hello �World");
    }
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use super::debugger::SBDebugger;
use super::filespec::SBFileSpec;
use super::module::SBModule;
use super::modulespec::SBModuleSpec;
use super::platform::SBPlatform;
use super::process::SBProcess;
use sys;

/// The target program running under the debugger.
#[derive(Debug)]
pub struct SBTarget {
    /// The underlying raw `SBTargetRef`.
    pub raw: sys::SBTargetRef,
}

impl SBTarget {
    /// Construct a new `SBTarget`.
    pub fn wrap(raw: sys::SBTargetRef) -> SBTarget {
        SBTarget { raw: raw }
    }

    /// Construct a new `Some(SBTarget)` or `None`.
    pub fn maybe_wrap(raw: sys::SBTargetRef) -> Option<SBTarget> {
        if unsafe { sys::SBTargetIsValid(raw) != 0 } {
            Some(SBTarget { raw: raw })
        } else {
            None
        }
    }

    /// Check whether or not this is a valid `SBTarget` value.
    pub fn is_valid(&self) -> bool {
        unsafe { sys::SBTargetIsValid(self.raw) != 0 }
    }

    /// Get the [`SBPlatform`] associated with this target.
    ///
    /// After return, the platform object should be checked for validity.
    ///
    /// [`SBPlatform`]: strut.SBPlatform.html
    pub fn platform(&self) -> SBPlatform {
        unsafe { SBPlatform { raw: sys::SBTargetGetPlatform(self.raw) } }
    }

    /// Get the [`SBProcess`] associated with this target.
    ///
    /// [`SBProcess`]: strut.SBProcess.html
    pub fn process(&self) -> SBProcess {
        unsafe { SBProcess { raw: sys::SBTargetGetProcess(self.raw) } }
    }

    /// Get a filespec for the executable.
    pub fn executable(&self) -> Option<SBFileSpec> {
        SBFileSpec::maybe_wrap(unsafe { sys::SBTargetGetExecutable(self.raw) })
    }

    /// Add a module to the target.
    pub fn add_module(&self, module: &SBModule) -> bool {
        unsafe { sys::SBTargetAddModule(self.raw, module.raw) != 0 }
    }

    /// Add a module to the target using an `SBModuleSpec`.
    pub fn add_module_spec(&self, module_spec: &SBModuleSpec) -> Option<SBModule> {
        SBModule::maybe_wrap(unsafe { sys::SBTargetAddModule4(self.raw, module_spec.raw) })
    }

    /// Remove a module from the target.
    pub fn remove_module(&self, module: &SBModule) -> bool {
        unsafe { sys::SBTargetRemoveModule(self.raw, module.raw) != 0 }
    }

    /// Get the debugger controlling this target.
    pub fn debugger(&self) -> SBDebugger {
        SBDebugger { raw: unsafe { sys::SBTargetGetDebugger(self.raw) } }
    }

    /// Find the module for the given `SBFileSpec`.
    pub fn find_module(&self, file_spec: &SBFileSpec) -> Option<SBModule> {
        SBModule::maybe_wrap(unsafe { sys::SBTargetFindModule(self.raw, file_spec.raw) })
    }
}

impl Drop for SBTarget {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBTarget(self.raw) };
    }
}
<commit_msg>Implement SBTarget::launch().<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use super::debugger::SBDebugger;
use super::error::SBError;
use super::filespec::SBFileSpec;
use super::launchinfo::SBLaunchInfo;
use super::module::SBModule;
use super::modulespec::SBModuleSpec;
use super::platform::SBPlatform;
use super::process::SBProcess;
use sys;

/// The target program running under the debugger.
#[derive(Debug)]
pub struct SBTarget {
    /// The underlying raw `SBTargetRef`.
    pub raw: sys::SBTargetRef,
}

impl SBTarget {
    /// Construct a new `SBTarget`.
    pub fn wrap(raw: sys::SBTargetRef) -> SBTarget {
        SBTarget { raw: raw }
    }

    /// Construct a new `Some(SBTarget)` or `None`.
    pub fn maybe_wrap(raw: sys::SBTargetRef) -> Option<SBTarget> {
        if unsafe { sys::SBTargetIsValid(raw) != 0 } {
            Some(SBTarget { raw: raw })
        } else {
            None
        }
    }

    /// Check whether or not this is a valid `SBTarget` value.
    pub fn is_valid(&self) -> bool {
        unsafe { sys::SBTargetIsValid(self.raw) != 0 }
    }

    /// Get the [`SBPlatform`] associated with this target.
    ///
    /// After return, the platform object should be checked for validity.
    ///
    /// [`SBPlatform`]: strut.SBPlatform.html
    pub fn platform(&self) -> SBPlatform {
        unsafe { SBPlatform { raw: sys::SBTargetGetPlatform(self.raw) } }
    }

    /// Get the [`SBProcess`] associated with this target.
    ///
    /// [`SBProcess`]: strut.SBProcess.html
    pub fn process(&self) -> SBProcess {
        unsafe { SBProcess { raw: sys::SBTargetGetProcess(self.raw) } }
    }

    /// Launch a target for debugging.
    pub fn launch(&self, launch_info: SBLaunchInfo) -> Result<SBProcess, SBError> {
        let error: SBError = SBError::new();
        let process =
            SBProcess::wrap(unsafe { sys::SBTargetLaunch2(self.raw, launch_info.raw, error.raw) });
        if error.is_success() {
            Ok(process)
        } else {
            Err(error)
        }
    }

    /// Get a filespec for the executable.
    pub fn executable(&self) -> Option<SBFileSpec> {
        SBFileSpec::maybe_wrap(unsafe { sys::SBTargetGetExecutable(self.raw) })
    }

    /// Add a module to the target.
    pub fn add_module(&self, module: &SBModule) -> bool {
        unsafe { sys::SBTargetAddModule(self.raw, module.raw) != 0 }
    }

    /// Add a module to the target using an `SBModuleSpec`.
    pub fn add_module_spec(&self, module_spec: &SBModuleSpec) -> Option<SBModule> {
        SBModule::maybe_wrap(unsafe { sys::SBTargetAddModule4(self.raw, module_spec.raw) })
    }

    /// Remove a module from the target.
    pub fn remove_module(&self, module: &SBModule) -> bool {
        unsafe { sys::SBTargetRemoveModule(self.raw, module.raw) != 0 }
    }

    /// Get the debugger controlling this target.
    pub fn debugger(&self) -> SBDebugger {
        SBDebugger { raw: unsafe { sys::SBTargetGetDebugger(self.raw) } }
    }

    /// Find the module for the given `SBFileSpec`.
    pub fn find_module(&self, file_spec: &SBFileSpec) -> Option<SBModule> {
        SBModule::maybe_wrap(unsafe { sys::SBTargetFindModule(self.raw, file_spec.raw) })
    }
}

impl Drop for SBTarget {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBTarget(self.raw) };
    }
}
<|endoftext|>


<commit_before>use std::cell::{RefCell, Ref};

use opencl;
use opencl::hl::KernelArg;
use opencl::mem::{Buffer, CLBuffer};
use libc;
use ref_filter_map::ref_filter_map;

use array::Array;
use context::Context;
use helper;
use num::Num;
use range_arg::RangeArg;

pub enum TensorMode {
    In,
    Out,
    Mut,
}

pub struct Tensor<T: Num> {
    shape: Vec<usize>,
    dim_steps: Vec<usize>,
    buffer: CLBuffer<T>,
    event: RefCell<Option<Event>>,
}

impl<T: Num> Tensor<T> {
    pub fn new(ctx: &Context, shape: Vec<usize>, mode: TensorMode) -> Tensor<T> {
        let mem_mode =
            match mode {
                TensorMode::In => { opencl::cl::CL_MEM_READ_ONLY },
                TensorMode::Out => { opencl::cl::CL_MEM_WRITE_ONLY },
                TensorMode::Mut => { opencl::cl::CL_MEM_READ_WRITE },
            };
        let buf_size = shape.iter().fold(1, |a, b| a*b);
        let dim_steps = helper::compute_dim_steps(&shape);
        Tensor {
            shape: shape,
            dim_steps: dim_steps,
            buffer: ctx.ctx.create_buffer(buf_size, mem_mode),
            event: RefCell::new(None),
        }
    }

    pub fn from_array(ctx: &Context,
                      array: &Array<T>,
                      mode: TensorMode) -> Tensor<T> {
        let mem_mode =
            match mode {
                TensorMode::In => { opencl::cl::CL_MEM_READ_ONLY },
                TensorMode::Out => { opencl::cl::CL_MEM_WRITE_ONLY },
                TensorMode::Mut => { opencl::cl::CL_MEM_READ_WRITE },
            };
        Tensor {
            shape: array.shape().to_vec(),
            dim_steps: array.dim_steps().to_owned(),
            buffer: ctx.ctx.create_buffer_from(array.buffer(), mem_mode),
            event: RefCell::new(None),
        }
    }

    pub fn get(&self, ctx: &Context) -> Array<T> {
        let vec = ctx.queue.get(&self.buffer, self.get_event().as_ref().map(|x| &**x));
        Array::from_vec(self.shape.clone(), vec)
    }

    pub fn read(&self, ctx: &Context, array: &mut Array<T>) {
        ctx.queue.read(&self.buffer, &mut array.buffer_mut(), self.get_event().as_ref().map(|x| &**x));
    }

    pub fn set(&self, ctx: &Context, array: &Array<T>) {
        ctx.queue.write(&self.buffer, &array.buffer(), ());
    }

    pub fn shape(&self) -> &[usize] {
        &self.shape
    }

    pub fn len(&self) -> usize {
        self.buffer.len()
    }

    pub fn set_event(&self, e: Event) {
        *self.event.borrow_mut() = Some(e);
    }

    pub fn get_event(&self) -> Option<Ref<Event>> {
        if self.event.borrow().is_some() {
            ref_filter_map(self.event.borrow(), |o| o.as_ref())
        } else {
            None
        }
    }

    pub fn slice<'t, R: AsRef<[RangeArg]>>(&'t self, r: R) -> TensorView<'t, T, R> {
        TensorView {
            shape: self.shape.as_ref(),
            dim_steps: self.dim_steps.as_ref(),
            ranges: r,
            buffer: &self.buffer,
            event: &self.event,
        }
    }
}

impl<T: Num> KernelArg for Tensor<T> {
    fn get_value(&self) -> (libc::size_t, *const libc::c_void) {
        self.buffer.get_value()
    }
}

impl<'t, T: Num, R: AsRef<[RangeArg]>> KernelArg for TensorView<'t, T, R> {
    fn get_value(&self) -> (libc::size_t, *const libc::c_void) {
        self.buffer.get_value()
    }
}

pub struct TensorView<'t, T: Num+'t, R: AsRef<[RangeArg]>> {
    pub shape: &'t [usize],
    pub dim_steps: &'t [usize],
    ranges: R,
    buffer: &'t CLBuffer<T>,
    event: &'t RefCell<Option<Event>>,
}

impl<'t, T: Num, R: AsRef<[RangeArg]>> TensorView<'t, T, R> {
    pub fn set_event(&self, e: Event) {
        *self.event.borrow_mut() = Some(e);
    }

    pub fn get_event(&self) -> Option<Ref<Event>> {
        if self.event.borrow().is_some() {
            ref_filter_map(self.event.borrow(), |o| o.as_ref())
        } else {
            None
        }
    }

    pub fn view_offset(&self, dim: usize) -> usize {
        self.ranges.as_ref()[dim].start
    }

    pub fn view_shape(&self, dim: usize) -> usize {
        self.ranges.as_ref()[dim].len(self.shape[dim])
    }

    pub fn len(&self) -> usize {
        self.buffer.len()
    }
}

pub type Event = opencl::hl::Event;

////////////////////////////////////////////////////////////////////////////////////////////////////

#[test]
fn test_tensor_read() {
    let ref ctx = Context::new();

    let a = Array::from_vec(vec![2, 2], vec![1i32, 2,
                                             3, 4]);
    let at = Tensor::from_array(ctx, &a, TensorMode::Out);
    let mut b = Array::new(vec![2, 2], 0);

    at.read(ctx, &mut b);

    assert!(b.buffer() == &[1, 2,
                            3, 4]);
}
<commit_msg>Slicing with incomplete dimensions<commit_after>use std::cell::{RefCell, Ref};

use opencl;
use opencl::hl::KernelArg;
use opencl::mem::{Buffer, CLBuffer};
use libc;
use ref_filter_map::ref_filter_map;

use array::Array;
use context::Context;
use helper;
use num::Num;
use range_arg::RangeArg;

pub enum TensorMode {
    In,
    Out,
    Mut,
}

pub struct Tensor<T: Num> {
    shape: Vec<usize>,
    dim_steps: Vec<usize>,
    buffer: CLBuffer<T>,
    event: RefCell<Option<Event>>,
}

impl<T: Num> Tensor<T> {
    pub fn new(ctx: &Context, shape: Vec<usize>, mode: TensorMode) -> Tensor<T> {
        let mem_mode =
            match mode {
                TensorMode::In => { opencl::cl::CL_MEM_READ_ONLY },
                TensorMode::Out => { opencl::cl::CL_MEM_WRITE_ONLY },
                TensorMode::Mut => { opencl::cl::CL_MEM_READ_WRITE },
            };
        let buf_size = shape.iter().fold(1, |a, b| a*b);
        let dim_steps = helper::compute_dim_steps(&shape);
        Tensor {
            shape: shape,
            dim_steps: dim_steps,
            buffer: ctx.ctx.create_buffer(buf_size, mem_mode),
            event: RefCell::new(None),
        }
    }

    pub fn from_array(ctx: &Context,
                      array: &Array<T>,
                      mode: TensorMode) -> Tensor<T> {
        let mem_mode =
            match mode {
                TensorMode::In => { opencl::cl::CL_MEM_READ_ONLY },
                TensorMode::Out => { opencl::cl::CL_MEM_WRITE_ONLY },
                TensorMode::Mut => { opencl::cl::CL_MEM_READ_WRITE },
            };
        Tensor {
            shape: array.shape().to_vec(),
            dim_steps: array.dim_steps().to_owned(),
            buffer: ctx.ctx.create_buffer_from(array.buffer(), mem_mode),
            event: RefCell::new(None),
        }
    }

    pub fn get(&self, ctx: &Context) -> Array<T> {
        let vec = ctx.queue.get(&self.buffer, self.get_event().as_ref().map(|x| &**x));
        Array::from_vec(self.shape.clone(), vec)
    }

    pub fn read(&self, ctx: &Context, array: &mut Array<T>) {
        ctx.queue.read(&self.buffer, &mut array.buffer_mut(), self.get_event().as_ref().map(|x| &**x));
    }

    pub fn set(&self, ctx: &Context, array: &Array<T>) {
        ctx.queue.write(&self.buffer, &array.buffer(), ());
    }

    pub fn shape(&self) -> &[usize] {
        &self.shape
    }

    pub fn len(&self) -> usize {
        self.buffer.len()
    }

    pub fn set_event(&self, e: Event) {
        *self.event.borrow_mut() = Some(e);
    }

    pub fn get_event(&self) -> Option<Ref<Event>> {
        if self.event.borrow().is_some() {
            ref_filter_map(self.event.borrow(), |o| o.as_ref())
        } else {
            None
        }
    }

    pub fn slice<'t, R: AsRef<[RangeArg]>>(&'t self, r: R) -> TensorView<'t, T, R> {
        TensorView {
            shape: self.shape.as_ref(),
            dim_steps: self.dim_steps.as_ref(),
            ranges: r,
            buffer: &self.buffer,
            event: &self.event,
        }
    }
}

impl<T: Num> KernelArg for Tensor<T> {
    fn get_value(&self) -> (libc::size_t, *const libc::c_void) {
        self.buffer.get_value()
    }
}

impl<'t, T: Num, R: AsRef<[RangeArg]>> KernelArg for TensorView<'t, T, R> {
    fn get_value(&self) -> (libc::size_t, *const libc::c_void) {
        self.buffer.get_value()
    }
}

pub struct TensorView<'t, T: Num+'t, R: AsRef<[RangeArg]>> {
    pub shape: &'t [usize],
    pub dim_steps: &'t [usize],
    ranges: R,
    buffer: &'t CLBuffer<T>,
    event: &'t RefCell<Option<Event>>,
}

impl<'t, T: Num, R: AsRef<[RangeArg]>> TensorView<'t, T, R> {
    pub fn set_event(&self, e: Event) {
        *self.event.borrow_mut() = Some(e);
    }

    pub fn get_event(&self) -> Option<Ref<Event>> {
        if self.event.borrow().is_some() {
            ref_filter_map(self.event.borrow(), |o| o.as_ref())
        } else {
            None
        }
    }

    pub fn view_offset(&self, dim: usize) -> usize {
        self.ranges.as_ref().get(dim).map(|r| r.start).unwrap_or(0)
    }

    pub fn view_shape(&self, dim: usize) -> usize {
        self.ranges.as_ref().get(dim).map(|r| r.len(self.shape[dim])).unwrap_or(self.shape[dim])
    }

    pub fn len(&self) -> usize {
        self.buffer.len()
    }
}

pub type Event = opencl::hl::Event;

////////////////////////////////////////////////////////////////////////////////////////////////////

#[test]
fn test_tensor_read() {
    let ref ctx = Context::new();

    let a = Array::from_vec(vec![2, 2], vec![1i32, 2,
                                             3, 4]);
    let at = Tensor::from_array(ctx, &a, TensorMode::Out);
    let mut b = Array::new(vec![2, 2], 0);

    at.read(ctx, &mut b);

    assert!(b.buffer() == &[1, 2,
                            3, 4]);
}

#[test]
fn test_tensor_incomplete_slice() {
    let ref ctx = Context::new();
    let t = Tensor::<f32>::new(ctx, vec![4, 5, 6], TensorMode::Out);
    let t_slice = t.slice(s![1..3]);
    assert!(t_slice.view_offset(0) == 1);
    assert!(t_slice.view_offset(1) == 0);
    assert!(t_slice.view_offset(2) == 0);
    assert!(t_slice.view_shape(0) == 2);
    assert!(t_slice.view_shape(1) == 5);
    assert!(t_slice.view_shape(2) == 6);
}
<|endoftext|>


<commit_before>use std::io;
use std::io::{BufRead, BufReader};
use std::path::{PathBuf, Path};
use std::ffi::CString;
use std::ops::Deref;
use std::fs::File;
use std::collections::HashSet;
use object::Object;
use object::File as OFile;
use memmap::{Mmap, Protection};
use gimli::*;
use regex::Regex;
use rustc_demangle::demangle;

/// Describes a function as low_pc, high_pc and bool representing is_test.
type FuncDesc = (u64, u64, FunctionType);

#[derive(Clone, Copy, PartialEq)]
enum FunctionType {
    Generated,
    Test,
    Standard
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LineType {
    /// Generated test main. Shouldn't be traced.
    TestMain,
    /// Entry of function known to be a test
    TestEntry(u64),
    /// Entry of function. May or may not be test
    FunctionEntry(u64),
    /// Standard statement
    Statement,
    /// Condition
    Condition,
    /// Unknown type
    Unknown,
}

#[derive(Debug, Clone)]
pub struct TracerData {
    pub path: PathBuf,
    pub line: u64,
    pub address: u64,
    pub trace_type: LineType,
    pub hits: u64,
}

fn line_is_traceable(file: &PathBuf, line: u64) -> bool {
    let mut result = false;
    if line > 0 {
        // Module imports are flagged as debuggable. But are always ran so meaningless!
        let reg: Regex = Regex::new(r"(:?^|\s)(:?mod)|(:?crate)\s+\w+;").unwrap();
        if let Ok(f) = File::open(file) {
            let reader = BufReader::new(&f);
            if let Some(Ok(l)) = reader.lines().nth((line - 1) as usize) {
                result = !reg.is_match(l.as_ref());
            }
        }
    }
    result
}

fn generate_func_desc<T: Endianity>(die: &DebuggingInformationEntry<T>,
                                    debug_str: &DebugStr<T>) -> Result<FuncDesc> {
    let mut func_type = FunctionType::Standard;
    let low = die.attr_value(DW_AT_low_pc)?;
    let high = die.attr_value(DW_AT_high_pc)?;
    let linkage = die.attr_value(DW_AT_linkage_name)?;

    // Low is a program counter address so stored in an Addr
    let low = match low {
        Some(AttributeValue::Addr(x)) => x,
        _ => 0u64,
    };
    // High is an offset from the base pc, therefore is u64 data.
    let high = match high {
        Some(AttributeValue::Udata(x)) => x,
        _ => 0u64,
    };
    if let Some(AttributeValue::DebugStrRef(offset)) = linkage {
        let empty = CString::new("").unwrap();
        let name = debug_str.get_str(offset).unwrap_or(empty.deref());
        // go from CStr to Owned String
        let name = name.to_str().unwrap_or("");
        let name = demangle(name).to_string();
        // Simplest test is whether it's in tests namespace.
        // Rust guidelines recommend all tests are in a tests module.
        func_type = if name.contains("tests::") {
            FunctionType::Test
        } else if name.contains("__test::main") {
            FunctionType::Generated
        } else {
            FunctionType::Standard
        };
    }
    Ok((low, high, func_type))
}

/// Finds all function entry points and returns a vector
/// This will identify definite tests, but may be prone to false negatives.
/// TODO Potential to trace all function calls from __test::main and find addresses of interest
fn get_entry_points<T: Endianity>(debug_info: &CompilationUnitHeader<T>,
                                  debug_abbrev: &Abbreviations,
                                  debug_str: &DebugStr<T>) -> Vec<FuncDesc> {
    let mut result:Vec<FuncDesc> = Vec::new();
    let mut cursor = debug_info.entries(debug_abbrev);
    // skip compilation unit root.
    let _ = cursor.next_entry();
    while let Ok(Some((_, node))) = cursor.next_dfs() {
        // Function DIE
        if node.tag() == DW_TAG_subprogram {

            if let Ok(fd) = generate_func_desc(&node, &debug_str) {
                result.push(fd);
            }
        }
    }
    result
}

fn get_addresses_from_program<T:Endianity>(prog: IncompleteLineNumberProgram<T>,
                                           entries: &Vec<(u64, LineType)>,
                                           project: &Path) -> Result<Vec<TracerData>> {
    let mut result: Vec<TracerData> = Vec::new();
    let ( cprog, seq) = prog.sequences()?;
    for s in seq {
        let mut sm = cprog.resume_from(&s);
         while let Ok(Some((ref header, &ln_row))) = sm.next_row() {
            if let Some(file) = ln_row.file(header) {
                let mut path = PathBuf::new();

                if let Some(dir) = file.directory(header) {
                    if let Ok(temp) = String::from_utf8(dir.to_bytes().to_vec()) {
                        path.push(temp);
                    }
                }
                if path.is_relative() {
                    if let Ok(p) = path.canonicalize() {
                        path = p;
                    }
                }
                // Source is part of project so we cover it.
                if path.starts_with(project) {
                    let force_test = path.starts_with(project.join("tests"));
                    if let Some(file) = ln_row.file(header) {
                        // If we can't map to line, we can't trace it.
                        let line = ln_row.line().unwrap_or(0);
                        let file = file.path_name();
                        // We now need to filter out lines which are meaningless to trace.

                        if let Ok(file) = String::from_utf8(file.to_bytes().to_vec()) {
                            path.push(file);
                            if !line_is_traceable(&path, line) {
                                continue;
                            }
                            let address = ln_row.address();

                            let desc = entries.iter()
                                              .filter(|&&(addr, _)| addr == address )
                                              .map(|&(_, t)| t)
                                              .nth(0)
                                              .unwrap_or(LineType::Unknown);
                            // TODO HACK: If in tests/ directory force it to a TestEntry
                            let desc = match desc {
                                LineType::FunctionEntry(e) if force_test => LineType::TestEntry(e),
                                x @ _ => x
                            };
                            result.push( TracerData {
                                path: path,
                                line: line,
                                address: address,
                                trace_type: desc,
                                hits: 0u64
                            });
                        }
                    }
                }
            }
        }
    }
    Ok(result)
}

fn get_line_addresses<Endian: Endianity>(project: &Path, obj: &OFile) -> Result<Vec<TracerData>>  {
    let mut result: Vec<TracerData> = Vec::new();
    let debug_info = obj.get_section(".debug_info").unwrap_or(&[]);
    let debug_info = DebugInfo::<Endian>::new(debug_info);
    let debug_abbrev = obj.get_section(".debug_abbrev").unwrap_or(&[]);
    let debug_abbrev = DebugAbbrev::<Endian>::new(debug_abbrev);
    let debug_strings = obj.get_section(".debug_str").unwrap_or(&[]);
    let debug_strings = DebugStr::<Endian>::new(debug_strings);

    let mut iter = debug_info.units();
    while let Ok(Some(cu)) = iter.next() {
        let addr_size = cu.address_size();
        let abbr = match cu.abbreviations(debug_abbrev) {
            Ok(a) => a,
            _ => continue,
        };
        let entries = get_entry_points(&cu, &abbr, &debug_strings)
            .iter()
            .map(|&(a, b, c)| {
                match c {
                    FunctionType::Test => (a, LineType::TestEntry(b)),
                    FunctionType::Standard => (a, LineType::FunctionEntry(b)),
                    FunctionType::Generated => (a, LineType::TestMain),
                }
            }).collect();
        if let Ok(Some((_, root))) = cu.entries(&abbr).next_dfs() {
            let offset = match root.attr_value(DW_AT_stmt_list) {
                Ok(Some(AttributeValue::DebugLineRef(o))) => o,
                _ => continue,
            };
            let debug_line = obj.get_section(".debug_line").unwrap_or(&[]);
            let debug_line = DebugLine::<Endian>::new(debug_line);

            let prog = debug_line.program(offset, addr_size, None, None)?;
            if let Ok(mut addresses) = get_addresses_from_program(prog, &entries, &project) {
                result.append(&mut addresses);
            }
        }
    }
    // Due to rust being a higher level language multiple instructions may map
    // to the same line. This prunes these to just the first instruction address
    let mut check: HashSet<(&Path, u64)> = HashSet::new();
    let mut result = result.iter()
                           .filter(|x| check.insert((x.path.as_path(), x.line)))
                           .filter(|x| x.trace_type != LineType::TestMain)
                           .map(|x| x.clone())
                           .collect::<Vec<TracerData>>();
    let addresses = result.iter()
                          .map(|x| x.address)
                          .collect::<Vec<_>>();
    // TODO Probably a more idiomatic way to do this.
    {
        let test_entries = result.iter_mut()
                                 .filter(|x| match x.trace_type {
                                     LineType::TestEntry(_) => true,
                                     _ => false,
                                 });

        for ref mut test_entry in test_entries {
            let endpoint = match test_entry.trace_type {
                LineType::TestEntry(x) => x,
                _ => continue,
            };
            let max_address = addresses.iter()
                                       .fold(0, |acc, x| {
                                           if x > &(test_entry.address + acc) && (x-test_entry.address) <= endpoint {
                                               *x - test_entry.address
                                           } else {
                                               acc
                                           }
                                       });
            test_entry.trace_type = LineType::TestEntry(max_address);
        }
    }
    Ok(result)
}

/// Generates a list of lines we want to trace the coverage of. Used to instrument the
/// traces into the test executable
pub fn generate_tracer_data(manifest: &Path, test: &Path) -> io::Result<Vec<TracerData>> {
    let file = File::open(test)?;
    let file = Mmap::open(&file, Protection::Read)?;
    if let Ok(obj) = OFile::parse(unsafe {file.as_slice() }) {

        let data = if obj.is_little_endian() {
            get_line_addresses::<LittleEndian>(manifest, &obj)
        } else {
            get_line_addresses::<BigEndian>(manifest, &obj)
        };
        data.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Error while parsing"))
    } else {
        Err(io::Error::new(io::ErrorKind::InvalidData, "Unable to parse binary."))
    }
}
<commit_msg>Added filter to tracer so source in target folder isn't covered.<commit_after>use std::io;
use std::io::{BufRead, BufReader};
use std::path::{PathBuf, Path};
use std::ffi::CString;
use std::ops::Deref;
use std::fs::File;
use std::collections::HashSet;
use object::Object;
use object::File as OFile;
use memmap::{Mmap, Protection};
use gimli::*;
use regex::Regex;
use rustc_demangle::demangle;

/// Describes a function as low_pc, high_pc and bool representing is_test.
type FuncDesc = (u64, u64, FunctionType);

#[derive(Clone, Copy, PartialEq)]
enum FunctionType {
    Generated,
    Test,
    Standard
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LineType {
    /// Generated test main. Shouldn't be traced.
    TestMain,
    /// Entry of function known to be a test
    TestEntry(u64),
    /// Entry of function. May or may not be test
    FunctionEntry(u64),
    /// Standard statement
    Statement,
    /// Condition
    Condition,
    /// Unknown type
    Unknown,
}

#[derive(Debug, Clone)]
pub struct TracerData {
    pub path: PathBuf,
    pub line: u64,
    pub address: u64,
    pub trace_type: LineType,
    pub hits: u64,
}

fn line_is_traceable(file: &PathBuf, line: u64) -> bool {
    let mut result = false;
    if line > 0 {
        // Module imports are flagged as debuggable. But are always ran so meaningless!
        let reg: Regex = Regex::new(r"(:?^|\s)(:?mod)|(:?crate)\s+\w+;").unwrap();
        if let Ok(f) = File::open(file) {
            let reader = BufReader::new(&f);
            if let Some(Ok(l)) = reader.lines().nth((line - 1) as usize) {
                result = !reg.is_match(l.as_ref());
            }
        }
    }
    result
}

fn generate_func_desc<T: Endianity>(die: &DebuggingInformationEntry<T>,
                                    debug_str: &DebugStr<T>) -> Result<FuncDesc> {
    let mut func_type = FunctionType::Standard;
    let low = die.attr_value(DW_AT_low_pc)?;
    let high = die.attr_value(DW_AT_high_pc)?;
    let linkage = die.attr_value(DW_AT_linkage_name)?;

    // Low is a program counter address so stored in an Addr
    let low = match low {
        Some(AttributeValue::Addr(x)) => x,
        _ => 0u64,
    };
    // High is an offset from the base pc, therefore is u64 data.
    let high = match high {
        Some(AttributeValue::Udata(x)) => x,
        _ => 0u64,
    };
    if let Some(AttributeValue::DebugStrRef(offset)) = linkage {
        let empty = CString::new("").unwrap();
        let name = debug_str.get_str(offset).unwrap_or(empty.deref());
        // go from CStr to Owned String
        let name = name.to_str().unwrap_or("");
        let name = demangle(name).to_string();
        // Simplest test is whether it's in tests namespace.
        // Rust guidelines recommend all tests are in a tests module.
        func_type = if name.contains("tests::") {
            FunctionType::Test
        } else if name.contains("__test::main") {
            FunctionType::Generated
        } else {
            FunctionType::Standard
        };
    }
    Ok((low, high, func_type))
}

/// Finds all function entry points and returns a vector
/// This will identify definite tests, but may be prone to false negatives.
/// TODO Potential to trace all function calls from __test::main and find addresses of interest
fn get_entry_points<T: Endianity>(debug_info: &CompilationUnitHeader<T>,
                                  debug_abbrev: &Abbreviations,
                                  debug_str: &DebugStr<T>) -> Vec<FuncDesc> {
    let mut result:Vec<FuncDesc> = Vec::new();
    let mut cursor = debug_info.entries(debug_abbrev);
    // skip compilation unit root.
    let _ = cursor.next_entry();
    while let Ok(Some((_, node))) = cursor.next_dfs() {
        // Function DIE
        if node.tag() == DW_TAG_subprogram {

            if let Ok(fd) = generate_func_desc(&node, &debug_str) {
                result.push(fd);
            }
        }
    }
    result
}

fn get_addresses_from_program<T:Endianity>(prog: IncompleteLineNumberProgram<T>,
                                           entries: &Vec<(u64, LineType)>,
                                           project: &Path) -> Result<Vec<TracerData>> {
    let mut result: Vec<TracerData> = Vec::new();
    let ( cprog, seq) = prog.sequences()?;
    for s in seq {
        let mut sm = cprog.resume_from(&s);
         while let Ok(Some((ref header, &ln_row))) = sm.next_row() {
            if let Some(file) = ln_row.file(header) {
                let mut path = PathBuf::new();

                if let Some(dir) = file.directory(header) {
                    if let Ok(temp) = String::from_utf8(dir.to_bytes().to_vec()) {
                        path.push(temp);
                    }
                }
                // Fix relative paths and determine if in target directory
                // Source in target directory shouldn't be covered as it's either
                // autogenerated or resulting from the projects Cargo.lock
                let is_target = if path.is_relative() {
                    let res = path.starts_with("target");
                    if !res {
                        if let Ok(p) = path.canonicalize() {
                            path = p;
                        }
                    }
                    res
                } else {
                    path.starts_with(project.join("target"))
                };
                // Source is part of project so we cover it.
                if !is_target && path.starts_with(project) {
                    let force_test = path.starts_with(project.join("tests"));
                    if let Some(file) = ln_row.file(header) {
                        // If we can't map to line, we can't trace it.
                        let line = ln_row.line().unwrap_or(0);
                        let file = file.path_name();
                        // We now need to filter out lines which are meaningless to trace.

                        if let Ok(file) = String::from_utf8(file.to_bytes().to_vec()) {
                            path.push(file);
                            if !line_is_traceable(&path, line) {
                                continue;
                            }
                            let address = ln_row.address();

                            let desc = entries.iter()
                                              .filter(|&&(addr, _)| addr == address )
                                              .map(|&(_, t)| t)
                                              .nth(0)
                                              .unwrap_or(LineType::Unknown);
                            // TODO HACK: If in tests/ directory force it to a TestEntry
                            let desc = match desc {
                                LineType::FunctionEntry(e) if force_test => LineType::TestEntry(e),
                                x @ _ => x
                            };
                            result.push( TracerData {
                                path: path,
                                line: line,
                                address: address,
                                trace_type: desc,
                                hits: 0u64
                            });
                        }
                    }
                }
            }
        }
    }
    Ok(result)
}

fn get_line_addresses<Endian: Endianity>(project: &Path, obj: &OFile) -> Result<Vec<TracerData>>  {
    let mut result: Vec<TracerData> = Vec::new();
    let debug_info = obj.get_section(".debug_info").unwrap_or(&[]);
    let debug_info = DebugInfo::<Endian>::new(debug_info);
    let debug_abbrev = obj.get_section(".debug_abbrev").unwrap_or(&[]);
    let debug_abbrev = DebugAbbrev::<Endian>::new(debug_abbrev);
    let debug_strings = obj.get_section(".debug_str").unwrap_or(&[]);
    let debug_strings = DebugStr::<Endian>::new(debug_strings);

    let mut iter = debug_info.units();
    while let Ok(Some(cu)) = iter.next() {
        let addr_size = cu.address_size();
        let abbr = match cu.abbreviations(debug_abbrev) {
            Ok(a) => a,
            _ => continue,
        };
        let entries = get_entry_points(&cu, &abbr, &debug_strings)
            .iter()
            .map(|&(a, b, c)| {
                match c {
                    FunctionType::Test => (a, LineType::TestEntry(b)),
                    FunctionType::Standard => (a, LineType::FunctionEntry(b)),
                    FunctionType::Generated => (a, LineType::TestMain),
                }
            }).collect();
        if let Ok(Some((_, root))) = cu.entries(&abbr).next_dfs() {
            let offset = match root.attr_value(DW_AT_stmt_list) {
                Ok(Some(AttributeValue::DebugLineRef(o))) => o,
                _ => continue,
            };
            let debug_line = obj.get_section(".debug_line").unwrap_or(&[]);
            let debug_line = DebugLine::<Endian>::new(debug_line);

            let prog = debug_line.program(offset, addr_size, None, None)?;
            if let Ok(mut addresses) = get_addresses_from_program(prog, &entries, &project) {
                result.append(&mut addresses);
            }
        }
    }
    // Due to rust being a higher level language multiple instructions may map
    // to the same line. This prunes these to just the first instruction address
    let mut check: HashSet<(&Path, u64)> = HashSet::new();
    let mut result = result.iter()
                           .filter(|x| check.insert((x.path.as_path(), x.line)))
                           .filter(|x| x.trace_type != LineType::TestMain)
                           .map(|x| x.clone())
                           .collect::<Vec<TracerData>>();
    let addresses = result.iter()
                          .map(|x| x.address)
                          .collect::<Vec<_>>();
    // TODO Probably a more idiomatic way to do this.
    {
        let test_entries = result.iter_mut()
                                 .filter(|x| match x.trace_type {
                                     LineType::TestEntry(_) => true,
                                     _ => false,
                                 });

        for ref mut test_entry in test_entries {
            let endpoint = match test_entry.trace_type {
                LineType::TestEntry(x) => x,
                _ => continue,
            };
            let max_address = addresses.iter()
                                       .fold(0, |acc, x| {
                                           if x > &(test_entry.address + acc) && (x-test_entry.address) <= endpoint {
                                               *x - test_entry.address
                                           } else {
                                               acc
                                           }
                                       });
            test_entry.trace_type = LineType::TestEntry(max_address);
        }
    }
    Ok(result)
}

/// Generates a list of lines we want to trace the coverage of. Used to instrument the
/// traces into the test executable
pub fn generate_tracer_data(manifest: &Path, test: &Path) -> io::Result<Vec<TracerData>> {
    let file = File::open(test)?;
    let file = Mmap::open(&file, Protection::Read)?;
    if let Ok(obj) = OFile::parse(unsafe {file.as_slice() }) {

        let data = if obj.is_little_endian() {
            get_line_addresses::<LittleEndian>(manifest, &obj)
        } else {
            get_line_addresses::<BigEndian>(manifest, &obj)
        };
        data.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Error while parsing"))
    } else {
        Err(io::Error::new(io::ErrorKind::InvalidData, "Unable to parse binary."))
    }
}
<|endoftext|>


<commit_before>//! This module provides usefull traits that where deprecated in rust

// Note copied from the stdlib under MIT license

use std::num::{ Float, Int, NumCast };

/// Num trait from old stdlib
pub trait Num: Zero + One + Add<Self, Self> + Sub<Self, Self> + Mul<Self, Self> + Div<Self, Self> + Rem<Self, Self> + Neg<Self> + PartialEq<Self> { }
impl<A: Zero + One + Add<A, A> + Sub<A, A> + Mul<A, A> + Div<A, A> + Rem<A, A> + Neg<A> + PartialEq<A>> Num for A { }

/// Zero trait from old stdlib
pub trait Zero: Add<Self, Self> {
    /// Returns the zero value for T
    fn zero() -> Self;
    /// Returns true if zero.
    fn is_zero(&self) -> bool;
}

/// Returns the zero value for T
#[allow(unused)]
pub fn zero<T: Zero>() -> T { Zero::zero() }
macro_rules! zero_impl {
    ($t:ty, $v:expr) => {
        impl Zero for $t {
            fn zero() -> $t { $v }
            fn is_zero(&self) -> bool { *self == $v }
        }
    }
}
zero_impl!(uint, 0u)
zero_impl!(u8,   0u8)
zero_impl!(u16,  0u16)
zero_impl!(u32,  0u32)
zero_impl!(u64,  0u64)
zero_impl!(int, 0i)
zero_impl!(i8,  0i8)
zero_impl!(i16, 0i16)
zero_impl!(i32, 0i32)
zero_impl!(i64, 0i64)
zero_impl!(f32, 0.0f32)
zero_impl!(f64, 0.0f64)

/// Primitive trait from old stdlib, added max_value
pub trait Primitive: Copy + NumCast + Num + PartialOrd<Self> + Clone + ::std::default::Default {
    /// The maximum value of primitive.
    fn max_value() -> Self;
}

impl Primitive for uint {
    fn max_value() -> uint { Int::max_value() }
}
impl Primitive for u8 {
    fn max_value() -> u8 { Int::max_value() }
}
impl Primitive for u16 {
    fn max_value() -> u16 { Int::max_value() }
}
impl Primitive for u32 {
    fn max_value() -> u32 { Int::max_value() }
}
impl Primitive for u64 {
    fn max_value() -> u64 { Int::max_value() }
}
impl Primitive for int {
    fn max_value() -> int { Int::max_value() }
}
impl Primitive for i8 {
    fn max_value() -> i8 { Int::max_value() }
}
impl Primitive for i16 {
    fn max_value() -> i16 { Int::max_value() }
}
impl Primitive for i32 {
    fn max_value() -> i32 { Int::max_value() }
}
impl Primitive for i64 {
    fn max_value() -> i64 { Int::max_value() }
}
impl Primitive for f32 {
    fn max_value() -> f32 { Float::max_value() }
}
impl Primitive for f64 {
    fn max_value() -> f64 { Float::max_value() }
}

/// One trait from old stdlib, added max_value
pub trait One: Mul<Self, Self> {
    /// Returns the unit value of Self
    fn one() -> Self;
}
/// Returns the unit value of T
#[allow(unused)]
pub fn one<T: One>() -> T { One::one() }
macro_rules! one_impl {
    ($t:ty, $v:expr) => {
        impl One for $t {
            fn one() -> $t { $v }
        }
    }
}
one_impl!(uint, 1u)
one_impl!(u8,  1u8)
one_impl!(u16, 1u16)
one_impl!(u32, 1u32)
one_impl!(u64, 1u64)
one_impl!(int, 1i)
one_impl!(i8,  1i8)
one_impl!(i16, 1i16)
one_impl!(i32, 1i32)
one_impl!(i64, 1i64)
one_impl!(f32, 1.0f32)
one_impl!(f64, 1.0f64)<commit_msg>remove trait bound<commit_after>//! This module provides usefull traits that where deprecated in rust

// Note copied from the stdlib under MIT license

use std::num::{ Float, Int, NumCast };

/// Num trait from old stdlib
pub trait Num: Zero + One + Add<Self, Self> + Sub<Self, Self> + Mul<Self, Self> + Div<Self, Self> + Rem<Self, Self> + Neg<Self> + PartialEq<Self> { }
impl<A: Zero + One + Add<A, A> + Sub<A, A> + Mul<A, A> + Div<A, A> + Rem<A, A> + Neg<A> + PartialEq<A>> Num for A { }

/// Zero trait from old stdlib
pub trait Zero: Add<Self, Self> {
    /// Returns the zero value for T
    fn zero() -> Self;
    /// Returns true if zero.
    fn is_zero(&self) -> bool;
}

/// Returns the zero value for T
#[allow(unused)]
pub fn zero<T: Zero>() -> T { Zero::zero() }
macro_rules! zero_impl {
    ($t:ty, $v:expr) => {
        impl Zero for $t {
            fn zero() -> $t { $v }
            fn is_zero(&self) -> bool { *self == $v }
        }
    }
}
zero_impl!(uint, 0u)
zero_impl!(u8,   0u8)
zero_impl!(u16,  0u16)
zero_impl!(u32,  0u32)
zero_impl!(u64,  0u64)
zero_impl!(int, 0i)
zero_impl!(i8,  0i8)
zero_impl!(i16, 0i16)
zero_impl!(i32, 0i32)
zero_impl!(i64, 0i64)
zero_impl!(f32, 0.0f32)
zero_impl!(f64, 0.0f64)

/// Primitive trait from old stdlib, added max_value
pub trait Primitive: Copy + NumCast + Num + PartialOrd<Self> + Clone {
    /// The maximum value of primitive.
    fn max_value() -> Self;
}

impl Primitive for uint {
    fn max_value() -> uint { Int::max_value() }
}
impl Primitive for u8 {
    fn max_value() -> u8 { Int::max_value() }
}
impl Primitive for u16 {
    fn max_value() -> u16 { Int::max_value() }
}
impl Primitive for u32 {
    fn max_value() -> u32 { Int::max_value() }
}
impl Primitive for u64 {
    fn max_value() -> u64 { Int::max_value() }
}
impl Primitive for int {
    fn max_value() -> int { Int::max_value() }
}
impl Primitive for i8 {
    fn max_value() -> i8 { Int::max_value() }
}
impl Primitive for i16 {
    fn max_value() -> i16 { Int::max_value() }
}
impl Primitive for i32 {
    fn max_value() -> i32 { Int::max_value() }
}
impl Primitive for i64 {
    fn max_value() -> i64 { Int::max_value() }
}
impl Primitive for f32 {
    fn max_value() -> f32 { Float::max_value() }
}
impl Primitive for f64 {
    fn max_value() -> f64 { Float::max_value() }
}

/// One trait from old stdlib, added max_value
pub trait One: Mul<Self, Self> {
    /// Returns the unit value of Self
    fn one() -> Self;
}
/// Returns the unit value of T
#[allow(unused)]
pub fn one<T: One>() -> T { One::one() }
macro_rules! one_impl {
    ($t:ty, $v:expr) => {
        impl One for $t {
            fn one() -> $t { $v }
        }
    }
}
one_impl!(uint, 1u)
one_impl!(u8,  1u8)
one_impl!(u16, 1u16)
one_impl!(u32, 1u32)
one_impl!(u64, 1u64)
one_impl!(int, 1i)
one_impl!(i8,  1i8)
one_impl!(i16, 1i16)
one_impl!(i32, 1i32)
one_impl!(i64, 1i64)
one_impl!(f32, 1.0f32)
one_impl!(f64, 1.0f64)<|endoftext|>


<commit_before>use error::PackageError;
use std::fs::{ File, metadata };
use std::path::Path;
use tar::Archive;

fn unpack_tar(input: &Path, target: &Path) -> Result<u64, PackageError> {
    let file = File::open(input)?;
    let mut archive = Archive::new(file);
    archive.unpack(target)?;
    let target_file = metadata(target)?;
    Ok(target_file.len())
}

fn unpack_gzip() {

}<commit_msg>Function for unpacking gzip.<commit_after>use error::PackageError;
use flate2::bufread::GzDecoder;
use std::fs::{ File, metadata };
use std::io::{ BufReader, BufWriter, Read, Write };
use std::path::Path;
use tar::Archive;

fn unpack_tar(input: &Path, target: &Path) -> Result<u64, PackageError> {
    let file = File::open(input)?;
    let mut archive = Archive::new(file);
    archive.unpack(target)?;
    let target_file = metadata(target)?;
    Ok(target_file.len())
}

fn unpack_gzip(input: &Path, target: &Path) -> Result<u64, PackageError> {
    let file = File::open(input)?;
    let decoder = GzDecoder::new(BufReader::new(file))?;
    let target = File::create(target)?;
    let mut target = BufWriter::new(target);
    let mut bytes = 0;
    for byte in decoder.bytes() {
        target.write(&[byte?])?;
        bytes += 1;
    }
    Ok(bytes)
}<|endoftext|>