<commit_before>use libusb::{
    LogLevel,
    Context,
    DeviceHandle,
    AsyncGroup,
    Result as UsbResult,
    Error,
};

use consts;

pub struct UsbWrapper {
    context: &'static Context,
    pub handle: &'static DeviceHandle<'static>,
    has_kernel_driver0: bool,
    has_kernel_driver1: bool,
    pub async_group: &'static mut AsyncGroup<'static>,
}

impl UsbWrapper {
    pub fn new() -> UsbResult<UsbWrapper> {
        // We must leak both context and handle and async_group, as rust does not allow sibling structs.
        // Leaking them gives us a &'static reference, which we can then use without
        // lifetime bounds, as it outlives everything.
        // We must make sure though, that the leaked memory is freed afterwards,
        // which is done in Drop.
        let context = try!(get_context());
        let context_ptr = Box::into_raw(Box::new(context));
        let context_ref = unsafe { &*context_ptr as &'static Context };
        let (handle, driver0, driver1) = try!(get_handle(context_ref));
        let async_group = AsyncGroup::new(context_ref);
        let handle_ptr = Box::into_raw(Box::new(handle));
        let async_ptr = Box::into_raw(Box::new(async_group));
        unsafe {
            Ok(UsbWrapper {
                context: context_ref,
                handle: &mut *handle_ptr as &'static mut DeviceHandle<'static>,
                has_kernel_driver0: driver0,
                has_kernel_driver1: driver1,
                async_group: &mut *async_ptr as &'static mut AsyncGroup<'static>,
            })
        }
    }
}

macro_rules! unwrap_safe {
    ($e:expr) => {
        if ::std::thread::panicking() {
            match $e {
                Ok(_) => {},
                Err(e) => println!("Error while dropping UsbWrapper during another panic: {:?}", e),
            }
        } else {
            $e.unwrap();
        }
    }
}

impl Drop for UsbWrapper {
    fn drop(&mut self) {
        // make sure handle_mut is dropped before dropping it's refering content
        // this assures that there will be no dangling pointers
        {
            let handle_mut = unsafe { &mut *(self.handle as *const _ as *mut DeviceHandle<'static>) };
            unwrap_safe!(handle_mut.release_interface(1));
            unwrap_safe!(handle_mut.release_interface(0));
            if self.has_kernel_driver1 {
                unwrap_safe!(handle_mut.attach_kernel_driver(1));
            }
            if self.has_kernel_driver0 {
                unwrap_safe!(handle_mut.attach_kernel_driver(0));
            }
        }
        // first, drop async_group to release all captured references to the DeviceHandle
        let async_ptr = &mut *self.async_group as *mut AsyncGroup<'static>;
        drop(unsafe { Box::from_raw(async_ptr) });
        // then, drop the DeviceHandle to release Context
        let handle_ptr = &*self.handle as *const _ as *mut DeviceHandle<'static>;
        drop(unsafe { Box::from_raw(handle_ptr) });
        let context_ptr = self.context as *const _ as *mut Context;
        drop(unsafe { Box::from_raw(context_ptr) });
    }
}

fn get_context() -> UsbResult<Context> {
    let mut context = try!(Context::new());
    context.set_log_level(LogLevel::Debug);
    context.set_log_level(LogLevel::Info);
    context.set_log_level(LogLevel::Warning);
    context.set_log_level(LogLevel::Error);
    context.set_log_level(LogLevel::None);
    Ok(context)
}

fn get_handle<'a>(context: &'a Context) -> UsbResult<(DeviceHandle<'a>, bool, bool)> {
    let devices = try!(context.devices());
    for d in devices.iter() {
        let dd = match d.device_descriptor() {
            Ok(dd) => dd,
            Err(_) => continue
        };
        if dd.vendor_id() == consts::VENDOR_ID && dd.product_id() == consts::PRODUCT_ID {
            let mut handle = try!(d.open());
            // for some reason we cannot claim interface 2 as it doesn't exist
            // but we will be able to read from it, if we claim interface 1
            // detch kernel driver
            let has_kernel_driver0 = try!(detach(&mut handle, 0));
            let has_kernel_driver1 = try!(detach(&mut handle, 1));
            // claim interfaces
            try!(handle.claim_interface(0));
            try!(handle.claim_interface(1));
            // reset keyboard to get clean status
            try!(handle.reset());
            return Ok((handle, has_kernel_driver0, has_kernel_driver1));
        }
    }
    Err(Error::NoDevice)
}

fn detach(handle: &mut DeviceHandle, iface: u8) -> UsbResult<bool> {
    match handle.kernel_driver_active(iface) {
        Ok(true) => {
            try!(handle.detach_kernel_driver(iface));
            Ok(true)
        },
        _ => Ok(false)
    }

}

<commit_msg>fix(util): Don't unwrap during drop<commit_after>use libusb::{
    LogLevel,
    Context,
    DeviceHandle,
    AsyncGroup,
    Result as UsbResult,
    Error,
};

use consts;

pub struct UsbWrapper {
    context: &'static Context,
    pub handle: &'static DeviceHandle<'static>,
    has_kernel_driver0: bool,
    has_kernel_driver1: bool,
    pub async_group: &'static mut AsyncGroup<'static>,
}

impl UsbWrapper {
    pub fn new() -> UsbResult<UsbWrapper> {
        // We must leak both context and handle and async_group, as rust does not allow sibling structs.
        // Leaking them gives us a &'static reference, which we can then use without
        // lifetime bounds, as it outlives everything.
        // We must make sure though, that the leaked memory is freed afterwards,
        // which is done in Drop.
        let context = try!(get_context());
        let context_ptr = Box::into_raw(Box::new(context));
        let context_ref = unsafe { &*context_ptr as &'static Context };
        let (handle, driver0, driver1) = try!(get_handle(context_ref));
        let async_group = AsyncGroup::new(context_ref);
        let handle_ptr = Box::into_raw(Box::new(handle));
        let async_ptr = Box::into_raw(Box::new(async_group));
        unsafe {
            Ok(UsbWrapper {
                context: context_ref,
                handle: &mut *handle_ptr as &'static mut DeviceHandle<'static>,
                has_kernel_driver0: driver0,
                has_kernel_driver1: driver1,
                async_group: &mut *async_ptr as &'static mut AsyncGroup<'static>,
            })
        }
    }
}

macro_rules! unwrap_safe {
    ($e:expr) => {
        match $e {
            Ok(_) => {},
            Err(e) => println!("Error while dropping UsbWrapper during another panic: {:?}", e),
        }
    }
}

impl Drop for UsbWrapper {
    fn drop(&mut self) {
        // make sure handle_mut is dropped before dropping it's refering content
        // this assures that there will be no dangling pointers
        {
            let handle_mut = unsafe { &mut *(self.handle as *const _ as *mut DeviceHandle<'static>) };
            unwrap_safe!(handle_mut.release_interface(1));
            unwrap_safe!(handle_mut.release_interface(0));
            if self.has_kernel_driver1 {
                unwrap_safe!(handle_mut.attach_kernel_driver(1));
            }
            if self.has_kernel_driver0 {
                unwrap_safe!(handle_mut.attach_kernel_driver(0));
            }
        }
        // first, drop async_group to release all captured references to the DeviceHandle
        let async_ptr = &mut *self.async_group as *mut AsyncGroup<'static>;
        drop(unsafe { Box::from_raw(async_ptr) });
        // then, drop the DeviceHandle to release Context
        let handle_ptr = &*self.handle as *const _ as *mut DeviceHandle<'static>;
        drop(unsafe { Box::from_raw(handle_ptr) });
        let context_ptr = self.context as *const _ as *mut Context;
        drop(unsafe { Box::from_raw(context_ptr) });
    }
}

fn get_context() -> UsbResult<Context> {
    let mut context = try!(Context::new());
    context.set_log_level(LogLevel::Debug);
    context.set_log_level(LogLevel::Info);
    context.set_log_level(LogLevel::Warning);
    context.set_log_level(LogLevel::Error);
    context.set_log_level(LogLevel::None);
    Ok(context)
}

fn get_handle<'a>(context: &'a Context) -> UsbResult<(DeviceHandle<'a>, bool, bool)> {
    let devices = try!(context.devices());
    for d in devices.iter() {
        let dd = match d.device_descriptor() {
            Ok(dd) => dd,
            Err(_) => continue
        };
        if dd.vendor_id() == consts::VENDOR_ID && dd.product_id() == consts::PRODUCT_ID {
            let mut handle = try!(d.open());
            // for some reason we cannot claim interface 2 as it doesn't exist
            // but we will be able to read from it, if we claim interface 1
            // detch kernel driver
            let has_kernel_driver0 = try!(detach(&mut handle, 0));
            let has_kernel_driver1 = try!(detach(&mut handle, 1));
            // claim interfaces
            try!(handle.claim_interface(0));
            try!(handle.claim_interface(1));
            // reset keyboard to get clean status
            try!(handle.reset());
            return Ok((handle, has_kernel_driver0, has_kernel_driver1));
        }
    }
    Err(Error::NoDevice)
}

fn detach(handle: &mut DeviceHandle, iface: u8) -> UsbResult<bool> {
    match handle.kernel_driver_active(iface) {
        Ok(true) => {
            try!(handle.detach_kernel_driver(iface));
            Ok(true)
        },
        _ => Ok(false)
    }

}

<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use wrap::Wrapper;

use std::mem;
use std::ops::Deref;

pub trait Refcount {
    unsafe fn inc_ref(&self);
    unsafe fn dec_ref(&self);
}

pub struct Ref<T> where T: Refcount {
    ptr: *const T
}

unsafe impl<T> Send for Ref<T> where T: Refcount + Send { }
unsafe impl<T> Sync for Ref<T> where T: Refcount + Sync { }

impl<T> Ref<T> where T: Refcount {

    pub fn new(source: &T) -> Ref<T> {
        unsafe {
            source.inc_ref();
        }
        Ref { ptr: source as *const T }
    }
}

impl<T> Ref<T> where T: Refcount + Wrapper {

    pub unsafe fn from_raw(ptr: *mut <T as Wrapper>::Raw) -> Ref<T> {
        Ref { ptr: ptr as *const T }
    }

    pub unsafe fn into_raw(self) -> *mut <T as Wrapper>::Raw {
        let ptr = self.ptr;
        mem::forget(self);
        ptr as *mut _
    }
}

#[unsafe_destructor]
impl<T> Drop for Ref<T> where T: Refcount {
    fn drop(&mut self) {
        unsafe {
            self.dec_ref();
        }
    }
}

impl<T> Clone for Ref<T> where T: Refcount {

    fn clone(&self) -> Ref<T> {
        Ref::new(self.deref())
    }

    fn clone_from(&mut self, source: &Ref<T>) {
        unsafe {
            source.inc_ref();
            self.dec_ref();
        }
        self.ptr = source.ptr;
    }
}

impl<T> Deref for Ref<T> {

    type Target = T;

    fn deref(&self) -> &T {
        unsafe { mem::copy_lifetime(self, &*self.ptr) }
    }
}
<commit_msg>refcount: removed an unnecessary copy_lifetime<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use wrap::Wrapper;

use std::mem;
use std::ops::Deref;

pub trait Refcount {
    unsafe fn inc_ref(&self);
    unsafe fn dec_ref(&self);
}

pub struct Ref<T> where T: Refcount {
    ptr: *const T
}

unsafe impl<T> Send for Ref<T> where T: Refcount + Send { }
unsafe impl<T> Sync for Ref<T> where T: Refcount + Sync { }

impl<T> Ref<T> where T: Refcount {

    pub fn new(source: &T) -> Ref<T> {
        unsafe {
            source.inc_ref();
        }
        Ref { ptr: source as *const T }
    }
}

impl<T> Ref<T> where T: Refcount + Wrapper {

    pub unsafe fn from_raw(ptr: *mut <T as Wrapper>::Raw) -> Ref<T> {
        Ref { ptr: ptr as *const T }
    }

    pub unsafe fn into_raw(self) -> *mut <T as Wrapper>::Raw {
        let ptr = self.ptr;
        mem::forget(self);
        ptr as *mut _
    }
}

#[unsafe_destructor]
impl<T> Drop for Ref<T> where T: Refcount {
    fn drop(&mut self) {
        unsafe {
            self.dec_ref();
        }
    }
}

impl<T> Clone for Ref<T> where T: Refcount {

    fn clone(&self) -> Ref<T> {
        Ref::new(self.deref())
    }

    fn clone_from(&mut self, source: &Ref<T>) {
        unsafe {
            source.inc_ref();
            self.dec_ref();
        }
        self.ptr = source.ptr;
    }
}

impl<T> Deref for Ref<T> {

    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.ptr }
    }
}
<|endoftext|>


<commit_before>//!
//!  synth_voice.rs
//!
//!  Created by Mitchell Nordine at 04:01PM on June 28, 2014.
//!
//!

use dsp::Settings as DspSettings;
use dsp::{Sample};
use oscillator::Oscillator;
use time::{self, Samples};

pub type Playhead = time::calc::Samples;
pub type LoopStart = time::calc::Samples;
pub type LoopEnd = time::calc::Samples;
pub type Attack = time::calc::Samples;
pub type Release = time::calc::Samples;
pub type LoopPlayhead = time::calc::Samples;
pub type NoteDuration = time::calc::Samples;
pub type NoteFreqMulti = f64;
pub type NoteHz = f32;
pub type NoteVelocity = f32;

/// A single Voice. A Synth may consist
/// of any number of Voices.
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct Voice {
    /// The current phase for each oscillator owned by the Synth.
    pub oscillator_phases: Vec<f64>,
    /// Data for a note, if there is one currently being played.
    pub maybe_note: Option<(NoteState, NoteHz, NoteFreqMulti, NoteVelocity)>,
    /// Playhead over the current note.
    pub playhead: Playhead,
    /// Playhead over the loop duration.
    pub loop_playhead: LoopPlayhead,
}

/// The current state of the Voice's note playback.
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum NoteState {
    /// The note is current playing.
    Playing,
    /// The note has been released and is fading out.
    Released(Playhead),
}

impl Voice {

    /// Constructor for a Voice.
    pub fn new(num_oscillators: usize) -> Voice {
        Voice {
            oscillator_phases: (0..num_oscillators).map(|_| 0.0).collect(),
            maybe_note: None,
            playhead: 0,
            loop_playhead: 0,
        }
    }

    /// Default constructor for a Voice with a single Oscillator.
    pub fn default() -> Voice { Voice::new(1) }

    /// Trigger playback with the given note, resetting all playheads.
    #[inline]
    pub fn note_on(&mut self, hz: NoteHz, freq_multi: NoteFreqMulti, vel: NoteVelocity) {
        self.maybe_note = Some((NoteState::Playing, hz, freq_multi, vel));
        self.playhead = 0;
        self.loop_playhead = 0;
    }

    /// Release playback of the current not eif there is one.
    #[inline]
    pub fn note_off(&mut self) {
        self.maybe_note = self.maybe_note.map(|(_, h, m, v)| (NoteState::Released(0), h, m, v));
    }

    /// Stop playback of the current note if there is one and reset the playheads.
    #[inline]
    pub fn stop(&mut self) {
        for phase in self.oscillator_phases.iter_mut() { *phase = 0.0; }
        self.maybe_note = None;
        self.playhead = 0;
        self.loop_playhead = 0;
    }

    /// Generate and fill the audio buffer for the given parameters.
    #[inline]
    pub fn fill_buffer<S>(&mut self,
                          output: &mut [S],
                          settings: DspSettings,
                          oscillators: &[Oscillator],
                          duration: time::calc::Samples,
                          loop_data: Option<&(LoopStart, LoopEnd)>,
                          fade_data: Option<&(Attack, Release)>)
        where S: Sample
    {
        let Voice {
            ref mut oscillator_phases,
            ref mut playhead,
            ref mut loop_playhead,
            ref mut maybe_note,
        } = *self;

        let (attack, release) = fade_data.map_or_else(|| (0, 0), |&(a, r)| (a, r));
        let (freq_multi, velocity) = maybe_note.map_or_else(|| (1.0, 1.0), |(_, _, m, v)| (m, v));

        for frame in output.chunks_mut(settings.channels as usize) {

            // Calculate the amplitude of the current frame.
            let wave = if maybe_note.is_some() && *loop_playhead < duration {
                let ratio = *loop_playhead as f64 / duration as f64;
                let note_state = maybe_note.map(|(state, _, _, _)| state).unwrap();
                // Sum the amplitude of each oscillator at the given ratio.
                let active_oscillators = oscillators.iter().filter(|osc| !osc.is_muted);
                active_oscillators.enumerate().fold(0.0, |total, (i, osc)| {
                    let phase = &mut oscillator_phases[i];
                    let mut wave = osc.amp_at_ratio(*phase, ratio);
                    *phase = osc.next_phase(*phase, ratio, freq_multi, settings.sample_hz as f64);
                    // If within the attack duration, apply the fade.
                    if *playhead < attack {
                        wave *= *playhead as f32 / attack as f32;
                    }
                    // If within the release duration, apply the fade.
                    if let NoteState::Released(release_playhead) = note_state {
                        wave *= (release - release_playhead) as f32 / release as f32;
                    }
                    wave + total
                })
            } else {
                // If the playhead is out of range or if there is no note, zero the frame.
                0.0
            };

            // Assign the amp to each channel.
            for channel in frame.iter_mut() {
                *channel = Sample::from_wave(wave * velocity);
            }

            // Iterate the release playhead and check for whether or not the release playhead
            // exceeds the release limit. If it does, reset the note.
            let note_should_reset = match *maybe_note {
                Some((NoteState::Released(ref mut release_playhead), _, _, _)) => {
                    *release_playhead += 1;
                    *release_playhead > release
                },
                None => continue,
                _ => false,
            };
            if note_should_reset {
                *maybe_note = None;
                *playhead = 0;
            }

            // Iterate the loop_playhead. If the loop_playhead passes the loop_end,
            // reset the playhead to the start.
            *loop_playhead += 1;
            if let Some(&(loop_start, loop_end)) = loop_data {
                if *loop_playhead >= loop_end {
                    *loop_playhead = (*loop_playhead - loop_end) + loop_start;
                }
            }

            // Iterate the playhead. If the playhead passes the duration of the instrument or
            // the note that is currently being played, reset the playhead and stop playback.
            *playhead += 1;
            if *playhead >= duration + release || *loop_playhead > duration {
                *maybe_note = None;
                *playhead = 0;
            }

        }

    }

}

<commit_msg>Removed unnecessary Voice::default method<commit_after>//!
//!  synth_voice.rs
//!
//!  Created by Mitchell Nordine at 04:01PM on June 28, 2014.
//!
//!

use dsp::Settings as DspSettings;
use dsp::{Sample};
use oscillator::Oscillator;
use time::{self, Samples};

pub type Playhead = time::calc::Samples;
pub type LoopStart = time::calc::Samples;
pub type LoopEnd = time::calc::Samples;
pub type Attack = time::calc::Samples;
pub type Release = time::calc::Samples;
pub type LoopPlayhead = time::calc::Samples;
pub type NoteDuration = time::calc::Samples;
pub type NoteFreqMulti = f64;
pub type NoteHz = f32;
pub type NoteVelocity = f32;

/// A single Voice. A Synth may consist
/// of any number of Voices.
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct Voice {
    /// The current phase for each oscillator owned by the Synth.
    pub oscillator_phases: Vec<f64>,
    /// Data for a note, if there is one currently being played.
    pub maybe_note: Option<(NoteState, NoteHz, NoteFreqMulti, NoteVelocity)>,
    /// Playhead over the current note.
    pub playhead: Playhead,
    /// Playhead over the loop duration.
    pub loop_playhead: LoopPlayhead,
}

/// The current state of the Voice's note playback.
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum NoteState {
    /// The note is current playing.
    Playing,
    /// The note has been released and is fading out.
    Released(Playhead),
}

impl Voice {

    /// Constructor for a Voice.
    pub fn new(num_oscillators: usize) -> Voice {
        Voice {
            oscillator_phases: (0..num_oscillators).map(|_| 0.0).collect(),
            maybe_note: None,
            playhead: 0,
            loop_playhead: 0,
        }
    }

    /// Trigger playback with the given note, resetting all playheads.
    #[inline]
    pub fn note_on(&mut self, hz: NoteHz, freq_multi: NoteFreqMulti, vel: NoteVelocity) {
        self.maybe_note = Some((NoteState::Playing, hz, freq_multi, vel));
        self.playhead = 0;
        self.loop_playhead = 0;
    }

    /// Release playback of the current not eif there is one.
    #[inline]
    pub fn note_off(&mut self) {
        self.maybe_note = self.maybe_note.map(|(_, h, m, v)| (NoteState::Released(0), h, m, v));
    }

    /// Stop playback of the current note if there is one and reset the playheads.
    #[inline]
    pub fn stop(&mut self) {
        for phase in self.oscillator_phases.iter_mut() { *phase = 0.0; }
        self.maybe_note = None;
        self.playhead = 0;
        self.loop_playhead = 0;
    }

    /// Generate and fill the audio buffer for the given parameters.
    #[inline]
    pub fn fill_buffer<S>(&mut self,
                          output: &mut [S],
                          settings: DspSettings,
                          oscillators: &[Oscillator],
                          duration: time::calc::Samples,
                          loop_data: Option<&(LoopStart, LoopEnd)>,
                          fade_data: Option<&(Attack, Release)>)
        where S: Sample
    {
        let Voice {
            ref mut oscillator_phases,
            ref mut playhead,
            ref mut loop_playhead,
            ref mut maybe_note,
        } = *self;

        let (attack, release) = fade_data.map_or_else(|| (0, 0), |&(a, r)| (a, r));
        let (freq_multi, velocity) = maybe_note.map_or_else(|| (1.0, 1.0), |(_, _, m, v)| (m, v));

        for frame in output.chunks_mut(settings.channels as usize) {

            // Calculate the amplitude of the current frame.
            let wave = if maybe_note.is_some() && *loop_playhead < duration {
                let ratio = *loop_playhead as f64 / duration as f64;
                let note_state = maybe_note.map(|(state, _, _, _)| state).unwrap();
                // Sum the amplitude of each oscillator at the given ratio.
                let active_oscillators = oscillators.iter().filter(|osc| !osc.is_muted);
                active_oscillators.enumerate().fold(0.0, |total, (i, osc)| {
                    let phase = &mut oscillator_phases[i];
                    let mut wave = osc.amp_at_ratio(*phase, ratio);
                    *phase = osc.next_phase(*phase, ratio, freq_multi, settings.sample_hz as f64);
                    // If within the attack duration, apply the fade.
                    if *playhead < attack {
                        wave *= *playhead as f32 / attack as f32;
                    }
                    // If within the release duration, apply the fade.
                    if let NoteState::Released(release_playhead) = note_state {
                        wave *= (release - release_playhead) as f32 / release as f32;
                    }
                    wave + total
                })
            } else {
                // If the playhead is out of range or if there is no note, zero the frame.
                0.0
            };

            // Assign the amp to each channel.
            for channel in frame.iter_mut() {
                *channel = Sample::from_wave(wave * velocity);
            }

            // Iterate the release playhead and check for whether or not the release playhead
            // exceeds the release limit. If it does, reset the note.
            let note_should_reset = match *maybe_note {
                Some((NoteState::Released(ref mut release_playhead), _, _, _)) => {
                    *release_playhead += 1;
                    *release_playhead > release
                },
                None => continue,
                _ => false,
            };
            if note_should_reset {
                *maybe_note = None;
                *playhead = 0;
            }

            // Iterate the loop_playhead. If the loop_playhead passes the loop_end,
            // reset the playhead to the start.
            *loop_playhead += 1;
            if let Some(&(loop_start, loop_end)) = loop_data {
                if *loop_playhead >= loop_end {
                    *loop_playhead = (*loop_playhead - loop_end) + loop_start;
                }
            }

            // Iterate the playhead. If the playhead passes the duration of the instrument or
            // the note that is currently being played, reset the playhead and stop playback.
            *playhead += 1;
            if *playhead >= duration + release || *loop_playhead > duration {
                *maybe_note = None;
                *playhead = 0;
            }

        }

    }

}

<|endoftext|>


<commit_before>/* Copyright (c) 2016
 * Jeff Nettleton
 *
 * Licensed under the MIT license (http://opensource.org/licenses/MIT). This
 * file may not be copied, modified, or distributed except according to those
 * terms
 */

extern crate chrono;

use std::collections::HashMap;
use utils::make_response;

pub trait ToOutput {
    fn to_output(&self) -> &[u8];
}

impl ToOutput for str {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for &'static str {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for String {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for Vec<u8> {
    fn to_output(&self) -> &[u8] {
        self.as_slice()
    }
}

#[derive(Debug)]
pub struct Response {
    code:       u16,
    cmsg:       String,
    ctype:      String,
    headers:    HashMap<String, String>,
    payload:    Vec<u8>,
}

impl Response {
    pub fn new() -> Response {
        let mut res = Response {
            code:       200,
            cmsg:       String::from("OK"),
            ctype:      String::from("text/plain"),
            headers:    HashMap::new(),
            payload:    Vec::with_capacity(2048),
        };

        let now = chrono::UTC::now().format("%a, %d %b %Y, %H:%M:%S GMT").to_string();

        res.add_header("Connection", "close");
        res.add_header("Server", "canteen/0.0.1");
        res.add_header("Date", &now);

        res
    }

    pub fn get_http_message(code: u16) -> String {
        let msg = match code {
            100 => "Continue",
            101 => "Switching Protocols",
            200 => "OK",
            201 => "Created",
            202 => "Accepted",
            203 => "Non-Authoritative Information",
            204 => "No Content",
            205 => "Reset Content",
            206 => "Partial Content",
            300 => "Multiple Choices",
            301 => "Moved Permanently",
            302 => "Found",
            303 => "See Other",
            304 => "Not Modified",
            305 => "Use Proxy",
            307 => "Temporary Redirect",
            400 => "Bad Request",
            401 => "Unauthorized",
            402 => "Payment Required",
            403 => "Forbidden",
            404 => "Not Found",
            405 => "Method Not Allowed",
            406 => "Not Acceptable",
            407 => "Proxy Authentication Required",
            408 => "Request Time Out",
            409 => "Conflict",
            410 => "Gone",
            411 => "Length Required",
            412 => "Precondition Failed",
            413 => "Request Entity Too Large",
            414 => "Request-URI Too Large",
            415 => "Unsupported Media Type",
            416 => "Requested Range Not Satisfiable",
            417 => "Expectation Failed",
            500 => "Internal Server Error",
            501 => "Not Implemented",
            502 => "Bad Gateway",
            503 => "Service Unavailable",
            504 => "Gateway Time-out",
            505 => "HTTP Version Not Supported",
            _   => "OK",
        };

        String::from(msg)
    }

    fn err_body(message: &str, path: &str) -> String {
        format!("\
                 \

Your request failed

{}: {}
", message, path)
    }

    pub fn err_403(path: &str) -> Response {
        make_response(Response::err_body("forbidden", path), "text/html", 403)
    }

    pub fn err_404(path: &str) -> Response {
        make_response(Response::err_body("not found", path), "text/html", 403)
    }

    pub fn err_500(path: &str) -> Response {
        make_response(Response::err_body("internal server error", path), "text/html", 500)
    }

    /* set the response code
     * ex: res.set_code(200, "OK");
     */
    pub fn set_code(&mut self, code: u16) {
        self.code = code;
        self.cmsg = Response::get_http_message(code);
    }

    /* set the content type
     * ex: res.set_content_type("text/html");
     */
    pub fn set_content_type(&mut self, ctype: &str) {
        self.ctype = String::from(ctype);
    }

    /* add an HTTP header
     * ex: res.add_header("Connection", "close");
     */
    pub fn add_header(&mut self, key: &str, value: &str) {
        if !self.headers.contains_key(key) {
            self.headers.insert(String::from(key), String::from(value));
        }
    }

    /* add data to the payload -- can take any type that has
     * implemented the canteen::response::ToOutput trait
     */
    pub fn append<T: ToOutput>(&mut self, payload: T) {
        self.payload.extend(payload.to_output().into_iter());
    }

    pub fn gen_output(&self) -> Vec<u8> {
        let mut output: Vec<u8> = Vec::with_capacity(self.payload.len() + 500);
        let mut inter = String::new();

        inter.push_str(&format!("HTTP/1.1 {} {}\r\n", self.code, self.cmsg));

        for (key, value) in &self.headers {
            inter.push_str(&format!("{}: {}\r\n", key, value));
        }

        inter.push_str(&format!("Content-Type: {}\r\n", self.ctype));
        inter.push_str(&format!("Content-Length: {}\r\n", self.payload.len()));
        inter.push_str("\r\n");

        output.extend(inter.as_bytes());
        output.extend(self.payload.iter());

        output
    }
}
<commit_msg>document canteen::response in the Rust doc style<commit_after>// Copyright (c) 2016
// Jeff Nettleton
//
// Licensed under the MIT license (http://opensource.org/licenses/MIT). This
// file may not be copied, modified, or distributed except according to those
// terms

extern crate chrono;

use std::collections::HashMap;

/// A trait that converts data from the handler function to a u8 slice.
pub trait ToOutput {
    fn to_output(&self) -> &[u8];
}

impl ToOutput for str {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for &'static str {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for String {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for Vec<u8> {
    fn to_output(&self) -> &[u8] {
        self.as_slice()
    }
}

/// This struct reprsents the response to an HTTP client.
#[derive(Debug)]
pub struct Response {
    code:       u16,
    cmsg:       String,
    ctype:      String,
    headers:    HashMap<String, String>,
    payload:    Vec<u8>,
}

impl Response {
    /// Create a new, empty Response.
    pub fn new() -> Response {
        let mut res = Response {
            code:       200,
            cmsg:       String::from("OK"),
            ctype:      String::from("text/plain"),
            headers:    HashMap::new(),
            payload:    Vec::with_capacity(2048),
        };

        let now = chrono::UTC::now().format("%a, %d %b %Y, %H:%M:%S GMT").to_string();

        res.add_header("Connection", "close");
        res.add_header("Server", "canteen/0.0.1");
        res.add_header("Date", &now);

        res
    }

    /// Gets the HTTP message for a given code.
    pub fn get_http_message(code: u16) -> String {
        let msg = match code {
            100 => "Continue",
            101 => "Switching Protocols",
            200 => "OK",
            201 => "Created",
            202 => "Accepted",
            203 => "Non-Authoritative Information",
            204 => "No Content",
            205 => "Reset Content",
            206 => "Partial Content",
            300 => "Multiple Choices",
            301 => "Moved Permanently",
            302 => "Found",
            303 => "See Other",
            304 => "Not Modified",
            305 => "Use Proxy",
            307 => "Temporary Redirect",
            400 => "Bad Request",
            401 => "Unauthorized",
            402 => "Payment Required",
            403 => "Forbidden",
            404 => "Not Found",
            405 => "Method Not Allowed",
            406 => "Not Acceptable",
            407 => "Proxy Authentication Required",
            408 => "Request Time Out",
            409 => "Conflict",
            410 => "Gone",
            411 => "Length Required",
            412 => "Precondition Failed",
            413 => "Request Entity Too Large",
            414 => "Request-URI Too Large",
            415 => "Unsupported Media Type",
            416 => "Requested Range Not Satisfiable",
            417 => "Expectation Failed",
            500 => "Internal Server Error",
            501 => "Not Implemented",
            502 => "Bad Gateway",
            503 => "Service Unavailable",
            504 => "Gateway Time-out",
            505 => "HTTP Version Not Supported",
            _   => "OK",
        };

        String::from(msg)
    }

    /// Sets the response code for the HTTP response.
    ///
    /// # Examples
    ///
    /// ```
    /// res.set_code(200);
    /// ```
    pub fn set_code(&mut self, code: u16) {
        self.code = code;
        self.cmsg = Response::get_http_message(code);
    }

    /// Sets the Content-Type header for the HTTP response.
    ///
    /// # Examples
    ///
    /// ```
    /// res.set_content_type("text/html");
    /// ```
    pub fn set_content_type(&mut self, ctype: &str) {
        self.ctype = String::from(ctype);
    }

    /// Adds a header to the HTTP response.
    ///
    /// # Examples
    ///
    /// ```
    /// res.add_header("Content-Type", "text/html");
    /// ```
    pub fn add_header(&mut self, key: &str, value: &str) {
        if !self.headers.contains_key(key) {
            self.headers.insert(String::from(key), String::from(value));
        }
    }

    /// Appends data to the body of the HTTP response. The trait ToOutput must
    /// be implemented for the type passed.
    ///
    /// # Examples
    ///
    /// ```
    /// let data = "{ message: \"Hello, world!\" }";
    /// res.append(data);
    /// ```
    pub fn append<T: ToOutput>(&mut self, payload: T) {
        self.payload.extend(payload.to_output().into_iter());
    }

    /// Returns a byte array containing the full contents of the HTTP response,
    /// for use by the Canteen struct.
    pub fn gen_output(&self) -> Vec<u8> {
        let mut output: Vec<u8> = Vec::with_capacity(self.payload.len() + 500);
        let mut inter = String::new();

        inter.push_str(&format!("HTTP/1.1 {} {}\r\n", self.code, self.cmsg));

        for (key, value) in &self.headers {
            inter.push_str(&format!("{}: {}\r\n", key, value));
        }

        inter.push_str(&format!("Content-Type: {}\r\n", self.ctype));
        inter.push_str(&format!("Content-Length: {}\r\n", self.payload.len()));
        inter.push_str("\r\n");

        output.extend(inter.as_bytes());
        output.extend(self.payload.iter());

        output
    }
}
<|endoftext|>


<commit_before>use common::{Header, HTTPVersion, StatusCode};
use std::io::{IoResult, MemReader};
use std::io::fs::File;
use std::io::util;
use std::io::util::NullReader;

/// Object representing an HTTP response whose purpose is to be given to a `Request`.
///
/// Some headers cannot be changed. Trying to define the value
///  of one of these will have no effect:
///
///  - `Accept-Ranges`
///  - `Connection`
///  - `Content-Range`
///  - `Trailer`
///  - `Transfer-Encoding`
///  - `Upgrade`
///
/// Some headers have special behaviors:
///
///  - `Content-Encoding`: If you define this header, the library
///      will assume that the data from the `Reader` has the specified encoding
///      and will just pass-through.
///
///  - `Content-Length`: The length of the data should be set manually
///      using the `Reponse` object's API. Attempting to set the value of this
///      header will be equivalent to modifying the size of the data but the header
///      itself may not be present in the final result.
///
#[experimental]
pub struct Response<R> {
    reader: R,
    status_code: StatusCode,
    headers: Vec<Header>,
    data_length: Option<uint>,
}

/// Transfer encoding to use when sending the message.
/// Note that only *supported* encoding are listed here.
enum TransferEncoding {
    Identity,
    Chunked,
}

impl ::std::from_str::FromStr for TransferEncoding {
    fn from_str(input: &str) -> Option<TransferEncoding> {
        use std::ascii::StrAsciiExt;

        if input.eq_ignore_ascii_case("identity") {
            return Some(Identity);
        } else if input.eq_ignore_ascii_case("chunked") {
            return Some(Chunked);
        }

        None
    }
}

/// Builds a Date: header with the current date.
// TODO: this is optimisable
fn build_date_header() -> Header {
    use time;
    let date = time::now_utc().strftime("%a, %d %b %Y %H:%M:%S GMT");
    from_str(format!("Date: {}", date).as_slice()).unwrap()
}

fn write_message_header<W: Writer>(mut writer: W, http_version: &HTTPVersion,
                                   status_code: &StatusCode, headers: &[Header])
    -> IoResult<()>
{
    // writing status line
    try!(write!(writer, "HTTP/{} {} {}\r\n",
        http_version,
        status_code.as_uint(),
        status_code.get_default_reason_phrase()
    ));

    // writing headers
    for header in headers.iter() {
        try!(write!(writer, "{}: {}\r\n", header.field, header.value));
    }

    // separator between header and data
    try!(write!(writer, "\r\n"));

    Ok(())
}

fn choose_transfer_encoding(request_headers: &[Header], http_version: &HTTPVersion,
                            entity_length: &Option<uint>, has_additional_headers: bool)
    -> TransferEncoding
{
    use util;

    // HTTP 1.0 doesn't support other encoding
    if *http_version <= HTTPVersion(1, 0) {
        return Identity;
    }

    // parsing the request's TE header
    let user_request = request_headers.iter()
        // finding TE
        .find(|h| h.field.equiv(&"TE"))

        // getting its value
        .map(|h| h.value.as_slice())

        // getting the corresponding TransferEncoding
        .and_then(|value| {
            // getting list of requested elements
            let mut parse = util::parse_header_value(value);

            // sorting elements by most priority
            parse.sort_by(|a, b| b.val1().partial_cmp(&a.val1()).unwrap_or(Equal));

            // trying to parse each requested encoding
            for value in parse.iter() {
                // q=0 are ignored
                if value.val1() <= 0.0 { continue }

                match from_str::<TransferEncoding>(value.val0()) {
                    Some(te) => return Some(te),
                    _ => ()     // unrecognized/unsupported encoding
                };
            }

            // encoding not found
            None
        });

    //
    if user_request.is_some() {
        return user_request.unwrap();
    }

    // if we have additional headers, using chunked
    if has_additional_headers {
        return Chunked;
    }

    // if we don't have a Content-Length, or if the Content-Length is too big, using chunks writer
    let chunks_threshold = 32768;
    if entity_length.as_ref().filtered(|val| **val < chunks_threshold).is_none() {
        return Chunked;
    }

    // Identity by default
    Identity
}

impl<R: Reader> Response<R> {
    /// Creates a new Response object.
    ///
    /// The `additional_headers` argument is a receiver that
    ///  may provide headers even after the response has been sent.
    ///
    /// All the other arguments are straight-forward.
    #[experimental]
    pub fn new(status_code: StatusCode, headers: Vec<Header>,
               data: R, data_length: Option<uint>,
               additional_headers: Option<Receiver<Header>>)
                -> Response<R>
    {
        let mut response = Response {
            reader: data,
            status_code: status_code,
            headers: Vec::new(),
            data_length: data_length,
        };

        for h in headers.move_iter() {
            response.add_header(h)
        }

        // dummy implementation
        if additional_headers.is_some() {
            for h in additional_headers.unwrap().iter() {
                response.add_header(h)
            }
        }

        response
    }

    /// Adds a header to the list.
    /// Does all the checks.
    #[experimental]
    pub fn add_header(&mut self, header: Header) {
        // ignoring forbidden headers
        if header.field.equiv(&"Accept-Ranges") ||
           header.field.equiv(&"Connection") ||
           header.field.equiv(&"Content-Range") ||
           header.field.equiv(&"Trailer") ||
           header.field.equiv(&"Transfer-Encoding") ||
           header.field.equiv(&"Upgrade")
        {
            return;
        }

        // if the header is Content-Length, setting the data length
        if header.field.equiv(&"Content-Length") {
            match from_str::<uint>(header.value.as_slice()) {
                Some(val) => self.data_length = Some(val),
                None => ()      // wrong value for content-length
            };

            return;
        }

        self.headers.push(header)
    }

    /// Returns the same request, but with an additional header.
    ///
    /// Some headers cannot be modified and some other have a
    ///  special behavior. See the documentation above.
    #[unstable]
    #[inline]
    pub fn with_header(mut self, header: Header) -> Response<R> {
        self.add_header(header);
        self
    }

    /// Returns the same request, but with a different status code.
    #[unstable]
    #[inline]
    pub fn with_status_code(mut self, code: StatusCode) -> Response<R> {
        self.status_code = code;
        self
    }

    /// Returns the same request, but with different data.
    #[unstable]
    pub fn with_data<S: Reader>(self, reader: S, data_length: Option<uint>) -> Response<S> {
        Response {
            reader: reader,
            headers: self.headers,
            status_code: self.status_code,
            data_length: data_length,
        }
    }

    /// Prints the HTTP response to a writer.
    ///
    /// This function is the one used to send the response to the client's socket.
    /// Therefore you shouldn't expect anything pretty-printed or even readable.
    ///
    /// The HTTP version and headers passed as arguments are used to
    ///  decide which features (most notably, encoding) to use.
    ///
    /// Note: does not flush the writer.
    #[unstable]
    pub fn raw_print<W: Writer>(mut self, mut writer: W, http_version: HTTPVersion,
                                request_headers: &[Header], do_not_send_body: bool,
                                upgrade: Option<&str>)
                                -> IoResult<()>
    {
        let mut transfer_encoding = Some(choose_transfer_encoding(request_headers,
                                    &http_version, &self.data_length, false /* TODO */));

        // add `Date` if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Date")).is_none() {
            self.headers.unshift(build_date_header());
        }

        // add `Server` if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Server")).is_none() {
            self.headers.unshift(
                from_str("Server: tiny-http (Rust)").unwrap()
            );
        }

        // handling upgrade
        if upgrade.is_some() {
            let upgrade = upgrade.unwrap();
            self.headers.unshift(from_str(format!("Upgrade: {}", upgrade).as_slice()).unwrap());
            self.headers.unshift(from_str("Connection: upgrade").unwrap());
            transfer_encoding = None;
        }

        // checking whether to ignore the body of the response
        let do_not_send_body = do_not_send_body ||
            match self.status_code.as_uint() {
                // sattus code 1xx, 204 and 304 MUST not include a body
                100..199 | 204 | 304 => true,
                _ => false
            };

        // preparing headers for transfer
        match transfer_encoding {
            Some(Chunked) => {
                self.headers.push(
                    from_str("Transfer-Encoding: chunked").unwrap()
                )
            },

            Some(Identity) => {
                assert!(self.data_length.is_some());
                let data_length = self.data_length.unwrap();

                self.headers.push(
                    from_str(format!("Content-Length: {}", data_length).as_slice()).unwrap()
                )
            },

            _ => ()
        };

        // sending headers
        try!(write_message_header(writer.by_ref(), &http_version,
            &self.status_code, self.headers.as_slice()));

        // sending the body
        if !do_not_send_body {
            match transfer_encoding {

                Some(Chunked) => {
                    use util::ChunksEncoder;

                    let mut writer = ChunksEncoder::new(writer);
                    try!(util::copy(&mut self.reader, &mut writer));
                },

                Some(Identity) => {
                    use util::EqualReader;

                    assert!(self.data_length.is_some());
                    let data_length = self.data_length.unwrap();

                    if data_length >= 1 {
                        let (mut equ_reader, _) =
                            EqualReader::new(self.reader.by_ref(), data_length);
                        try!(util::copy(&mut equ_reader, &mut writer));
                    }
                },

                _ => ()

            }
        }

        Ok(())
    }
}

impl Response<File> {
    /// Builds a new `Response` from a `File`.
    ///
    /// The `Content-Type` will **not** be automatically detected,
    ///  you must set it yourself.
    #[experimental]
    pub fn from_file(mut file: File) -> Response<File> {
        let file_size = file.stat().ok().map(|v| v.size as uint);

        Response::new(
            StatusCode(200),
            Vec::new(),
            file,
            file_size,
            None,
        )
    }
}

impl Response<MemReader> {
    #[experimental]
    pub fn from_data(data: Vec<u8>) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            Vec::new(),
            MemReader::new(data),
            Some(data_len),
            None,
        )
    }

    #[experimental]
    pub fn from_string(data: String) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            vec!(
                from_str("Content-Type: text/plain; charset=UTF-8").unwrap()
            ),
            MemReader::new(data.into_bytes()),
            Some(data_len),
            None,
        )
    }
}

impl Response<NullReader> {
    /// Builds an empty `Response` with the given status code.
    #[experimental]
    pub fn new_empty(status_code: StatusCode) -> Response<NullReader> {
        Response::new(
            status_code,
            Vec::new(),
            NullReader,
            Some(0),
            None,
        )
    }
}

impl Clone for Response<NullReader> {
    fn clone(&self) -> Response<NullReader> {
        Response {
            reader: NullReader,
            status_code: self.status_code.clone(),
            headers: self.headers.clone(),
            data_length: self.data_length.clone(),
        }
    }
}
<commit_msg>Fix deprecated warnings<commit_after>use common::{Header, HTTPVersion, StatusCode};
use std::io::{IoResult, MemReader};
use std::io::fs::File;
use std::io::util;
use std::io::util::NullReader;

/// Object representing an HTTP response whose purpose is to be given to a `Request`.
///
/// Some headers cannot be changed. Trying to define the value
///  of one of these will have no effect:
///
///  - `Accept-Ranges`
///  - `Connection`
///  - `Content-Range`
///  - `Trailer`
///  - `Transfer-Encoding`
///  - `Upgrade`
///
/// Some headers have special behaviors:
///
///  - `Content-Encoding`: If you define this header, the library
///      will assume that the data from the `Reader` has the specified encoding
///      and will just pass-through.
///
///  - `Content-Length`: The length of the data should be set manually
///      using the `Reponse` object's API. Attempting to set the value of this
///      header will be equivalent to modifying the size of the data but the header
///      itself may not be present in the final result.
///
#[experimental]
pub struct Response<R> {
    reader: R,
    status_code: StatusCode,
    headers: Vec<Header>,
    data_length: Option<uint>,
}

/// Transfer encoding to use when sending the message.
/// Note that only *supported* encoding are listed here.
enum TransferEncoding {
    Identity,
    Chunked,
}

impl ::std::from_str::FromStr for TransferEncoding {
    fn from_str(input: &str) -> Option<TransferEncoding> {
        use std::ascii::StrAsciiExt;

        if input.eq_ignore_ascii_case("identity") {
            return Some(Identity);
        } else if input.eq_ignore_ascii_case("chunked") {
            return Some(Chunked);
        }

        None
    }
}

/// Builds a Date: header with the current date.
// TODO: this is optimisable
fn build_date_header() -> Header {
    use time;
    let date = time::now_utc().strftime("%a, %d %b %Y %H:%M:%S GMT");
    from_str(format!("Date: {}", date).as_slice()).unwrap()
}

fn write_message_header<W: Writer>(mut writer: W, http_version: &HTTPVersion,
                                   status_code: &StatusCode, headers: &[Header])
    -> IoResult<()>
{
    // writing status line
    try!(write!(writer, "HTTP/{} {} {}\r\n",
        http_version,
        status_code.as_uint(),
        status_code.get_default_reason_phrase()
    ));

    // writing headers
    for header in headers.iter() {
        try!(write!(writer, "{}: {}\r\n", header.field, header.value));
    }

    // separator between header and data
    try!(write!(writer, "\r\n"));

    Ok(())
}

fn choose_transfer_encoding(request_headers: &[Header], http_version: &HTTPVersion,
                            entity_length: &Option<uint>, has_additional_headers: bool)
    -> TransferEncoding
{
    use util;

    // HTTP 1.0 doesn't support other encoding
    if *http_version <= HTTPVersion(1, 0) {
        return Identity;
    }

    // parsing the request's TE header
    let user_request = request_headers.iter()
        // finding TE
        .find(|h| h.field.equiv(&"TE"))

        // getting its value
        .map(|h| h.value.as_slice())

        // getting the corresponding TransferEncoding
        .and_then(|value| {
            // getting list of requested elements
            let mut parse = util::parse_header_value(value);

            // sorting elements by most priority
            parse.sort_by(|a, b| b.val1().partial_cmp(&a.val1()).unwrap_or(Equal));

            // trying to parse each requested encoding
            for value in parse.iter() {
                // q=0 are ignored
                if value.val1() <= 0.0 { continue }

                match from_str::<TransferEncoding>(value.val0()) {
                    Some(te) => return Some(te),
                    _ => ()     // unrecognized/unsupported encoding
                };
            }

            // encoding not found
            None
        });

    //
    if user_request.is_some() {
        return user_request.unwrap();
    }

    // if we have additional headers, using chunked
    if has_additional_headers {
        return Chunked;
    }

    // if we don't have a Content-Length, or if the Content-Length is too big, using chunks writer
    let chunks_threshold = 32768;
    if entity_length.as_ref().filtered(|val| **val < chunks_threshold).is_none() {
        return Chunked;
    }

    // Identity by default
    Identity
}

impl<R: Reader> Response<R> {
    /// Creates a new Response object.
    ///
    /// The `additional_headers` argument is a receiver that
    ///  may provide headers even after the response has been sent.
    ///
    /// All the other arguments are straight-forward.
    #[experimental]
    pub fn new(status_code: StatusCode, headers: Vec<Header>,
               data: R, data_length: Option<uint>,
               additional_headers: Option<Receiver<Header>>)
                -> Response<R>
    {
        let mut response = Response {
            reader: data,
            status_code: status_code,
            headers: Vec::new(),
            data_length: data_length,
        };

        for h in headers.move_iter() {
            response.add_header(h)
        }

        // dummy implementation
        if additional_headers.is_some() {
            for h in additional_headers.unwrap().iter() {
                response.add_header(h)
            }
        }

        response
    }

    /// Adds a header to the list.
    /// Does all the checks.
    #[experimental]
    pub fn add_header(&mut self, header: Header) {
        // ignoring forbidden headers
        if header.field.equiv(&"Accept-Ranges") ||
           header.field.equiv(&"Connection") ||
           header.field.equiv(&"Content-Range") ||
           header.field.equiv(&"Trailer") ||
           header.field.equiv(&"Transfer-Encoding") ||
           header.field.equiv(&"Upgrade")
        {
            return;
        }

        // if the header is Content-Length, setting the data length
        if header.field.equiv(&"Content-Length") {
            match from_str::<uint>(header.value.as_slice()) {
                Some(val) => self.data_length = Some(val),
                None => ()      // wrong value for content-length
            };

            return;
        }

        self.headers.push(header)
    }

    /// Returns the same request, but with an additional header.
    ///
    /// Some headers cannot be modified and some other have a
    ///  special behavior. See the documentation above.
    #[unstable]
    #[inline]
    pub fn with_header(mut self, header: Header) -> Response<R> {
        self.add_header(header);
        self
    }

    /// Returns the same request, but with a different status code.
    #[unstable]
    #[inline]
    pub fn with_status_code(mut self, code: StatusCode) -> Response<R> {
        self.status_code = code;
        self
    }

    /// Returns the same request, but with different data.
    #[unstable]
    pub fn with_data<S: Reader>(self, reader: S, data_length: Option<uint>) -> Response<S> {
        Response {
            reader: reader,
            headers: self.headers,
            status_code: self.status_code,
            data_length: data_length,
        }
    }

    /// Prints the HTTP response to a writer.
    ///
    /// This function is the one used to send the response to the client's socket.
    /// Therefore you shouldn't expect anything pretty-printed or even readable.
    ///
    /// The HTTP version and headers passed as arguments are used to
    ///  decide which features (most notably, encoding) to use.
    ///
    /// Note: does not flush the writer.
    #[unstable]
    pub fn raw_print<W: Writer>(mut self, mut writer: W, http_version: HTTPVersion,
                                request_headers: &[Header], do_not_send_body: bool,
                                upgrade: Option<&str>)
                                -> IoResult<()>
    {
        let mut transfer_encoding = Some(choose_transfer_encoding(request_headers,
                                    &http_version, &self.data_length, false /* TODO */));

        // add `Date` if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Date")).is_none() {
            self.headers.insert(0, build_date_header());
        }

        // add `Server` if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Server")).is_none() {
            self.headers.insert(0,
                from_str("Server: tiny-http (Rust)").unwrap()
            );
        }

        // handling upgrade
        if upgrade.is_some() {
            let upgrade = upgrade.unwrap();
            self.headers.insert(0, from_str(format!("Upgrade: {}", upgrade).as_slice()).unwrap());
            self.headers.insert(0, from_str("Connection: upgrade").unwrap());
            transfer_encoding = None;
        }

        // checking whether to ignore the body of the response
        let do_not_send_body = do_not_send_body ||
            match self.status_code.as_uint() {
                // sattus code 1xx, 204 and 304 MUST not include a body
                100..199 | 204 | 304 => true,
                _ => false
            };

        // preparing headers for transfer
        match transfer_encoding {
            Some(Chunked) => {
                self.headers.push(
                    from_str("Transfer-Encoding: chunked").unwrap()
                )
            },

            Some(Identity) => {
                assert!(self.data_length.is_some());
                let data_length = self.data_length.unwrap();

                self.headers.push(
                    from_str(format!("Content-Length: {}", data_length).as_slice()).unwrap()
                )
            },

            _ => ()
        };

        // sending headers
        try!(write_message_header(writer.by_ref(), &http_version,
            &self.status_code, self.headers.as_slice()));

        // sending the body
        if !do_not_send_body {
            match transfer_encoding {

                Some(Chunked) => {
                    use util::ChunksEncoder;

                    let mut writer = ChunksEncoder::new(writer);
                    try!(util::copy(&mut self.reader, &mut writer));
                },

                Some(Identity) => {
                    use util::EqualReader;

                    assert!(self.data_length.is_some());
                    let data_length = self.data_length.unwrap();

                    if data_length >= 1 {
                        let (mut equ_reader, _) =
                            EqualReader::new(self.reader.by_ref(), data_length);
                        try!(util::copy(&mut equ_reader, &mut writer));
                    }
                },

                _ => ()

            }
        }

        Ok(())
    }
}

impl Response<File> {
    /// Builds a new `Response` from a `File`.
    ///
    /// The `Content-Type` will **not** be automatically detected,
    ///  you must set it yourself.
    #[experimental]
    pub fn from_file(mut file: File) -> Response<File> {
        let file_size = file.stat().ok().map(|v| v.size as uint);

        Response::new(
            StatusCode(200),
            Vec::new(),
            file,
            file_size,
            None,
        )
    }
}

impl Response<MemReader> {
    #[experimental]
    pub fn from_data(data: Vec<u8>) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            Vec::new(),
            MemReader::new(data),
            Some(data_len),
            None,
        )
    }

    #[experimental]
    pub fn from_string(data: String) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            vec!(
                from_str("Content-Type: text/plain; charset=UTF-8").unwrap()
            ),
            MemReader::new(data.into_bytes()),
            Some(data_len),
            None,
        )
    }
}

impl Response<NullReader> {
    /// Builds an empty `Response` with the given status code.
    #[experimental]
    pub fn new_empty(status_code: StatusCode) -> Response<NullReader> {
        Response::new(
            status_code,
            Vec::new(),
            NullReader,
            Some(0),
            None,
        )
    }
}

impl Clone for Response<NullReader> {
    fn clone(&self) -> Response<NullReader> {
        Response {
            reader: NullReader,
            status_code: self.status_code.clone(),
            headers: self.headers.clone(),
            data_length: self.data_length.clone(),
        }
    }
}
<|endoftext|>


<commit_before>use std::ffi::{CStr, CString};
use std::rc::Rc;
use std::fmt;
use std::error;

use sys::sdl as ll;
use util::CStringExt;

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum Error {
    NoMemError = ll::SDL_ENOMEM as isize,
    ReadError = ll::SDL_EFREAD as isize,
    WriteError = ll::SDL_EFWRITE as isize,
    SeekError = ll::SDL_EFSEEK as isize,
    UnsupportedError = ll::SDL_UNSUPPORTED as isize
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct ErrorMessage(pub String);

impl fmt::Display for ErrorMessage {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "SDL error: {}", self.0)
    }
}

impl error::Error for ErrorMessage {
    fn description(&self) -> &str {
        "SDL error"
    }
}

impl From<String> for ErrorMessage {
    fn from(src: String) -> Self {
        ErrorMessage(src)
    }
}

pub type SdlResult<T> = Result<T, ErrorMessage>;

use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
/// Only one Sdl context can be alive at a time.
/// Set to false by default (not alive).
static IS_SDL_CONTEXT_ALIVE: AtomicBool = ATOMIC_BOOL_INIT;

/// The SDL context type. Initialize with `sdl2::init()`.
///
/// From a thread-safety perspective, `Sdl` represents the main thread.
/// As such, `Sdl` is a useful type for ensuring that SDL types that can only
/// be used on the main thread are initialized that way.
///
/// For instance, `SDL_PumpEvents()` is not thread safe, and may only be
/// called on the main thread.
/// All functionality that calls `SDL_PumpEvents()` is thus put into an
/// `EventPump` type, which can only be obtained through `Sdl`.
/// This guarantees that the only way to call event-pumping functions is on
/// the main thread.
#[derive(Clone)]
pub struct Sdl {
    sdldrop: Rc<SdlDrop>
}

impl Sdl {
    #[inline]
    fn new() -> SdlResult<Sdl> {
        unsafe {
            use std::sync::atomic::Ordering;

            // Atomically switch the `IS_SDL_CONTEXT_ALIVE` global to true
            let was_alive = IS_SDL_CONTEXT_ALIVE.swap(true, Ordering::Relaxed);

            if was_alive {
                Err(ErrorMessage("Cannot initialize `Sdl` more than once at a time.".into()))
            } else {
                // Initialize SDL without any explicit subsystems (flags = 0).
                if ll::SDL_Init(0) == 0 {
                    Ok(Sdl {
                        sdldrop: Rc::new(SdlDrop)
                    })
                } else {
                    IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
                    Err(get_error())
                }
            }
        }
    }

    /// Initializes the audio subsystem.
    #[inline]
    pub fn audio(&self) -> SdlResult<AudioSubsystem> { AudioSubsystem::new(self) }

    /// Initializes the event subsystem.
    #[inline]
    pub fn event(&self) -> SdlResult<EventSubsystem> { EventSubsystem::new(self) }

    /// Initializes the joystick subsystem.
    #[inline]
    pub fn joystick(&self) -> SdlResult<JoystickSubsystem> { JoystickSubsystem::new(self) }

    /// Initializes the haptic subsystem.
    #[inline]
    pub fn haptic(&self) -> SdlResult<HapticSubsystem> { HapticSubsystem::new(self) }

    /// Initializes the game controller subsystem.
    #[inline]
    pub fn game_controller(&self) -> SdlResult<GameControllerSubsystem> { GameControllerSubsystem::new(self) }

    /// Initializes the timer subsystem.
    #[inline]
    pub fn timer(&self) -> SdlResult<TimerSubsystem> { TimerSubsystem::new(self) }

    /// Initializes the video subsystem.
    #[inline]
    pub fn video(&self) -> SdlResult<VideoSubsystem> { VideoSubsystem::new(self) }

    /// Obtains the SDL event pump.
    ///
    /// At most one `EventPump` is allowed to be alive during the program's execution.
    /// If this function is called while an `EventPump` instance is alive, the function will return
    /// an error.
    #[inline]
    pub fn event_pump(&self) -> SdlResult<EventPump> {
        EventPump::new(self)
    }

    #[inline]
    #[doc(hidden)]
    pub fn sdldrop(&self) -> Rc<SdlDrop> {
        self.sdldrop.clone()
    }
}

/// When SDL is no longer in use (the refcount in an `Rc<SdlDrop>` reaches 0), the library is quit.
#[doc(hidden)]
pub struct SdlDrop;

impl Drop for SdlDrop {
    #[inline]
    fn drop(&mut self) {
        use std::sync::atomic::Ordering;

        let was_alive = IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
        assert!(was_alive);

        unsafe { ll::SDL_Quit(); }
    }
}

// No subsystem can implement `Send` because the destructor, `SDL_QuitSubSystem`,
// utilizes non-atomic reference counting and should thus be called on a single thread.
// Some subsystems have functions designed to be thread-safe, such as adding a timer or accessing
// the event queue. These subsystems implement `Sync`.

macro_rules! subsystem {
    ($name:ident, $flag:expr) => (
        impl $name {
            #[inline]
            fn new(sdl: &Sdl) -> SdlResult<$name> {
                let result = unsafe { ll::SDL_InitSubSystem($flag) };

                if result == 0 {
                    Ok($name {
                        _subsystem_drop: Rc::new(SubsystemDrop {
                            _sdldrop: sdl.sdldrop.clone(),
                            flag: $flag
                        })
                    })
                } else {
                    Err(get_error())
                }
            }
        }
    );
    ($name:ident, $flag:expr, nosync) => (
        #[derive(Clone)]
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>
        }

        impl $name {
            /// Obtain an SDL context.
            #[inline]
            pub fn sdl(&self) -> Sdl {
                Sdl { sdldrop: self._subsystem_drop._sdldrop.clone() }
            }
        }

        subsystem!($name, $flag);
    );
    ($name:ident, $flag:expr, sync) => (
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>
        }
        unsafe impl Sync for $name {}

        impl $name {
            #[inline]
            pub fn clone(&mut self) -> $name {
                $name {
                    _subsystem_drop: self._subsystem_drop.clone()
                }
            }

            /// Obtain an SDL context.
            #[inline]
            pub fn sdl(&mut self) -> Sdl {
                Sdl { sdldrop: self._subsystem_drop._sdldrop.clone() }
            }
        }

        subsystem!($name, $flag);
    )
}

/// When a subsystem is no longer in use (the refcount in an `Rc<SubsystemDrop>` reaches 0),
/// the subsystem is quit.
#[derive(Clone)]
struct SubsystemDrop {
    _sdldrop: Rc<SdlDrop>,
    flag: ll::SDL_InitFlag
}

impl Drop for SubsystemDrop {
    #[inline]
    fn drop(&mut self) {
        unsafe { ll::SDL_QuitSubSystem(self.flag); }
    }
}

subsystem!(AudioSubsystem, ll::SDL_INIT_AUDIO, nosync);
subsystem!(GameControllerSubsystem, ll::SDL_INIT_GAMECONTROLLER, nosync);
subsystem!(HapticSubsystem, ll::SDL_INIT_HAPTIC, nosync);
subsystem!(JoystickSubsystem, ll::SDL_INIT_JOYSTICK, nosync);
subsystem!(VideoSubsystem, ll::SDL_INIT_VIDEO, nosync);
// Timers can be added on other threads.
subsystem!(TimerSubsystem, ll::SDL_INIT_TIMER, sync);
// The event queue can be read from other threads.
subsystem!(EventSubsystem, ll::SDL_INIT_EVENTS, sync);

static mut IS_EVENT_PUMP_ALIVE: bool = false;

/// A thread-safe type that encapsulates SDL event-pumping functions.
pub struct EventPump {
    _sdldrop: Rc<SdlDrop>
}

impl EventPump {
    /// Obtains the SDL event pump.
    #[inline]
    fn new(sdl: &Sdl) -> SdlResult<EventPump> {
        // Called on the main SDL thread.

        unsafe {
            if IS_EVENT_PUMP_ALIVE {
                Err(ErrorMessage("an `EventPump` instance is already alive - there can only be one `EventPump` in use at a time.".into()))
            } else {
                // Initialize the events subsystem, just in case none of the other subsystems have done it yet.
                let result = ll::SDL_InitSubSystem(ll::SDL_INIT_EVENTS);

                if result == 0 {
                    IS_EVENT_PUMP_ALIVE = true;

                    Ok(EventPump {
                        _sdldrop: sdl.sdldrop.clone()
                    })
                } else {
                    Err(get_error())
                }
            }
        }
    }
}

impl Drop for EventPump {
    #[inline]
    fn drop(&mut self) {
        // Called on the main SDL thread.

        unsafe {
            assert!(IS_EVENT_PUMP_ALIVE);
            ll::SDL_QuitSubSystem(ll::SDL_INIT_EVENTS);
            IS_EVENT_PUMP_ALIVE = false;
        }
    }
}

/// Initializes the SDL library.
/// This must be called before using any other SDL function.
///
/// # Example
/// ```no_run
/// let sdl_context = sdl2::init().unwrap();
/// let mut event_pump = sdl_context.event_pump().unwrap();
///
/// for event in event_pump.poll_iter() {
///     // ...
/// }
///
/// // SDL_Quit() is called here as `sdl_context` is dropped.
/// ```
#[inline]
pub fn init() -> SdlResult<Sdl> { Sdl::new() }

pub fn get_error() -> ErrorMessage {
    unsafe {
        let err = ll::SDL_GetError();
        ErrorMessage(String::from_utf8_lossy(CStr::from_ptr(err).to_bytes()).to_string())
    }
}

pub fn set_error(err: &str) {
    let err = CString::new(err).remove_nul();
    unsafe { ll::SDL_SetError(err.as_ptr()); }
}

pub fn set_error_from_code(err: Error) {
    unsafe { ll::SDL_Error(err as ll::SDL_errorcode); }
}

pub fn clear_error() {
    unsafe { ll::SDL_ClearError(); }
}
<commit_msg>Add a doc description for ErrorMessage<commit_after>use std::ffi::{CStr, CString};
use std::rc::Rc;
use std::fmt;
use std::error;

use sys::sdl as ll;
use util::CStringExt;

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum Error {
    NoMemError = ll::SDL_ENOMEM as isize,
    ReadError = ll::SDL_EFREAD as isize,
    WriteError = ll::SDL_EFWRITE as isize,
    SeekError = ll::SDL_EFSEEK as isize,
    UnsupportedError = ll::SDL_UNSUPPORTED as isize
}

/// A message with information about an error that SDL has encountered.
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct ErrorMessage(pub String);

impl fmt::Display for ErrorMessage {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "SDL error: {}", self.0)
    }
}

impl error::Error for ErrorMessage {
    fn description(&self) -> &str {
        "SDL error"
    }
}

impl From<String> for ErrorMessage {
    fn from(src: String) -> Self {
        ErrorMessage(src)
    }
}

pub type SdlResult<T> = Result<T, ErrorMessage>;

use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
/// Only one Sdl context can be alive at a time.
/// Set to false by default (not alive).
static IS_SDL_CONTEXT_ALIVE: AtomicBool = ATOMIC_BOOL_INIT;

/// The SDL context type. Initialize with `sdl2::init()`.
///
/// From a thread-safety perspective, `Sdl` represents the main thread.
/// As such, `Sdl` is a useful type for ensuring that SDL types that can only
/// be used on the main thread are initialized that way.
///
/// For instance, `SDL_PumpEvents()` is not thread safe, and may only be
/// called on the main thread.
/// All functionality that calls `SDL_PumpEvents()` is thus put into an
/// `EventPump` type, which can only be obtained through `Sdl`.
/// This guarantees that the only way to call event-pumping functions is on
/// the main thread.
#[derive(Clone)]
pub struct Sdl {
    sdldrop: Rc<SdlDrop>
}

impl Sdl {
    #[inline]
    fn new() -> SdlResult<Sdl> {
        unsafe {
            use std::sync::atomic::Ordering;

            // Atomically switch the `IS_SDL_CONTEXT_ALIVE` global to true
            let was_alive = IS_SDL_CONTEXT_ALIVE.swap(true, Ordering::Relaxed);

            if was_alive {
                Err(ErrorMessage("Cannot initialize `Sdl` more than once at a time.".into()))
            } else {
                // Initialize SDL without any explicit subsystems (flags = 0).
                if ll::SDL_Init(0) == 0 {
                    Ok(Sdl {
                        sdldrop: Rc::new(SdlDrop)
                    })
                } else {
                    IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
                    Err(get_error())
                }
            }
        }
    }

    /// Initializes the audio subsystem.
    #[inline]
    pub fn audio(&self) -> SdlResult<AudioSubsystem> { AudioSubsystem::new(self) }

    /// Initializes the event subsystem.
    #[inline]
    pub fn event(&self) -> SdlResult<EventSubsystem> { EventSubsystem::new(self) }

    /// Initializes the joystick subsystem.
    #[inline]
    pub fn joystick(&self) -> SdlResult<JoystickSubsystem> { JoystickSubsystem::new(self) }

    /// Initializes the haptic subsystem.
    #[inline]
    pub fn haptic(&self) -> SdlResult<HapticSubsystem> { HapticSubsystem::new(self) }

    /// Initializes the game controller subsystem.
    #[inline]
    pub fn game_controller(&self) -> SdlResult<GameControllerSubsystem> { GameControllerSubsystem::new(self) }

    /// Initializes the timer subsystem.
    #[inline]
    pub fn timer(&self) -> SdlResult<TimerSubsystem> { TimerSubsystem::new(self) }

    /// Initializes the video subsystem.
    #[inline]
    pub fn video(&self) -> SdlResult<VideoSubsystem> { VideoSubsystem::new(self) }

    /// Obtains the SDL event pump.
    ///
    /// At most one `EventPump` is allowed to be alive during the program's execution.
    /// If this function is called while an `EventPump` instance is alive, the function will return
    /// an error.
    #[inline]
    pub fn event_pump(&self) -> SdlResult<EventPump> {
        EventPump::new(self)
    }

    #[inline]
    #[doc(hidden)]
    pub fn sdldrop(&self) -> Rc<SdlDrop> {
        self.sdldrop.clone()
    }
}

/// When SDL is no longer in use (the refcount in an `Rc<SdlDrop>` reaches 0), the library is quit.
#[doc(hidden)]
pub struct SdlDrop;

impl Drop for SdlDrop {
    #[inline]
    fn drop(&mut self) {
        use std::sync::atomic::Ordering;

        let was_alive = IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
        assert!(was_alive);

        unsafe { ll::SDL_Quit(); }
    }
}

// No subsystem can implement `Send` because the destructor, `SDL_QuitSubSystem`,
// utilizes non-atomic reference counting and should thus be called on a single thread.
// Some subsystems have functions designed to be thread-safe, such as adding a timer or accessing
// the event queue. These subsystems implement `Sync`.

macro_rules! subsystem {
    ($name:ident, $flag:expr) => (
        impl $name {
            #[inline]
            fn new(sdl: &Sdl) -> SdlResult<$name> {
                let result = unsafe { ll::SDL_InitSubSystem($flag) };

                if result == 0 {
                    Ok($name {
                        _subsystem_drop: Rc::new(SubsystemDrop {
                            _sdldrop: sdl.sdldrop.clone(),
                            flag: $flag
                        })
                    })
                } else {
                    Err(get_error())
                }
            }
        }
    );
    ($name:ident, $flag:expr, nosync) => (
        #[derive(Clone)]
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>
        }

        impl $name {
            /// Obtain an SDL context.
            #[inline]
            pub fn sdl(&self) -> Sdl {
                Sdl { sdldrop: self._subsystem_drop._sdldrop.clone() }
            }
        }

        subsystem!($name, $flag);
    );
    ($name:ident, $flag:expr, sync) => (
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>
        }
        unsafe impl Sync for $name {}

        impl $name {
            #[inline]
            pub fn clone(&mut self) -> $name {
                $name {
                    _subsystem_drop: self._subsystem_drop.clone()
                }
            }

            /// Obtain an SDL context.
            #[inline]
            pub fn sdl(&mut self) -> Sdl {
                Sdl { sdldrop: self._subsystem_drop._sdldrop.clone() }
            }
        }

        subsystem!($name, $flag);
    )
}

/// When a subsystem is no longer in use (the refcount in an `Rc<SubsystemDrop>` reaches 0),
/// the subsystem is quit.
#[derive(Clone)]
struct SubsystemDrop {
    _sdldrop: Rc<SdlDrop>,
    flag: ll::SDL_InitFlag
}

impl Drop for SubsystemDrop {
    #[inline]
    fn drop(&mut self) {
        unsafe { ll::SDL_QuitSubSystem(self.flag); }
    }
}

subsystem!(AudioSubsystem, ll::SDL_INIT_AUDIO, nosync);
subsystem!(GameControllerSubsystem, ll::SDL_INIT_GAMECONTROLLER, nosync);
subsystem!(HapticSubsystem, ll::SDL_INIT_HAPTIC, nosync);
subsystem!(JoystickSubsystem, ll::SDL_INIT_JOYSTICK, nosync);
subsystem!(VideoSubsystem, ll::SDL_INIT_VIDEO, nosync);
// Timers can be added on other threads.
subsystem!(TimerSubsystem, ll::SDL_INIT_TIMER, sync);
// The event queue can be read from other threads.
subsystem!(EventSubsystem, ll::SDL_INIT_EVENTS, sync);

static mut IS_EVENT_PUMP_ALIVE: bool = false;

/// A thread-safe type that encapsulates SDL event-pumping functions.
pub struct EventPump {
    _sdldrop: Rc<SdlDrop>
}

impl EventPump {
    /// Obtains the SDL event pump.
    #[inline]
    fn new(sdl: &Sdl) -> SdlResult<EventPump> {
        // Called on the main SDL thread.

        unsafe {
            if IS_EVENT_PUMP_ALIVE {
                Err(ErrorMessage("an `EventPump` instance is already alive - there can only be one `EventPump` in use at a time.".into()))
            } else {
                // Initialize the events subsystem, just in case none of the other subsystems have done it yet.
                let result = ll::SDL_InitSubSystem(ll::SDL_INIT_EVENTS);

                if result == 0 {
                    IS_EVENT_PUMP_ALIVE = true;

                    Ok(EventPump {
                        _sdldrop: sdl.sdldrop.clone()
                    })
                } else {
                    Err(get_error())
                }
            }
        }
    }
}

impl Drop for EventPump {
    #[inline]
    fn drop(&mut self) {
        // Called on the main SDL thread.

        unsafe {
            assert!(IS_EVENT_PUMP_ALIVE);
            ll::SDL_QuitSubSystem(ll::SDL_INIT_EVENTS);
            IS_EVENT_PUMP_ALIVE = false;
        }
    }
}

/// Initializes the SDL library.
/// This must be called before using any other SDL function.
///
/// # Example
/// ```no_run
/// let sdl_context = sdl2::init().unwrap();
/// let mut event_pump = sdl_context.event_pump().unwrap();
///
/// for event in event_pump.poll_iter() {
///     // ...
/// }
///
/// // SDL_Quit() is called here as `sdl_context` is dropped.
/// ```
#[inline]
pub fn init() -> SdlResult<Sdl> { Sdl::new() }

pub fn get_error() -> ErrorMessage {
    unsafe {
        let err = ll::SDL_GetError();
        ErrorMessage(String::from_utf8_lossy(CStr::from_ptr(err).to_bytes()).to_string())
    }
}

pub fn set_error(err: &str) {
    let err = CString::new(err).remove_nul();
    unsafe { ll::SDL_SetError(err.as_ptr()); }
}

pub fn set_error_from_code(err: Error) {
    unsafe { ll::SDL_Error(err as ll::SDL_errorcode); }
}

pub fn clear_error() {
    unsafe { ll::SDL_ClearError(); }
}
<|endoftext|>


<commit_before>#![feature(phase)]
#[phase(plugin, link)]
extern crate log;

use config::Config;
use logger::FileLogger;
use window_manager::WindowManager;
use window_system::Rectangle;
use window_system::WindowSystem;
use window_system::{
    ClientMessageEvent,
    ConfigurationNotification,
    ConfigurationRequest,
    Enter,
    Leave,
    KeyPressed,
    WindowCreated,
    WindowDestroyed,
    WindowUnmapped,
};
use xlib_window_system::XlibWindowSystem;
use std::io::process::Command;

pub mod config;
pub mod core;
pub mod layout;
pub mod logger;
pub mod window_manager;
pub mod window_system;
pub mod xlib_window_system;

fn main() {
    // Initialize window system. Use xlib here for now
    let mut window_system = XlibWindowSystem::new();
    // Create a default configuration
    let config = Config::default();
    // Create the actual window manager
    let mut window_manager = WindowManager::new(&window_system, &config);
    //
    let mut logger = FileLogger::new(&config.logfile);
    log::set_logger(box logger);

    // Output some initial information
    info!("WTFTW - Window Tiling For The Win");
    info!("Starting wtftw on {} screen(s)", window_system.get_screen_infos().len());

    for (i, &Rectangle(x, y, w, h)) in window_system.get_screen_infos().iter().enumerate() {
        debug!("Display {}: {}x{} ({}, {})", i, w, h, x, y);
    }

    // Enter the event loop and just listen for events
    loop {
        match window_system.get_event() {
            ClientMessageEvent(window) => {
            },
            ConfigurationNotification(window) => {
                if window_system.get_root() == window {
                    debug!("X configuration changed. Rescreen");

                    // Output some initial information
                    info!("WTFTW - Window Tiling For The Win");
                    info!("Starting wtftw on {} screen(s)", window_system.get_number_of_screens());

                    for (i, &Rectangle(x, y, w, h)) in window_system.get_screen_infos().iter().enumerate() {
                        debug!("Display {}: {}x{} ({}, {})", i, w, h, x, y);
                    }

                    window_manager.rescreen(&mut window_system, &config);
                }
            },
            ConfigurationRequest(window, window_changes, mask) => {
                window_system.configure_window(window, window_changes, mask);
            },
            WindowCreated(window) => {
                if !window_manager.is_window_managed(window) {
                    window_manager.manage(&mut window_system, window, &config);
                }
            },
            WindowUnmapped(window, synthetic) => {
                if synthetic && window_manager.is_window_managed(window) {
                    window_manager.unmanage(&mut window_system, window, &config);
                }
            },
            WindowDestroyed(window) => {
                if window_manager.is_window_managed(window) {
                    window_manager.unmanage(&mut window_system, window, &config);
                }
            },
            Enter(window) => {
                if config.focus_follows_mouse && window_manager.is_window_managed(window) {
                    window_system.set_window_border_color(window, config.focus_border_color);
                    window_system.focus_window(window);
                }
            },
            Leave(window) => {
                if config.focus_follows_mouse && window_manager.is_window_managed(window) {
                    window_system.set_window_border_color(window, config.border_color);
                }
            },
            KeyPressed(_, key, mask) => {
                if mask & 8 != 0 && key >= 10 && key <= 18 && (key - 10) < config.tags.len() as u32 {
                    debug!("switching workspace to {}", config.tags[key as uint - 10].clone());
                    window_manager.view(&mut window_system, key - 10, &config);
                }

                if mask & 9 == 9 && key == 36 {
                    let (terminal, args) = config.terminal.clone();
                    let arguments : Vec<String> = args.split(' ').map(String::from_str).collect();
                    spawn(proc() {
                        Command::new(terminal).args(arguments.as_slice()).detached().spawn();
                    });
                }

                if mask & 9 == 9 && key == 33 {
                    spawn(proc() {
                        Command::new(String::from_str("gmrun")).detached().spawn();
                    });
                }

                if mask & 9 == 9 && key == 24 {
                    break;
                }
            }
            _ => ()
        }
    }
}
<commit_msg>added minor comments<commit_after>#![feature(phase)]
#[phase(plugin, link)]
extern crate log;

use config::Config;
use logger::FileLogger;
use window_manager::WindowManager;
use window_system::Rectangle;
use window_system::WindowSystem;
use window_system::{
    ClientMessageEvent,
    ConfigurationNotification,
    ConfigurationRequest,
    Enter,
    Leave,
    KeyPressed,
    WindowCreated,
    WindowDestroyed,
    WindowUnmapped,
};
use xlib_window_system::XlibWindowSystem;
use std::io::process::Command;

pub mod config;
pub mod core;
pub mod layout;
pub mod logger;
pub mod window_manager;
pub mod window_system;
pub mod xlib_window_system;

fn main() {
    // Initialize window system. Use xlib here for now
    let mut window_system = XlibWindowSystem::new();
    // Create a default configuration
    let config = Config::default();
    // Create the actual window manager
    let mut window_manager = WindowManager::new(&window_system, &config);
    //
    let mut logger = FileLogger::new(&config.logfile);
    log::set_logger(box logger);

    // Output some initial information
    info!("WTFTW - Window Tiling For The Win");
    info!("Starting wtftw on {} screen(s)", window_system.get_screen_infos().len());

    for (i, &Rectangle(x, y, w, h)) in window_system.get_screen_infos().iter().enumerate() {
        debug!("Display {}: {}x{} ({}, {})", i, w, h, x, y);
    }

    // Enter the event loop and just listen for events
    loop {
        match window_system.get_event() {
            ClientMessageEvent(window) => {
            },
            // The X11/Wayland configuration changed, so we need to readjust the
            // screen configurations.
            ConfigurationNotification(window) => {
                if window_system.get_root() == window {
                    debug!("X configuration changed. Rescreen");

                    // Output some initial information
                    info!("WTFTW - Window Tiling For The Win");
                    info!("Starting wtftw on {} screen(s)", window_system.get_number_of_screens());

                    for (i, &Rectangle(x, y, w, h)) in window_system.get_screen_infos().iter().enumerate() {
                        debug!("Display {}: {}x{} ({}, {})", i, w, h, x, y);
                    }

                    window_manager.rescreen(&mut window_system, &config);
                }
            },
            // A window asked to be reconfigured (i.e. resized, border change, etc.)
            ConfigurationRequest(window, window_changes, mask) => {
                window_system.configure_window(window, window_changes, mask);
            },
            // A new window was created, so we need to manage
            // it unless it is already managed by us.
            WindowCreated(window) => {
                if !window_manager.is_window_managed(window) {
                    window_manager.manage(&mut window_system, window, &config);
                }
            },
            WindowUnmapped(window, synthetic) => {
                if synthetic && window_manager.is_window_managed(window) {
                    window_manager.unmanage(&mut window_system, window, &config);
                }
            },
            WindowDestroyed(window) => {
                if window_manager.is_window_managed(window) {
                    window_manager.unmanage(&mut window_system, window, &config);
                }
            },
            // The mouse pointer entered a window's region. If focus following
            // is enabled, we need to set focus to it.
            Enter(window) => {
                if config.focus_follows_mouse && window_manager.is_window_managed(window) {
                    window_system.set_window_border_color(window, config.focus_border_color);
                    window_system.focus_window(window);
                }
            },
            // The mouse pointer
            Leave(window) => {
                if config.focus_follows_mouse && window_manager.is_window_managed(window) {
                    window_system.set_window_border_color(window, config.border_color);
                }
            },
            KeyPressed(_, key, mask) => {
                if mask & 8 != 0 && key >= 10 && key <= 18 && (key - 10) < config.tags.len() as u32 {
                    debug!("switching workspace to {}", config.tags[key as uint - 10].clone());
                    window_manager.view(&mut window_system, key - 10, &config);
                }

                if mask & 9 == 9 && key == 36 {
                    let (terminal, args) = config.terminal.clone();
                    let arguments : Vec<String> = args.split(' ').map(String::from_str).collect();
                    spawn(proc() {
                        Command::new(terminal).args(arguments.as_slice()).detached().spawn();
                    });
                }

                if mask & 9 == 9 && key == 33 {
                    spawn(proc() {
                        Command::new(String::from_str("gmrun")).detached().spawn();
                    });
                }

                if mask & 9 == 9 && key == 24 {
                    break;
                }
            }
            _ => ()
        }
    }
}
<|endoftext|>