<commit_before>#![allow(unused_variables)]
#![allow(unused_imports)]
#![allow(unused_must_use)]

//! Dropbox SDK for Rust
//!
//! This crate implements a simple client for the [Dropbox API](https://dropbox.com/developers).
//! It uses [hyper](https://hyperium.github.io) for HTTP, though that part is swappable if you would
//! like to use a different HTTP implementation.
//!
//! If you want to use hyper, just `use dbox::client::Client`, as in the example below. If,
//! however, you want to use something else, you will need to implement the `DropboxClient` trait
//! for your data structure, build this crate with `--no-default-features`, and pass a reference to
//! your client as the first parameter to the API functions.
//!
//! # Example
//!
//! ```ignore
//! extern crate dbox;
//!
//! use std::env;
//! use dbox::client::Client;
//! use dbox::files;
//!
//! let access_token = env::var("DROPBOX_TOKEN");
//! let client = Client::new(access_token);
//! let folder_list = files::copy_(&client, "/path/to/existing/file", "/path/to/new/file");
//! ```
//!

#[cfg(feature = "hyper-client")] extern crate hyper;
extern crate chrono;
extern crate rustc_serialize;

#[cfg(test)] extern crate rand;

use std::convert::From;
use std::fmt;
use std::collections::BTreeMap;

#[doc(hidden)]
pub enum Endpoint {
    Api,
    Content,
}

impl fmt::Display for Endpoint {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Endpoint::Api => write!(f, "api"),
            Endpoint::Content => write!(f, "content"),
        }
    }
}

pub trait DropboxClient {
    fn access_token(&self) -> &str;
    fn request<T>(&self, endpoint: Endpoint, url: &str, headers: &mut BTreeMap<String, String>, body: Option<T>) -> Result<Response>
            where T: rustc_serialize::Encodable + Clone;

    fn api<T>(&self, url: &str, headers: &mut BTreeMap<String, String>, body: Option<T>) -> Result<Response>
            where T: rustc_serialize::Encodable + Clone
    {
        self.request(Endpoint::Api, url, headers, body)
    }

    fn content<T>(&self, url: &str, headers: &mut BTreeMap<String, String>, body: Option<T>) -> Result<Response>
            where T: rustc_serialize::Encodable + Clone
    {
        self.request(Endpoint::Content, url, headers, body)
    }
}

/// Collection of possible errors
#[derive(Debug, PartialEq, Clone)]
pub enum ApiError {
    AddFolderMemberError,
    ClientError,
    CreateFolderError,
    CreateSharedLinkError,
    DeleteError,
    DownloadError,
    GetAccountError,
    GetAccountBatchError,
    GetMetadataError,
    GetSharedLinksError,
    ListFolderError,
    ListFolderContinueError,
    ListFolderLongpollError,
    ListFolderMembersContinueError,
    ListFoldersContinueError,
    ListRevisionsError,
    MountFolderError,
    PollError,
    PreviewError,
    RelinquishFolderMembershipError,
    RelocationError,
    RemoveFolderMemberError,
    RestoreError,
    RevokeSharedLinkError,
    SearchError,
    ShareFolderError,
    SharedFolderAccessError,
    ThumbnailError,
    TokenError,
    TransferFolderError,
    UnmountFolderError,
    UnshareFolderError,
    UpdateFolderMemberError,
    UpdateFolderPolicyError,
    UploadError,
    UploadSessionLookupError,
    UploadSessionFinishError,
}

impl From<rustc_serialize::json::DecoderError> for ApiError {
    fn from(e: rustc_serialize::json::DecoderError) -> ApiError {
        ApiError::ClientError
    }
}

/// Simple abstraction of a HTTP response, to allow the HTTP client to be pluggable
///
/// TODO: overhaul this
#[derive(Debug, PartialEq, Clone)]
pub struct Response {
    pub status: u16,
    pub api_result: Option<String>,
    pub body: String,
}

pub type Result<T> = ::std::result::Result<T, ApiError>;

#[cfg(feature = "hyper-client")]
/// Default implementation of the Dropbox Client
pub mod client;
/// Module for performing operations on files in a dropbox account
pub mod files;
/// Module that holds definitions for dropbox data structures
pub mod structs;
/// TODO
pub mod sharing;
/// TODO
pub mod users;

#[cfg(test)]
mod tests {
    use super::client::Client;
    use super::files;
    use super::DropboxClient;
    use chrono::{DateTime, Local};
    use rand;
    use std::str;
    use std::env;
    use std::default::Default;
    use rustc_serialize::json;

    const ACCESS_TOKEN: &'static str = "DROPBOX_TOKEN";
    const MALFORMED_TOKEN: &'static str = "asdf";

    fn random_ascii_letters(len: usize) -> String {
        let mut rng = rand::thread_rng();
        let ascii_letters = (65..91).chain((97..123)).collect::<Vec<u8>>();
        let random_bytes = rand::sample(&mut rng, ascii_letters.into_iter(), len);
        let random_string = str::from_utf8(&random_bytes).unwrap();
        random_string.to_owned()
    }

    #[test]
    fn test_bad_auth() {
        if let Ok(_) = Client::new(MALFORMED_TOKEN) {
            panic!("Malformed token should not be accepted");
        }

        let valid_looking_token = vec!["z"; 62].join("");
        let client = Client::new(&valid_looking_token).unwrap();
        if let Ok(_) = files::list_folder(&client, "") {
            panic!("Valid-looking but invalid token should not be accepted");
        }
    }

    #[test]
    fn test_list_rpc() {
        let access_token = match env::var(ACCESS_TOKEN) {
            Ok(t) => t,
            Err(_) => panic!("No {} found", ACCESS_TOKEN),
        };
        let client = Client::new(&access_token).unwrap();
        files::create_folder(&client, "");
        assert!(files::list_folder(&client, "").is_ok());
    }

    #[test]
    fn test_upload_download() {
        let access_token = match env::var(ACCESS_TOKEN) {
            Ok(t) => t,
            Err(_) => panic!("No {} found", ACCESS_TOKEN),
        };
        let random_filename = random_ascii_letters(15);
        let now: DateTime<Local> = Local::now();
        let now = format!("{}", now.timestamp());
        let random_path = format!("/Test/{}/{}", now, random_filename);
        let random_contents = random_ascii_letters(20);

        let client = Client::new(&access_token).unwrap();
        assert!(files::upload(&client, &random_contents, &random_path).is_ok());

        assert!(files::copy_(&client, &random_path, &format!("/Test/{}/{}copy", now, random_filename)).is_ok());

        println!("About to download file");
        let (metadata, resp) = files::download(&client, &random_path).unwrap();
        let body: String = json::decode(&resp.body).unwrap();
        assert_eq!(&body, &random_contents);

        assert!(files::delete(&client, &format!("/Test/{}", now)).is_ok());
    }
}
<commit_msg>update the tests for the latest calls that were implemented<commit_after>#![allow(unused_variables)]
#![allow(unused_imports)]
#![allow(unused_must_use)]

//! Dropbox SDK for Rust
//!
//! This crate implements a simple client for the [Dropbox API](https://dropbox.com/developers).
//! It uses [hyper](https://hyperium.github.io) for HTTP, though that part is swappable if you would
//! like to use a different HTTP implementation.
//!
//! If you want to use hyper, just `use dbox::client::Client`, as in the example below. If,
//! however, you want to use something else, you will need to implement the `DropboxClient` trait
//! for your data structure, build this crate with `--no-default-features`, and pass a reference to
//! your client as the first parameter to the API functions.
//!
//! # Example
//!
//! ```ignore
//! extern crate dbox;
//!
//! use std::env;
//! use dbox::client::Client;
//! use dbox::files;
//!
//! let access_token = env::var("DROPBOX_TOKEN");
//! let client = Client::new(access_token);
//! let folder_list = files::copy_(&client, "/path/to/existing/file", "/path/to/new/file");
//! ```
//!

#[cfg(feature = "hyper-client")] extern crate hyper;
extern crate chrono;
extern crate rustc_serialize;

#[cfg(test)] extern crate rand;

use std::convert::From;
use std::fmt;
use std::collections::BTreeMap;

#[doc(hidden)]
pub enum Endpoint {
    Api,
    Content,
}

impl fmt::Display for Endpoint {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Endpoint::Api => write!(f, "api"),
            Endpoint::Content => write!(f, "content"),
        }
    }
}

pub trait DropboxClient {
    fn access_token(&self) -> &str;
    fn request<T>(&self, endpoint: Endpoint, url: &str, headers: &mut BTreeMap<String, String>, body: Option<T>) -> Result<Response>
            where T: rustc_serialize::Encodable + Clone;

    fn api<T>(&self, url: &str, headers: &mut BTreeMap<String, String>, body: Option<T>) -> Result<Response>
            where T: rustc_serialize::Encodable + Clone
    {
        self.request(Endpoint::Api, url, headers, body)
    }

    fn content<T>(&self, url: &str, headers: &mut BTreeMap<String, String>, body: Option<T>) -> Result<Response>
            where T: rustc_serialize::Encodable + Clone
    {
        self.request(Endpoint::Content, url, headers, body)
    }
}

/// Collection of possible errors
#[derive(Debug, PartialEq, Clone)]
pub enum ApiError {
    AddFolderMemberError,
    ClientError,
    CreateFolderError,
    CreateSharedLinkError,
    DeleteError,
    DownloadError,
    GetAccountError,
    GetAccountBatchError,
    GetMetadataError,
    GetSharedLinksError,
    ListFolderError,
    ListFolderContinueError,
    ListFolderLongpollError,
    ListFolderMembersContinueError,
    ListFoldersContinueError,
    ListRevisionsError,
    MountFolderError,
    PollError,
    PreviewError,
    RelinquishFolderMembershipError,
    RelocationError,
    RemoveFolderMemberError,
    RestoreError,
    RevokeSharedLinkError,
    SearchError,
    ShareFolderError,
    SharedFolderAccessError,
    ThumbnailError,
    TokenError,
    TransferFolderError,
    UnmountFolderError,
    UnshareFolderError,
    UpdateFolderMemberError,
    UpdateFolderPolicyError,
    UploadError,
    UploadSessionLookupError,
    UploadSessionFinishError,
}

impl From<rustc_serialize::json::DecoderError> for ApiError {
    fn from(e: rustc_serialize::json::DecoderError) -> ApiError {
        ApiError::ClientError
    }
}

/// Simple abstraction of a HTTP response, to allow the HTTP client to be pluggable
///
/// TODO: overhaul this
#[derive(Debug, PartialEq, Clone)]
pub struct Response {
    pub status: u16,
    pub api_result: Option<String>,
    pub body: String,
}

pub type Result<T> = ::std::result::Result<T, ApiError>;

#[cfg(feature = "hyper-client")]
/// Default implementation of the Dropbox Client
pub mod client;
/// Module for performing operations on files in a dropbox account
pub mod files;
/// Module that holds definitions for dropbox data structures
pub mod structs;
/// TODO
pub mod sharing;
/// TODO
pub mod users;

#[cfg(test)]
mod tests {
    use super::client::Client;
    use super::files;
    use super::DropboxClient;
    use chrono::{DateTime, Local};
    use rand;
    use std::str;
    use std::env;
    use std::default::Default;
    use rustc_serialize::json;

    const ACCESS_TOKEN: &'static str = "DROPBOX_TOKEN";
    const MALFORMED_TOKEN: &'static str = "asdf";

    fn random_ascii_letters(len: usize) -> String {
        let mut rng = rand::thread_rng();
        let ascii_letters = (65..91).chain((97..123)).collect::<Vec<u8>>();
        let random_bytes = rand::sample(&mut rng, ascii_letters.into_iter(), len);
        let random_string = str::from_utf8(&random_bytes).unwrap();
        random_string.to_owned()
    }

    #[test]
    fn test_bad_auth() {
        if let Ok(_) = Client::new(MALFORMED_TOKEN) {
            panic!("Malformed token should not be accepted");
        }

        let valid_looking_token = vec!["z"; 62].join("");
        let client = Client::new(&valid_looking_token).unwrap();
        if let Ok(_) = files::list_folder(&client, "") {
            panic!("Valid-looking but invalid token should not be accepted");
        }
    }

    #[test]
    fn test_list_rpc() {
        let access_token = match env::var(ACCESS_TOKEN) {
            Ok(t) => t,
            Err(_) => panic!("No {} found", ACCESS_TOKEN),
        };
        let client = Client::new(&access_token).unwrap();
        assert!(files::create_folder(&client, "/testdir").is_ok());
        assert!(files::list_folder(&client, "/testdir").is_ok());
        assert!(files::delete(&client, "/testdir").is_ok());
    }

    #[test]
    fn test_upload_download() {
        let access_token = match env::var(ACCESS_TOKEN) {
            Ok(t) => t,
            Err(_) => panic!("No {} found", ACCESS_TOKEN),
        };
        let random_filename = random_ascii_letters(15);
        let now: DateTime<Local> = Local::now();
        let now = format!("{}", now.timestamp());
        let random_dir = format!("/Test/{}", now);
        let random_path = format!("/Test/{}/{}", now, random_filename);
        let random_path_copy = format!("/Test/{}/{}copy", now, random_filename);
        let random_contents = random_ascii_letters(20);

        let client = Client::new(&access_token).unwrap();

        assert!(files::upload(&client, &random_contents, &random_path).is_ok());

        files::list_folder(&client, &random_dir);

        assert!(files::copy_(&client, &random_path, &random_path_copy).is_ok());

        println!("About to download file");
        let (metadata, resp) = files::download(&client, &random_path).unwrap();
        let body: String = json::decode(&resp.body).unwrap();
        assert_eq!(&body, &random_contents);

        assert!(files::delete(&client, &random_path_copy).is_ok());
        assert!(files::delete(&client, &random_path).is_ok());
        assert!(files::delete(&client, &random_dir).is_ok());
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! A GLFW window back-end for the Piston game engine.

extern crate glfw;
extern crate collections;
extern crate gl;
extern crate event;
extern crate shader_version;
extern crate input;
extern crate current;

// External crates.
use current::{ Get, Modifier, Set };
use collections::RingBuf;
use glfw::Context;
use input::{
    keyboard,
    mouse,
    InputEvent,
};
use event::{
    Window,
    WindowSettings,
};
use event::window::{ ShouldClose, Size };
use event::window::{ PollEvent, SwapBuffers };
use event::window::{ CaptureCursor, SetCaptureCursor };
use shader_version::opengl::OpenGL;

/// Contains stuff for game window.
pub struct GlfwWindow {
    /// The window.
    pub window: glfw::Window,
    /// Receives events from window.
    events: Receiver<(f64, glfw::WindowEvent)>,
    /// GLFW context.
    pub glfw: glfw::Glfw,
    /// Game window settings.
    settings: WindowSettings,
    event_queue: RingBuf<input::InputEvent>,
    // Used to compute relative mouse movement.
    last_mouse_pos: Option<(f64, f64)>,
}

impl GlfwWindow {
    /// Create a new game window from an existing GLFW window.
    pub fn from_pieces(win: glfw::Window, glfw: glfw::Glfw,
                       events: Receiver<(f64, glfw::WindowEvent)>,
                       exit_on_esc: bool) -> GlfwWindow {
        win.set_all_polling(true);
        win.make_current();

        let (w, h) = win.get_framebuffer_size();
        let fullscreen = win.with_window_mode(|m| match m { glfw::Windowed => true, _ => false });

        GlfwWindow {
            window: win,
            events: events,
            glfw: glfw,
            settings: WindowSettings {
                title: "<unknown window title, created with from_pieces>".to_string(),
                size: [w as u32, h as u32],
                samples: 0, //unknown
                fullscreen: fullscreen,
                exit_on_esc: exit_on_esc,
            },
            event_queue: RingBuf::new(),
            last_mouse_pos: None,
        }
    }

    /// Creates a new game window for GLFW.
    pub fn new(opengl: OpenGL, settings: WindowSettings) -> GlfwWindow {
        use glfw::Context;

        // Initialize GLFW.
        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

        let (major, minor) = opengl.get_major_minor();

        // Make sure we have the right GL version.
        glfw.window_hint(glfw::ContextVersion(major as u32, minor as u32));
        glfw.window_hint(glfw::OpenglForwardCompat(true));
        glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));
        glfw.window_hint(glfw::Samples(settings.samples as u32));

        // Create GLFW window.
        let (window, events) = glfw.create_window(
            settings.size[0],
            settings.size[1],
            settings.title.as_slice(), glfw::Windowed
        ).expect("Failed to create GLFW window.");
        window.set_all_polling(true);
        window.make_current();

        // Load the OpenGL function pointers
        gl::load_with(|s| window.get_proc_address(s));

        GlfwWindow {
            window: window,
            events: events,
            glfw: glfw,
            settings: settings,
            event_queue: RingBuf::new(),
            last_mouse_pos: None,
        }
    }

    fn flush_messages(&mut self) {
        if self.event_queue.len() != 0 {
            return;
        }

        self.glfw.poll_events();
        for (_, event) in glfw::flush_messages(&self.events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _)
                if self.settings.exit_on_esc => {
                    self.window.set_should_close(true);
                }
                glfw::CharEvent(ch) => {
                    self.event_queue.push_back(input::Text(ch.to_string()));
                }
                glfw::KeyEvent(key, _, glfw::Press, _) => {
                    self.event_queue.push_back(
                        input::Press(input::Keyboard(glfw_map_key(key)))
                    );
                }
                glfw::KeyEvent(key, _, glfw::Release, _) => {
                    self.event_queue.push_back(
                        input::Release(input::Keyboard(glfw_map_key(key)))
                    );
                }
                glfw::MouseButtonEvent(button, glfw::Press, _) => {
                    self.event_queue.push_back(
                        input::Press(input::Mouse(glfw_map_mouse(button)))
                    );
                }
                glfw::MouseButtonEvent(button, glfw::Release, _) => {
                    self.event_queue.push_back(
                        input::Release(input::Mouse(glfw_map_mouse(button)))
                    );
                }
                glfw::CursorPosEvent(x, y) => {
                    self.event_queue.push_back(input::Move(input::MouseCursor(x, y)));
                    match self.last_mouse_pos {
                        Some((lx, ly)) => {
                            self.event_queue.push_back(
                                input::Move(input::MouseRelative(x - lx, y - ly))
                            )
                        }
                        None => {}
                    };
                    self.last_mouse_pos = Some((x, y));
                }
                glfw::ScrollEvent(x, y) => {
                    self.event_queue.push_back(input::Move(input::MouseScroll(x, y)));
                }
                glfw::SizeEvent(w, h) => {
                    self.event_queue.push_back(input::Resize(w as u32, h as u32));
                }
                glfw::FocusEvent(focus) => {
                    self.event_queue.push_back(input::Focus(focus));
                }
                _ => {}
            }
        }
    }
}

impl Get<Size> for GlfwWindow {
    fn get(&self) -> Size {
        let (w, h) = self.window.get_size();
        Size([w as u32, h as u32])
    }
}

impl Get<ShouldClose> for GlfwWindow {
    fn get(&self) -> ShouldClose {
        ShouldClose(self.window.should_close())
    }
}

impl PollEvent<InputEvent> for GlfwWindow {
    fn poll_event(&mut self) -> Option<input::InputEvent> {
        self.flush_messages();

        if self.event_queue.len() != 0 {
            self.event_queue.pop_front()
        } else {
            None
        }
    }
}

impl SwapBuffers for GlfwWindow {
    fn swap_buffers(&mut self) {
        use glfw::Context;

        self.window.swap_buffers();
    }
}

impl Modifier<GlfwWindow> for CaptureCursor {
    fn modify(self, window: &mut GlfwWindow) {
        let CaptureCursor(enabled) = self;
        if enabled {
            window.window.set_cursor_mode(glfw::CursorDisabled)
        } else {
            window.window.set_cursor_mode(glfw::CursorNormal);
            window.last_mouse_pos = None;
        }
    }
}

impl SetCaptureCursor for GlfwWindow {
    fn set_capture_cursor(&mut self, val: CaptureCursor) {
        self.set_mut(val);
    }
}

impl Window for GlfwWindow {
    fn get_settings<'a>(&'a self) -> &'a WindowSettings {
        &self.settings
    }

    fn get_draw_size(&self) -> (u32, u32) {
        let (w, h) = self.window.get_framebuffer_size();
        (w as u32, h as u32)
    }

    fn close(&mut self) {
        self.window.set_should_close(true);
    }
}

fn glfw_map_key(keycode: glfw::Key) -> keyboard::Key {
    match keycode {
        glfw::Key0 => keyboard::D0,
        glfw::Key1 => keyboard::D1,
        glfw::Key2 => keyboard::D2,
        glfw::Key3 => keyboard::D3,
        glfw::Key4 => keyboard::D4,
        glfw::Key5 => keyboard::D5,
        glfw::Key6 => keyboard::D6,
        glfw::Key7 => keyboard::D7,
        glfw::Key8 => keyboard::D8,
        glfw::Key9 => keyboard::D9,
        glfw::KeyA => keyboard::A,
        glfw::KeyB => keyboard::B,
        glfw::KeyC => keyboard::C,
        glfw::KeyD => keyboard::D,
        glfw::KeyE => keyboard::E,
        glfw::KeyF => keyboard::F,
        glfw::KeyG => keyboard::G,
        glfw::KeyH => keyboard::H,
        glfw::KeyI => keyboard::I,
        glfw::KeyJ => keyboard::J,
        glfw::KeyK => keyboard::K,
        glfw::KeyL => keyboard::L,
        glfw::KeyM => keyboard::M,
        glfw::KeyN => keyboard::N,
        glfw::KeyO => keyboard::O,
        glfw::KeyP => keyboard::P,
        glfw::KeyQ => keyboard::Q,
        glfw::KeyR => keyboard::R,
        glfw::KeyS => keyboard::S,
        glfw::KeyT => keyboard::T,
        glfw::KeyU => keyboard::U,
        glfw::KeyV => keyboard::V,
        glfw::KeyW => keyboard::W,
        glfw::KeyX => keyboard::X,
        glfw::KeyY => keyboard::Y,
        glfw::KeyZ => keyboard::Z,
        glfw::KeyApostrophe => keyboard::Unknown,
        glfw::KeyBackslash => keyboard::Backslash,
        glfw::KeyBackspace => keyboard::Backspace,
        glfw::KeyCapsLock => keyboard::CapsLock,
        glfw::KeyDelete => keyboard::Delete,
        glfw::KeyComma => keyboard::Comma,
        glfw::KeyDown => keyboard::Down,
        glfw::KeyEnd => keyboard::End,
        glfw::KeyEnter => keyboard::Return,
        glfw::KeyEqual => keyboard::Equals,
        glfw::KeyEscape => keyboard::Escape,
        glfw::KeyF1 => keyboard::F1,
        glfw::KeyF2 => keyboard::F2,
        glfw::KeyF3 => keyboard::F3,
        glfw::KeyF4 => keyboard::F4,
        glfw::KeyF5 => keyboard::F5,
        glfw::KeyF6 => keyboard::F6,
        glfw::KeyF7 => keyboard::F7,
        glfw::KeyF8 => keyboard::F8,
        glfw::KeyF9 => keyboard::F9,
        glfw::KeyF10 => keyboard::F10,
        glfw::KeyF11 => keyboard::F11,
        glfw::KeyF12 => keyboard::F12,
        glfw::KeyF13 => keyboard::F13,
        glfw::KeyF14 => keyboard::F14,
        glfw::KeyF15 => keyboard::F15,
        glfw::KeyF16 => keyboard::F16,
        glfw::KeyF17 => keyboard::F17,
        glfw::KeyF18 => keyboard::F18,
        glfw::KeyF19 => keyboard::F19,
        glfw::KeyF20 => keyboard::F20,
        glfw::KeyF21 => keyboard::F21,
        glfw::KeyF22 => keyboard::F22,
        glfw::KeyF23 => keyboard::F23,
        glfw::KeyF24 => keyboard::F24,
        // Possibly next code.
        glfw::KeyF25 => keyboard::Unknown,
        glfw::KeyKp0 => keyboard::NumPad0,
        glfw::KeyKp1 => keyboard::NumPad1,
        glfw::KeyKp2 => keyboard::NumPad2,
        glfw::KeyKp3 => keyboard::NumPad3,
        glfw::KeyKp4 => keyboard::NumPad4,
        glfw::KeyKp5 => keyboard::NumPad5,
        glfw::KeyKp6 => keyboard::NumPad6,
        glfw::KeyKp7 => keyboard::NumPad7,
        glfw::KeyKp8 => keyboard::NumPad8,
        glfw::KeyKp9 => keyboard::NumPad9,
        glfw::KeyKpDecimal => keyboard::NumPadDecimal,
        glfw::KeyKpDivide => keyboard::NumPadDivide,
        glfw::KeyKpMultiply => keyboard::NumPadMultiply,
        glfw::KeyKpSubtract => keyboard::NumPadMinus,
        glfw::KeyKpAdd => keyboard::NumPadPlus,
        glfw::KeyKpEnter => keyboard::NumPadEnter,
        glfw::KeyKpEqual => keyboard::NumPadEquals,
        glfw::KeyLeftShift => keyboard::LShift,
        glfw::KeyLeftControl => keyboard::LCtrl,
        glfw::KeyLeftAlt => keyboard::LAlt,
        glfw::KeyLeftSuper => keyboard::LGui,
        glfw::KeyRightShift => keyboard::RShift,
        glfw::KeyRightControl => keyboard::RCtrl,
        glfw::KeyRightAlt => keyboard::RAlt,
        glfw::KeyRightSuper => keyboard::RGui,
        // Map to backslash?
        glfw::KeyGraveAccent => keyboard::Unknown,
        glfw::KeyHome => keyboard::Home,
        glfw::KeyInsert => keyboard::Insert,
        glfw::KeyLeft => keyboard::Left,
        glfw::KeyLeftBracket => keyboard::LeftBracket,
        glfw::KeyMenu => keyboard::Menu,
        glfw::KeyMinus => keyboard::Minus,
        glfw::KeyNumLock => keyboard::NumLockClear,
        glfw::KeyPageDown => keyboard::PageDown,
        glfw::KeyPageUp => keyboard::PageUp,
        glfw::KeyPause => keyboard::Pause,
        glfw::KeyPeriod => keyboard::Period,
        glfw::KeyPrintScreen => keyboard::PrintScreen,
        glfw::KeyRight => keyboard::Right,
        glfw::KeyRightBracket => keyboard::RightBracket,
        glfw::KeyScrollLock => keyboard::ScrollLock,
        glfw::KeySemicolon => keyboard::Semicolon,
        glfw::KeySlash => keyboard::Slash,
        glfw::KeySpace => keyboard::Space,
        glfw::KeyTab => keyboard::Tab,
        glfw::KeyUp => keyboard::Up,
        glfw::KeyWorld1 => keyboard::Unknown,
        glfw::KeyWorld2 => keyboard::Unknown,
        // _ => keyboard::Unknown,
    }
}

fn glfw_map_mouse(mouse_button: glfw::MouseButton) -> mouse::Button {
    match mouse_button {
        glfw::MouseButton1 => mouse::Left,
        glfw::MouseButton2 => mouse::Right,
        glfw::MouseButton3 => mouse::Middle,
        glfw::MouseButton4 => mouse::X1,
        glfw::MouseButton5 => mouse::X2,
        glfw::MouseButton6 => mouse::Button6,
        glfw::MouseButton7 => mouse::Button7,
        glfw::MouseButton8 => mouse::Button8,
    }
}
<commit_msg>Upgraded to latest piston-event<commit_after>#![deny(missing_docs)]

//! A GLFW window back-end for the Piston game engine.

extern crate glfw;
extern crate collections;
extern crate gl;
extern crate event;
extern crate shader_version;
extern crate input;
extern crate current;

// External crates.
use current::{ Get, Modifier, Set };
use collections::RingBuf;
use glfw::Context;
use input::{
    keyboard,
    mouse,
    InputEvent,
};
use event::{
    Window,
    WindowSettings,
};
use event::window::{ ShouldClose, SetShouldClose, Size };
use event::window::{ PollEvent, SwapBuffers };
use event::window::{ CaptureCursor, SetCaptureCursor };
use shader_version::opengl::OpenGL;

/// Contains stuff for game window.
pub struct GlfwWindow {
    /// The window.
    pub window: glfw::Window,
    /// Receives events from window.
    events: Receiver<(f64, glfw::WindowEvent)>,
    /// GLFW context.
    pub glfw: glfw::Glfw,
    /// Game window settings.
    settings: WindowSettings,
    event_queue: RingBuf<input::InputEvent>,
    // Used to compute relative mouse movement.
    last_mouse_pos: Option<(f64, f64)>,
}

impl GlfwWindow {
    /// Create a new game window from an existing GLFW window.
    pub fn from_pieces(win: glfw::Window, glfw: glfw::Glfw,
                       events: Receiver<(f64, glfw::WindowEvent)>,
                       exit_on_esc: bool) -> GlfwWindow {
        win.set_all_polling(true);
        win.make_current();

        let (w, h) = win.get_framebuffer_size();
        let fullscreen = win.with_window_mode(|m| match m { glfw::Windowed => true, _ => false });

        GlfwWindow {
            window: win,
            events: events,
            glfw: glfw,
            settings: WindowSettings {
                title: "<unknown window title, created with from_pieces>".to_string(),
                size: [w as u32, h as u32],
                samples: 0, //unknown
                fullscreen: fullscreen,
                exit_on_esc: exit_on_esc,
            },
            event_queue: RingBuf::new(),
            last_mouse_pos: None,
        }
    }

    /// Creates a new game window for GLFW.
    pub fn new(opengl: OpenGL, settings: WindowSettings) -> GlfwWindow {
        use glfw::Context;

        // Initialize GLFW.
        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

        let (major, minor) = opengl.get_major_minor();

        // Make sure we have the right GL version.
        glfw.window_hint(glfw::ContextVersion(major as u32, minor as u32));
        glfw.window_hint(glfw::OpenglForwardCompat(true));
        glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));
        glfw.window_hint(glfw::Samples(settings.samples as u32));

        // Create GLFW window.
        let (window, events) = glfw.create_window(
            settings.size[0],
            settings.size[1],
            settings.title.as_slice(), glfw::Windowed
        ).expect("Failed to create GLFW window.");
        window.set_all_polling(true);
        window.make_current();

        // Load the OpenGL function pointers
        gl::load_with(|s| window.get_proc_address(s));

        GlfwWindow {
            window: window,
            events: events,
            glfw: glfw,
            settings: settings,
            event_queue: RingBuf::new(),
            last_mouse_pos: None,
        }
    }

    fn flush_messages(&mut self) {
        if self.event_queue.len() != 0 {
            return;
        }

        self.glfw.poll_events();
        for (_, event) in glfw::flush_messages(&self.events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _)
                if self.settings.exit_on_esc => {
                    self.window.set_should_close(true);
                }
                glfw::CharEvent(ch) => {
                    self.event_queue.push_back(input::Text(ch.to_string()));
                }
                glfw::KeyEvent(key, _, glfw::Press, _) => {
                    self.event_queue.push_back(
                        input::Press(input::Keyboard(glfw_map_key(key)))
                    );
                }
                glfw::KeyEvent(key, _, glfw::Release, _) => {
                    self.event_queue.push_back(
                        input::Release(input::Keyboard(glfw_map_key(key)))
                    );
                }
                glfw::MouseButtonEvent(button, glfw::Press, _) => {
                    self.event_queue.push_back(
                        input::Press(input::Mouse(glfw_map_mouse(button)))
                    );
                }
                glfw::MouseButtonEvent(button, glfw::Release, _) => {
                    self.event_queue.push_back(
                        input::Release(input::Mouse(glfw_map_mouse(button)))
                    );
                }
                glfw::CursorPosEvent(x, y) => {
                    self.event_queue.push_back(input::Move(input::MouseCursor(x, y)));
                    match self.last_mouse_pos {
                        Some((lx, ly)) => {
                            self.event_queue.push_back(
                                input::Move(input::MouseRelative(x - lx, y - ly))
                            )
                        }
                        None => {}
                    };
                    self.last_mouse_pos = Some((x, y));
                }
                glfw::ScrollEvent(x, y) => {
                    self.event_queue.push_back(input::Move(input::MouseScroll(x, y)));
                }
                glfw::SizeEvent(w, h) => {
                    self.event_queue.push_back(input::Resize(w as u32, h as u32));
                }
                glfw::FocusEvent(focus) => {
                    self.event_queue.push_back(input::Focus(focus));
                }
                _ => {}
            }
        }
    }
}

impl Get<Size> for GlfwWindow {
    fn get(&self) -> Size {
        let (w, h) = self.window.get_size();
        Size([w as u32, h as u32])
    }
}

impl Get<ShouldClose> for GlfwWindow {
    fn get(&self) -> ShouldClose {
        ShouldClose(self.window.should_close())
    }
}

impl PollEvent<InputEvent> for GlfwWindow {
    fn poll_event(&mut self) -> Option<input::InputEvent> {
        self.flush_messages();

        if self.event_queue.len() != 0 {
            self.event_queue.pop_front()
        } else {
            None
        }
    }
}

impl SwapBuffers for GlfwWindow {
    fn swap_buffers(&mut self) {
        use glfw::Context;

        self.window.swap_buffers();
    }
}

impl Modifier<GlfwWindow> for CaptureCursor {
    fn modify(self, window: &mut GlfwWindow) {
        let CaptureCursor(enabled) = self;
        if enabled {
            window.window.set_cursor_mode(glfw::CursorDisabled)
        } else {
            window.window.set_cursor_mode(glfw::CursorNormal);
            window.last_mouse_pos = None;
        }
    }
}

impl SetCaptureCursor for GlfwWindow {
    fn set_capture_cursor(&mut self, val: CaptureCursor) {
        self.set_mut(val);
    }
}

impl Modifier<GlfwWindow> for ShouldClose {
    fn modify(self, window: &mut GlfwWindow) {
        let ShouldClose(val) = self;
        window.window.set_should_close(val);
    }
}

impl SetShouldClose for GlfwWindow {
    fn set_should_close(&mut self, val: ShouldClose) {
        self.set_mut(val);
    }
}

impl Window for GlfwWindow {
    fn get_settings<'a>(&'a self) -> &'a WindowSettings {
        &self.settings
    }

    fn get_draw_size(&self) -> (u32, u32) {
        let (w, h) = self.window.get_framebuffer_size();
        (w as u32, h as u32)
    }
}

fn glfw_map_key(keycode: glfw::Key) -> keyboard::Key {
    match keycode {
        glfw::Key0 => keyboard::D0,
        glfw::Key1 => keyboard::D1,
        glfw::Key2 => keyboard::D2,
        glfw::Key3 => keyboard::D3,
        glfw::Key4 => keyboard::D4,
        glfw::Key5 => keyboard::D5,
        glfw::Key6 => keyboard::D6,
        glfw::Key7 => keyboard::D7,
        glfw::Key8 => keyboard::D8,
        glfw::Key9 => keyboard::D9,
        glfw::KeyA => keyboard::A,
        glfw::KeyB => keyboard::B,
        glfw::KeyC => keyboard::C,
        glfw::KeyD => keyboard::D,
        glfw::KeyE => keyboard::E,
        glfw::KeyF => keyboard::F,
        glfw::KeyG => keyboard::G,
        glfw::KeyH => keyboard::H,
        glfw::KeyI => keyboard::I,
        glfw::KeyJ => keyboard::J,
        glfw::KeyK => keyboard::K,
        glfw::KeyL => keyboard::L,
        glfw::KeyM => keyboard::M,
        glfw::KeyN => keyboard::N,
        glfw::KeyO => keyboard::O,
        glfw::KeyP => keyboard::P,
        glfw::KeyQ => keyboard::Q,
        glfw::KeyR => keyboard::R,
        glfw::KeyS => keyboard::S,
        glfw::KeyT => keyboard::T,
        glfw::KeyU => keyboard::U,
        glfw::KeyV => keyboard::V,
        glfw::KeyW => keyboard::W,
        glfw::KeyX => keyboard::X,
        glfw::KeyY => keyboard::Y,
        glfw::KeyZ => keyboard::Z,
        glfw::KeyApostrophe => keyboard::Unknown,
        glfw::KeyBackslash => keyboard::Backslash,
        glfw::KeyBackspace => keyboard::Backspace,
        glfw::KeyCapsLock => keyboard::CapsLock,
        glfw::KeyDelete => keyboard::Delete,
        glfw::KeyComma => keyboard::Comma,
        glfw::KeyDown => keyboard::Down,
        glfw::KeyEnd => keyboard::End,
        glfw::KeyEnter => keyboard::Return,
        glfw::KeyEqual => keyboard::Equals,
        glfw::KeyEscape => keyboard::Escape,
        glfw::KeyF1 => keyboard::F1,
        glfw::KeyF2 => keyboard::F2,
        glfw::KeyF3 => keyboard::F3,
        glfw::KeyF4 => keyboard::F4,
        glfw::KeyF5 => keyboard::F5,
        glfw::KeyF6 => keyboard::F6,
        glfw::KeyF7 => keyboard::F7,
        glfw::KeyF8 => keyboard::F8,
        glfw::KeyF9 => keyboard::F9,
        glfw::KeyF10 => keyboard::F10,
        glfw::KeyF11 => keyboard::F11,
        glfw::KeyF12 => keyboard::F12,
        glfw::KeyF13 => keyboard::F13,
        glfw::KeyF14 => keyboard::F14,
        glfw::KeyF15 => keyboard::F15,
        glfw::KeyF16 => keyboard::F16,
        glfw::KeyF17 => keyboard::F17,
        glfw::KeyF18 => keyboard::F18,
        glfw::KeyF19 => keyboard::F19,
        glfw::KeyF20 => keyboard::F20,
        glfw::KeyF21 => keyboard::F21,
        glfw::KeyF22 => keyboard::F22,
        glfw::KeyF23 => keyboard::F23,
        glfw::KeyF24 => keyboard::F24,
        // Possibly next code.
        glfw::KeyF25 => keyboard::Unknown,
        glfw::KeyKp0 => keyboard::NumPad0,
        glfw::KeyKp1 => keyboard::NumPad1,
        glfw::KeyKp2 => keyboard::NumPad2,
        glfw::KeyKp3 => keyboard::NumPad3,
        glfw::KeyKp4 => keyboard::NumPad4,
        glfw::KeyKp5 => keyboard::NumPad5,
        glfw::KeyKp6 => keyboard::NumPad6,
        glfw::KeyKp7 => keyboard::NumPad7,
        glfw::KeyKp8 => keyboard::NumPad8,
        glfw::KeyKp9 => keyboard::NumPad9,
        glfw::KeyKpDecimal => keyboard::NumPadDecimal,
        glfw::KeyKpDivide => keyboard::NumPadDivide,
        glfw::KeyKpMultiply => keyboard::NumPadMultiply,
        glfw::KeyKpSubtract => keyboard::NumPadMinus,
        glfw::KeyKpAdd => keyboard::NumPadPlus,
        glfw::KeyKpEnter => keyboard::NumPadEnter,
        glfw::KeyKpEqual => keyboard::NumPadEquals,
        glfw::KeyLeftShift => keyboard::LShift,
        glfw::KeyLeftControl => keyboard::LCtrl,
        glfw::KeyLeftAlt => keyboard::LAlt,
        glfw::KeyLeftSuper => keyboard::LGui,
        glfw::KeyRightShift => keyboard::RShift,
        glfw::KeyRightControl => keyboard::RCtrl,
        glfw::KeyRightAlt => keyboard::RAlt,
        glfw::KeyRightSuper => keyboard::RGui,
        // Map to backslash?
        glfw::KeyGraveAccent => keyboard::Unknown,
        glfw::KeyHome => keyboard::Home,
        glfw::KeyInsert => keyboard::Insert,
        glfw::KeyLeft => keyboard::Left,
        glfw::KeyLeftBracket => keyboard::LeftBracket,
        glfw::KeyMenu => keyboard::Menu,
        glfw::KeyMinus => keyboard::Minus,
        glfw::KeyNumLock => keyboard::NumLockClear,
        glfw::KeyPageDown => keyboard::PageDown,
        glfw::KeyPageUp => keyboard::PageUp,
        glfw::KeyPause => keyboard::Pause,
        glfw::KeyPeriod => keyboard::Period,
        glfw::KeyPrintScreen => keyboard::PrintScreen,
        glfw::KeyRight => keyboard::Right,
        glfw::KeyRightBracket => keyboard::RightBracket,
        glfw::KeyScrollLock => keyboard::ScrollLock,
        glfw::KeySemicolon => keyboard::Semicolon,
        glfw::KeySlash => keyboard::Slash,
        glfw::KeySpace => keyboard::Space,
        glfw::KeyTab => keyboard::Tab,
        glfw::KeyUp => keyboard::Up,
        glfw::KeyWorld1 => keyboard::Unknown,
        glfw::KeyWorld2 => keyboard::Unknown,
        // _ => keyboard::Unknown,
    }
}

fn glfw_map_mouse(mouse_button: glfw::MouseButton) -> mouse::Button {
    match mouse_button {
        glfw::MouseButton1 => mouse::Left,
        glfw::MouseButton2 => mouse::Right,
        glfw::MouseButton3 => mouse::Middle,
        glfw::MouseButton4 => mouse::X1,
        glfw::MouseButton5 => mouse::X2,
        glfw::MouseButton6 => mouse::Button6,
        glfw::MouseButton7 => mouse::Button7,
        glfw::MouseButton8 => mouse::Button8,
    }
}
<|endoftext|>


<commit_before>// Rx -- Reactive programming for Rust
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

//! Rx, a library for reactive programming in Rust.
//! Inspired by [Reactive Extensions for C#](https://rx.codeplex.com/).
//!
//! TODO: Add intro to observables for people who are unfamiliar with them.
//!
//! TODO: Add examples.

#![warn(missing_docs)]
#![feature(fn_traits, unboxed_closures)]

use observer::{NextObserver, CompletedObserver, ErrorObserver, OptionObserver, ResultObserver};
use std::fmt::Debug;
use std::iter::IntoIterator;

mod observer;

pub use observer::{Observer, BoxedObserver};

/// A stream of values.
///
/// An observable represents a stream of values, much like an iterator,
/// but instead of being “pull-based” like an iterator, it is “push-based”.
/// Multiple observers can subscribe to an observable and when the observable
/// produces a value, all observers get called with this value.
///
/// An observable can be _finite_ or _infinite_. An example of an infinite
/// observable are mouse clicks: you never know if the user is going to click
/// once more. An example of a finite observable are the results of a database
/// query: a database is can hold only finitely many records, so one result is
/// the last one.
///
/// A finite observable can end in two ways:
///
///  * **Completed**: when the observable ends normally.
///    For instance, an observable of database query results
///    will complete after the last result has been produced.
///  * **Failed**: when an error occurred.
///    For instance, an observable of database query results
///    may fail if the connection is lost.
///
/// Failures are fatal: after an observable produces an error, it will not
/// produce any new values. If this is not the desired behavior, you can
/// use an observable of `Result`.
pub trait Observable {
    /// The value produced by the observable.
    type Item;

    /// The error produced if the observable fails.
    type Error;

    /// The result of subscribing an observer.
    type Subscription: Drop;

    /// Subscribes an observer and returns the subscription.
    ///
    /// After subscription, `on_next` will be called on the observer for every
    /// value produced. If the observable completes, `on_completed` is called.
    /// If the observable fails with an error, `on_error` is called. It is
    /// guaranteed that no methods will be called on the observer after
    /// `on_completed` or `on_error` have been called.
    ///
    /// _When_ the observer is called is not part of the observable contract,
    /// it depends on the kind of observable. The observer may be called before
    /// `subscribe` returns, or it may be called in the future.
    ///
    /// The returned value represents the subscription. Dropping the subscription
    /// will prevent further calls on the observer.
    fn subscribe<O>(&mut self, observer: O) -> Self::Subscription
        where O: Observer<Self::Item, Self::Error>;

    /// Subscribes a function to handle values produced by the observable.
    ///
    /// For every value produced by the observable, `on_next` is called.
    ///
    /// **This subscription panics if the observable fails with an error.**
    ///
    /// See also [`subscribe()`](#tymethod.subscribe).
    fn subscribe_next<FnNext>(&mut self,
                              on_next: FnNext)
                              -> Self::Subscription
        where Self::Error: Debug, FnNext: FnMut(Self::Item) {
        let observer = NextObserver {
            fn_next: on_next,
        };
        self.subscribe(observer)
    }

    /// Subscribes functions to handle next and completion.
    ///
    /// For every value produced by the observable, `on_next` is called. If the
    /// observable completes, `on_completed` is called. A failure will cause a
    /// panic. After `on_completed` has been called, it is guaranteed that neither
    /// `on_next` nor `on_completed` is called again.
    ///
    /// **This subscription panics if the observable fails with an error.**
    ///
    /// See also [`subscribe()`](#tymethod.subscribe).
    fn subscribe_completed<FnNext, FnCompleted>(&mut self,
                                                on_next: FnNext,
                                                on_completed: FnCompleted)
                                                -> Self::Subscription
        where Self::Error: Debug, FnNext: FnMut(Self::Item), FnCompleted: FnOnce() {
        let observer = CompletedObserver {
            fn_next: on_next,
            fn_completed: on_completed,
        };
        self.subscribe(observer)
    }

    /// Subscribes functions to handle next, completion, and error.
    ///
    /// For every value produced by the observable, `on_next` is called. If the
    /// observable completes, `on_completed` is called. If it fails, `on_error`
    /// is called. After `on_completed` or `on_error` have been called, it is
    /// guaranteed that none of the three functions are called again.
    ///
    /// See also [`subscribe()`](#tymethod.subscribe).
    fn subscribe_error<FnNext, FnCompleted, FnError>(&mut self,
                                                     on_next: FnNext,
                                                     on_completed: FnCompleted,
                                                     on_error: FnError)
                                                     -> Self::Subscription
        where FnNext: FnMut(Self::Item), FnCompleted: FnOnce(), FnError: FnOnce(Self::Error) {
        let observer = ErrorObserver {
            fn_next: on_next,
            fn_completed: on_completed,
            fn_error: on_error,
        };
        self.subscribe(observer)
    }

    /// Subscribes a function that takes an option.
    ///
    /// The function translates into an observer as follows:
    ///
    ///  * `on_next(x)`: calls the functions with `Some(x)`.
    ///  * `on_completed()`: calls the function with `None`.
    ///  * `on_error(error)`: panics.
    ///
    /// After the function has been called with `None`,
    /// it is guaranteed never to be called again.
    ///
    /// **This subscription panics if the observable fails with an error.**
    ///
    /// See also [`subscribe()`](#tymethod.subscribe).
    fn subscribe_option<FnOption>(&mut self,
                                  on_next_or_completed: FnOption)
                                  -> Self::Subscription
        where Self::Error: Debug, FnOption: FnMut(Option<Self::Item>) {
        let observer = OptionObserver {
            fn_option: on_next_or_completed
        };
        self.subscribe(observer)
    }

    /// Subscribes a function that takes a result of an option.
    ///
    /// The function translates into an observer as follows:
    ///
    ///  * `on_next(x)`: calls the function with `Ok(Some(x))`.
    ///  * `on_completed()`: calls the function with `Ok(None)`.
    ///  * `on_error(error)`: calls the function with `Err(error)`.
    ///
    /// After the function has been called with `Ok(None)` or `Err(error)`,
    /// it is guaranteed never to be called again.
    ///
    /// See also [`subscribe()`](#tymethod.subscribe).
    fn subscribe_result<FnResult>(&mut self,
                                  on_next_or_completed_or_error: FnResult)
                                  -> Self::Subscription
        where FnResult: FnMut(Result<Option<Self::Item>, Self::Error>) {
        let observer = ResultObserver {
            fn_result: on_next_or_completed_or_error
        };
        self.subscribe(observer)
    }
}

/// A subscription where `drop()` is a no-op.
pub struct UncancellableSubscription;

impl Drop for UncancellableSubscription {
    fn drop(&mut self) { }
}

impl<'i, I> Observable for &'i I where &'i I: IntoIterator {
    type Item = <&'i I as IntoIterator>::Item;
    type Error = ();
    type Subscription = UncancellableSubscription;

    fn subscribe<O>(&mut self, mut observer: O) -> UncancellableSubscription
        where O: Observer<Self::Item, Self::Error> {
        for x in self.into_iter() {
            observer.on_next(x);
        }
        observer.on_completed();
        UncancellableSubscription
    }
}
<commit_msg>Require that obsevable items be Clone<commit_after>// Rx -- Reactive programming for Rust
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

//! Rx, a library for reactive programming in Rust.
//! Inspired by [Reactive Extensions for C#](https://rx.codeplex.com/).
//!
//! TODO: Add intro to observables for people who are unfamiliar with them.
//!
//! TODO: Add examples.

#![warn(missing_docs)]
#![feature(fn_traits, unboxed_closures)]

use observer::{NextObserver, CompletedObserver, ErrorObserver, OptionObserver, ResultObserver};
use std::fmt::Debug;
use std::iter::IntoIterator;

mod observer;

pub use observer::{Observer, BoxedObserver};

/// A stream of values.
///
/// An observable represents a stream of values, much like an iterator,
/// but instead of being “pull-based” like an iterator, it is “push-based”.
/// Multiple observers can subscribe to an observable and when the observable
/// produces a value, all observers get called with this value.
///
/// An observable can be _finite_ or _infinite_. An example of an infinite
/// observable are mouse clicks: you never know if the user is going to click
/// once more. An example of a finite observable are the results of a database
/// query: a database is can hold only finitely many records, so one result is
/// the last one.
///
/// A finite observable can end in two ways:
///
///  * **Completed**: when the observable ends normally.
///    For instance, an observable of database query results
///    will complete after the last result has been produced.
///  * **Failed**: when an error occurred.
///    For instance, an observable of database query results
///    may fail if the connection is lost.
///
/// Failures are fatal: after an observable produces an error, it will not
/// produce any new values. If this is not the desired behavior, you can
/// use an observable of `Result`.
pub trait Observable {
    /// The value produced by the observable.
    type Item: Clone;

    /// The error produced if the observable fails.
    type Error: Clone;

    /// The result of subscribing an observer.
    type Subscription: Drop;

    /// Subscribes an observer and returns the subscription.
    ///
    /// After subscription, `on_next` will be called on the observer for every
    /// value produced. If the observable completes, `on_completed` is called.
    /// If the observable fails with an error, `on_error` is called. It is
    /// guaranteed that no methods will be called on the observer after
    /// `on_completed` or `on_error` have been called.
    ///
    /// _When_ the observer is called is not part of the observable contract,
    /// it depends on the kind of observable. The observer may be called before
    /// `subscribe` returns, or it may be called in the future.
    ///
    /// The returned value represents the subscription. Dropping the subscription
    /// will prevent further calls on the observer.
    fn subscribe<O>(&mut self, observer: O) -> Self::Subscription
        where O: Observer<Self::Item, Self::Error>;

    /// Subscribes a function to handle values produced by the observable.
    ///
    /// For every value produced by the observable, `on_next` is called.
    ///
    /// **This subscription panics if the observable fails with an error.**
    ///
    /// See also [`subscribe()`](#tymethod.subscribe).
    fn subscribe_next<FnNext>(&mut self,
                              on_next: FnNext)
                              -> Self::Subscription
        where Self::Error: Debug, FnNext: FnMut(Self::Item) {
        let observer = NextObserver {
            fn_next: on_next,
        };
        self.subscribe(observer)
    }

    /// Subscribes functions to handle next and completion.
    ///
    /// For every value produced by the observable, `on_next` is called. If the
    /// observable completes, `on_completed` is called. A failure will cause a
    /// panic. After `on_completed` has been called, it is guaranteed that neither
    /// `on_next` nor `on_completed` is called again.
    ///
    /// **This subscription panics if the observable fails with an error.**
    ///
    /// See also [`subscribe()`](#tymethod.subscribe).
    fn subscribe_completed<FnNext, FnCompleted>(&mut self,
                                                on_next: FnNext,
                                                on_completed: FnCompleted)
                                                -> Self::Subscription
        where Self::Error: Debug, FnNext: FnMut(Self::Item), FnCompleted: FnOnce() {
        let observer = CompletedObserver {
            fn_next: on_next,
            fn_completed: on_completed,
        };
        self.subscribe(observer)
    }

    /// Subscribes functions to handle next, completion, and error.
    ///
    /// For every value produced by the observable, `on_next` is called. If the
    /// observable completes, `on_completed` is called. If it fails, `on_error`
    /// is called. After `on_completed` or `on_error` have been called, it is
    /// guaranteed that none of the three functions are called again.
    ///
    /// See also [`subscribe()`](#tymethod.subscribe).
    fn subscribe_error<FnNext, FnCompleted, FnError>(&mut self,
                                                     on_next: FnNext,
                                                     on_completed: FnCompleted,
                                                     on_error: FnError)
                                                     -> Self::Subscription
        where FnNext: FnMut(Self::Item), FnCompleted: FnOnce(), FnError: FnOnce(Self::Error) {
        let observer = ErrorObserver {
            fn_next: on_next,
            fn_completed: on_completed,
            fn_error: on_error,
        };
        self.subscribe(observer)
    }

    /// Subscribes a function that takes an option.
    ///
    /// The function translates into an observer as follows:
    ///
    ///  * `on_next(x)`: calls the functions with `Some(x)`.
    ///  * `on_completed()`: calls the function with `None`.
    ///  * `on_error(error)`: panics.
    ///
    /// After the function has been called with `None`,
    /// it is guaranteed never to be called again.
    ///
    /// **This subscription panics if the observable fails with an error.**
    ///
    /// See also [`subscribe()`](#tymethod.subscribe).
    fn subscribe_option<FnOption>(&mut self,
                                  on_next_or_completed: FnOption)
                                  -> Self::Subscription
        where Self::Error: Debug, FnOption: FnMut(Option<Self::Item>) {
        let observer = OptionObserver {
            fn_option: on_next_or_completed
        };
        self.subscribe(observer)
    }

    /// Subscribes a function that takes a result of an option.
    ///
    /// The function translates into an observer as follows:
    ///
    ///  * `on_next(x)`: calls the function with `Ok(Some(x))`.
    ///  * `on_completed()`: calls the function with `Ok(None)`.
    ///  * `on_error(error)`: calls the function with `Err(error)`.
    ///
    /// After the function has been called with `Ok(None)` or `Err(error)`,
    /// it is guaranteed never to be called again.
    ///
    /// See also [`subscribe()`](#tymethod.subscribe).
    fn subscribe_result<FnResult>(&mut self,
                                  on_next_or_completed_or_error: FnResult)
                                  -> Self::Subscription
        where FnResult: FnMut(Result<Option<Self::Item>, Self::Error>) {
        let observer = ResultObserver {
            fn_result: on_next_or_completed_or_error
        };
        self.subscribe(observer)
    }
}

/// A subscription where `drop()` is a no-op.
pub struct UncancellableSubscription;

impl Drop for UncancellableSubscription {
    fn drop(&mut self) { }
}

impl<'i, I> Observable for &'i I where &'i I: IntoIterator, <&'i I as IntoIterator>::Item: Clone {
    type Item = <&'i I as IntoIterator>::Item;
    type Error = ();
    type Subscription = UncancellableSubscription;

    fn subscribe<O>(&mut self, mut observer: O) -> UncancellableSubscription
        where O: Observer<Self::Item, Self::Error> {
        for x in self.into_iter() {
            observer.on_next(x);
        }
        observer.on_completed();
        UncancellableSubscription
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate apache2;

use apache2::{Request, Status};

apache2_module!(parallax_handler, c_parallax_handler, parallax_module, b"parallax\0");

macro_rules! html_template {() => ("<!doctype html>

      <meta charset='utf-8'>
      <meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'>
      <title>PolyDraw / Parallax</title>
      <meta name='viewport' content='width=device-width, initial-scale=1.0'>

      <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.css'>
      <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Khand:700'>

               S001

               S002

               S003

               S004

               S005

")}

fn parallax_handler(r: &mut Request) -> Result<Status, ()> {
   if try!(r.handler()) != "parallax" {
      return Ok(Status::DECLINED)
   }

   r.set_content_type("text/html");

   try!(r.write(format!(
      html_template!(),
      STYLESHEET,
      SCRIPT
   )));

   Ok(Status::OK)
}

const STYLESHEET: &'static str = "
   body {
      overflow: hidden;

      background-color: #000000;

      font-family: 'Khand', sans-serif;
      font-size: 180px;
      font-weight: 700;
      text-align: center;
      color: white;
   }

   section {
      display: block;
      position: relative;
   }

   .container {
      position: relative;
   }

   #S001 {
      background-color: #ed8c2b;
   }

   #S002 {
      background-color: #cf4a30;
   }

   #S003 {
      background-color: #911146;
   }

   #S004 {
      background-color: #35203b;
   }

   #S005 {
      background-color: #88a825;
   }
";

const SCRIPT: &'static str = "
   var CURRENT_SECTION = 0;
   var SECTION_COUNT = 5;

   var ACCUMULATED_SCROLL = 0;
   var TIMER_ID = null;

   var HEIGHT_RATIO = 4 / 7;

   var TOUCHSTART_Y = null;
   var TOUCHSTART_SECTION = null;

   var easingFunction = jQuery.fn.velocity.Easings.easeInQuad;

   $(document).keydown(function(e) {
      if (e.which == 40) { // Down arrow
         if (CURRENT_SECTION == SECTION_COUNT - 1) return;

         CURRENT_SECTION += 1;

         navigateToCurrentSection();
      }

      if (e.which == 38) { // Up arrow
         if (CURRENT_SECTION == 0) return;

         CURRENT_SECTION -= 1;
         navigateToCurrentSection();
      }
   });

   $(window).resize(function(){
      adjustContainerHeight();
   });

   $(window).mousewheel(function(event) {
      ACCUMULATED_SCROLL += -(event.deltaY * event.deltaFactor);

      processAccumulatedMove();
   });

   $(window).on('touchstart', function(event) {
      event.preventDefault();

      var e = event.originalEvent;
      TOUCHSTART_Y = e.touches[0].pageY;
      TOUCHSTART_SECTION = CURRENT_SECTION;

      console.log(e);
   });

   $(window).on('touchmove', function(event) {
      event.preventDefault();

      var e = event.originalEvent;
      var y = e.touches[0].pageY;

      ACCUMULATED_SCROLL = TOUCHSTART_Y - y;

      processAccumulatedMove();

      if (CURRENT_SECTION != TOUCHSTART_SECTION) {
         TOUCHSTART_Y = y;
         TOUCHSTART_SECTION = CURRENT_SECTION;
      }
   });

   var processAccumulatedMove = function() {
      if ((ACCUMULATED_SCROLL < 0 && CURRENT_SECTION == 0) || (ACCUMULATED_SCROLL > 0 && CURRENT_SECTION == SECTION_COUNT-1)) {
         ACCUMULATED_SCROLL = 0;
         return;
      }

      var switchDistance = $(window).height() * HEIGHT_RATIO;

      if (ACCUMULATED_SCROLL >= switchDistance) {
         ACCUMULATED_SCROLL = 0;
         CURRENT_SECTION += 1;
         navigateToCurrentSection();
      } else if (ACCUMULATED_SCROLL <= -switchDistance) {
         ACCUMULATED_SCROLL = 0;
         CURRENT_SECTION -= 1;
         navigateToCurrentSection();
      } else {
         transitionToAccumulated();

         if (TIMER_ID != null) {
            clearTimeout(TIMER_ID);
            TIMER_ID = null;
         };

         TIMER_ID = setTimeout(function() {
            TIMER_ID = null;
            navigateToCurrentSection(200);
         }, 600);
      }
   }

   var transitionToAccumulated = function() {
      var height = $(window).height();

      var switchDistance = height * HEIGHT_RATIO;

      var normalized = Math.abs(ACCUMULATED_SCROLL / switchDistance);
      var easing_ratio = easingFunction(normalized);

      $('#page-wrapper').velocity('stop').velocity({
         translateY: -(CURRENT_SECTION * height + ACCUMULATED_SCROLL * easing_ratio / 3)
      }, {
         easing: 'linear',
         duration: 100
      });
   }

   var navigateToCurrentSection = function(duration) {
      if (duration === undefined) {
         duration = 300;
      }
      var offset = -CURRENT_SECTION * $(window).height();
      $('#page-wrapper').velocity('stop').velocity({
         translateY: offset
      }, duration);
   }

   var adjustContainerHeight = function() {
      var height = $(window).height();

      $('.container')
         .height(height)
         .css({
            lineHeight: height + 'px'
         });

      navigateToCurrentSection();
   }

   adjustContainerHeight();
";
<commit_msg>Adding the missing javascript includes.<commit_after>#[macro_use]
extern crate apache2;

use apache2::{Request, Status};

apache2_module!(parallax_handler, c_parallax_handler, parallax_module, b"parallax\0");

macro_rules! html_template {() => ("<!doctype html>

      <meta charset='utf-8'>
      <meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'>
      <title>PolyDraw / Parallax</title>
      <meta name='viewport' content='width=device-width, initial-scale=1.0'>

      <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.css'>
      <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Khand:700'>

               S001

               S002

               S003

               S004

               S005

")}

fn parallax_handler(r: &mut Request) -> Result<Status, ()> {
   if try!(r.handler()) != "parallax" {
      return Ok(Status::DECLINED)
   }

   r.set_content_type("text/html");

   try!(r.write(format!(
      html_template!(),
      STYLESHEET,
      SCRIPT
   )));

   Ok(Status::OK)
}

const STYLESHEET: &'static str = "
   body {
      overflow: hidden;

      background-color: #000000;

      font-family: 'Khand', sans-serif;
      font-size: 180px;
      font-weight: 700;
      text-align: center;
      color: white;
   }

   section {
      display: block;
      position: relative;
   }

   .container {
      position: relative;
   }

   #S001 {
      background-color: #ed8c2b;
   }

   #S002 {
      background-color: #cf4a30;
   }

   #S003 {
      background-color: #911146;
   }

   #S004 {
      background-color: #35203b;
   }

   #S005 {
      background-color: #88a825;
   }
";

const SCRIPT: &'static str = "
   var CURRENT_SECTION = 0;
   var SECTION_COUNT = 5;

   var ACCUMULATED_SCROLL = 0;
   var TIMER_ID = null;

   var HEIGHT_RATIO = 4 / 7;

   var TOUCHSTART_Y = null;
   var TOUCHSTART_SECTION = null;

   var easingFunction = jQuery.fn.velocity.Easings.easeInQuad;

   $(document).keydown(function(e) {
      if (e.which == 40) { // Down arrow
         if (CURRENT_SECTION == SECTION_COUNT - 1) return;

         CURRENT_SECTION += 1;

         navigateToCurrentSection();
      }

      if (e.which == 38) { // Up arrow
         if (CURRENT_SECTION == 0) return;

         CURRENT_SECTION -= 1;
         navigateToCurrentSection();
      }
   });

   $(window).resize(function(){
      adjustContainerHeight();
   });

   $(window).mousewheel(function(event) {
      ACCUMULATED_SCROLL += -(event.deltaY * event.deltaFactor);

      processAccumulatedMove();
   });

   $(window).on('touchstart', function(event) {
      event.preventDefault();

      var e = event.originalEvent;
      TOUCHSTART_Y = e.touches[0].pageY;
      TOUCHSTART_SECTION = CURRENT_SECTION;

      console.log(e);
   });

   $(window).on('touchmove', function(event) {
      event.preventDefault();

      var e = event.originalEvent;
      var y = e.touches[0].pageY;

      ACCUMULATED_SCROLL = TOUCHSTART_Y - y;

      processAccumulatedMove();

      if (CURRENT_SECTION != TOUCHSTART_SECTION) {
         TOUCHSTART_Y = y;
         TOUCHSTART_SECTION = CURRENT_SECTION;
      }
   });

   var processAccumulatedMove = function() {
      if ((ACCUMULATED_SCROLL < 0 && CURRENT_SECTION == 0) || (ACCUMULATED_SCROLL > 0 && CURRENT_SECTION == SECTION_COUNT-1)) {
         ACCUMULATED_SCROLL = 0;
         return;
      }

      var switchDistance = $(window).height() * HEIGHT_RATIO;

      if (ACCUMULATED_SCROLL >= switchDistance) {
         ACCUMULATED_SCROLL = 0;
         CURRENT_SECTION += 1;
         navigateToCurrentSection();
      } else if (ACCUMULATED_SCROLL <= -switchDistance) {
         ACCUMULATED_SCROLL = 0;
         CURRENT_SECTION -= 1;
         navigateToCurrentSection();
      } else {
         transitionToAccumulated();

         if (TIMER_ID != null) {
            clearTimeout(TIMER_ID);
            TIMER_ID = null;
         };

         TIMER_ID = setTimeout(function() {
            TIMER_ID = null;
            navigateToCurrentSection(200);
         }, 600);
      }
   }

   var transitionToAccumulated = function() {
      var height = $(window).height();

      var switchDistance = height * HEIGHT_RATIO;

      var normalized = Math.abs(ACCUMULATED_SCROLL / switchDistance);
      var easing_ratio = easingFunction(normalized);

      $('#page-wrapper').velocity('stop').velocity({
         translateY: -(CURRENT_SECTION * height + ACCUMULATED_SCROLL * easing_ratio / 3)
      }, {
         easing: 'linear',
         duration: 100
      });
   }

   var navigateToCurrentSection = function(duration) {
      if (duration === undefined) {
         duration = 300;
      }
      var offset = -CURRENT_SECTION * $(window).height();
      $('#page-wrapper').velocity('stop').velocity({
         translateY: offset
      }, duration);
   }

   var adjustContainerHeight = function() {
      var height = $(window).height();

      $('.container')
         .height(height)
         .css({
            lineHeight: height + 'px'
         });

      navigateToCurrentSection();
   }

   adjustContainerHeight();
";
<|endoftext|>


<commit_before>//! A signal processing framework for making music with rust.
//!
//! `oxcable` is designed with simple but powerful abstractions, with minimal
//! performance loss, while functioning in real-time.
//!
//! `oxcable` seeks to provide the basic building blocks necessary to build
//! digital instruments and effects, and provide the tools to chain these
//! devices together quickly and easily.
//!
//! # Getting started
//!
//! Let's start with a simple example. This script will generate a sine wave at
//! 440Hz, and play it on your computer's speakers or headphones in an infinite
//! loop:
//!
//! ```
//! extern crate oxcable;
//! use oxcable::chain::{DeviceChain, Tick};
//! use oxcable::io::audio::AudioEngine;
//! use oxcable::oscillator::{Oscillator, Sine};
//!
//! fn main() {
//!     let engine = AudioEngine::with_buffer_size(256).unwrap();
//!     let mut chain = DeviceChain::from(
//!         Oscillator::new(Sine).freq(440.0)
//!     ).into(
//!         engine.default_output(1).unwrap()
//!     );
//! # }
//! # // wrap tick_forever() in a function that gets compiled by not run by
//! # //doctest
//! # fn dummy(chain: &mut DeviceChain) {
//!     chain.tick_forever();
//! }
//! ```
//!
//! # Devices
//!
//! Defining an audio device can be done by implenting the
//! [`AudioDevice` trait](types/trait.AudioDevice.html).
//!
//! Let's define a very simple audio device: one that simply passes its input
//! straight to the output. This can be done in just a few lines:
//!
//! ```
//! use oxcable::types::{AudioDevice, Sample, Time};
//!
//! struct IdentityFilter;
//! impl AudioDevice for IdentityFilter {
//!     fn num_inputs(&self) -> usize { 1 }
//!     fn num_outputs(&self) -> usize { 1 }
//!     fn tick(&mut self, _: Time, inputs: &[Sample], outputs: &mut[Sample]) {
//!         outputs[0] = inputs[0];
//!     }
//! }
//! ```
//!
//! Once we've defined a device, it is simple to use the device in isolation.
//! Say I want to test my filter. I can manually call tick a few times to
//! generate outputs:
//!
//! ```
//! # use oxcable::types::{AudioDevice, Sample, Time};
//! # struct IdentityFilter;
//! # impl AudioDevice for IdentityFilter {
//! #     fn num_inputs(&self) -> usize { 1 }
//! #     fn num_outputs(&self) -> usize { 1 }
//! #     fn tick(&mut self, _: Time, inputs: &[Sample], outputs: &mut[Sample]) {
//! #         outputs[0] = inputs[0];
//! #     }
//! # }
//! #
//! let mut input = [0.0];
//! let mut output = [0.0];
//! let mut filter = IdentityFilter;
//!
//! for i in 0..8 {
//!     input[0] = i as f32;
//!     filter.tick(i, &input, &mut output);
//!     assert_eq!(i as f32, output[0]);
//! }
//! ```
//!
//! By adhering to the `AudioDevice` trait, however, this new device will drop
//! straight into generic containers like [`DeviceChain`](chain/index.html) or
//! [`DeviceGraph`](graph/index.html), and into wrappers such as the `Buffered`
//! wrapper:
//!
//! ```
//! # use oxcable::types::{AudioDevice, Sample, Time};
//! # struct IdentityFilter;
//! # impl AudioDevice for IdentityFilter {
//! #     fn num_inputs(&self) -> usize { 1 }
//! #     fn num_outputs(&self) -> usize { 1 }
//! #     fn tick(&mut self, _: Time, inputs: &[Sample], outputs: &mut[Sample]) {
//! #         outputs[0] = inputs[0];
//! #     }
//! # }
//! #
//! use oxcable::wrappers::Buffered;
//! let mut filter = Buffered::from(IdentityFilter);
//!
//! for i in 0..8 {
//!     filter.inputs[0] = i as f32;
//!     filter.tick(i);
//!     assert_eq!(i as f32, filter.outputs[0]);
//! }
//! ```
//!
//! `oxcable` defines many simple devices itself. A list of these devices may be
//! found under [the `AudioDevice`
//! documentation](types/trait.AudioDevice.html#implementors).

extern crate byteorder;
extern crate num;
extern crate portaudio;
extern crate portmidi;
extern crate rand;

pub mod adsr;
pub mod chain;
pub mod delay;
pub mod dynamics;
pub mod filters;
pub mod graph;
pub mod io;
pub mod mixers;
pub mod oscillator;
pub mod reverb;
pub mod tick;
pub mod tremolo;
pub mod types;
pub mod utils;
pub mod voice_array;
pub mod wrappers;
<commit_msg>Add thread safety note to library docs<commit_after>//! A signal processing framework for making music with rust.
//!
//! `oxcable` is designed with simple but powerful abstractions, with minimal
//! performance loss, while functioning in real-time.
//!
//! `oxcable` seeks to provide the basic building blocks necessary to build
//! digital instruments and effects, and provide the tools to chain these
//! devices together quickly and easily.
//!
//! # Getting started
//!
//! Let's start with a simple example. This script will generate a sine wave at
//! 440Hz, and play it on your computer's speakers or headphones in an infinite
//! loop:
//!
//! ```
//! extern crate oxcable;
//! use oxcable::chain::{DeviceChain, Tick};
//! use oxcable::io::audio::AudioEngine;
//! use oxcable::oscillator::{Oscillator, Sine};
//!
//! fn main() {
//!     let engine = AudioEngine::with_buffer_size(256).unwrap();
//!     let mut chain = DeviceChain::from(
//!         Oscillator::new(Sine).freq(440.0)
//!     ).into(
//!         engine.default_output(1).unwrap()
//!     );
//! # }
//! # // wrap tick_forever() in a function that gets compiled by not run by
//! # //doctest
//! # fn dummy(chain: &mut DeviceChain) {
//!     chain.tick_forever();
//! }
//! ```
//!
//! # Devices
//!
//! Defining an audio device can be done by implenting the
//! [`AudioDevice` trait](types/trait.AudioDevice.html).
//!
//! Let's define a very simple audio device: one that simply passes its input
//! straight to the output. This can be done in just a few lines:
//!
//! ```
//! use oxcable::types::{AudioDevice, Sample, Time};
//!
//! struct IdentityFilter;
//! impl AudioDevice for IdentityFilter {
//!     fn num_inputs(&self) -> usize { 1 }
//!     fn num_outputs(&self) -> usize { 1 }
//!     fn tick(&mut self, _: Time, inputs: &[Sample], outputs: &mut[Sample]) {
//!         outputs[0] = inputs[0];
//!     }
//! }
//! ```
//!
//! Once we've defined a device, it is simple to use the device in isolation.
//! Say I want to test my filter. I can manually call tick a few times to
//! generate outputs:
//!
//! ```
//! # use oxcable::types::{AudioDevice, Sample, Time};
//! # struct IdentityFilter;
//! # impl AudioDevice for IdentityFilter {
//! #     fn num_inputs(&self) -> usize { 1 }
//! #     fn num_outputs(&self) -> usize { 1 }
//! #     fn tick(&mut self, _: Time, inputs: &[Sample], outputs: &mut[Sample]) {
//! #         outputs[0] = inputs[0];
//! #     }
//! # }
//! #
//! let mut input = [0.0];
//! let mut output = [0.0];
//! let mut filter = IdentityFilter;
//!
//! for i in 0..8 {
//!     input[0] = i as f32;
//!     filter.tick(i, &input, &mut output);
//!     assert_eq!(i as f32, output[0]);
//! }
//! ```
//!
//! By adhering to the `AudioDevice` trait, however, this new device will drop
//! straight into generic containers like [`DeviceChain`](chain/index.html) or
//! [`DeviceGraph`](graph/index.html), and into wrappers such as the `Buffered`
//! wrapper:
//!
//! ```
//! # use oxcable::types::{AudioDevice, Sample, Time};
//! # struct IdentityFilter;
//! # impl AudioDevice for IdentityFilter {
//! #     fn num_inputs(&self) -> usize { 1 }
//! #     fn num_outputs(&self) -> usize { 1 }
//! #     fn tick(&mut self, _: Time, inputs: &[Sample], outputs: &mut[Sample]) {
//! #         outputs[0] = inputs[0];
//! #     }
//! # }
//! #
//! use oxcable::wrappers::Buffered;
//! let mut filter = Buffered::from(IdentityFilter);
//!
//! for i in 0..8 {
//!     filter.inputs[0] = i as f32;
//!     filter.tick(i);
//!     assert_eq!(i as f32, filter.outputs[0]);
//! }
//! ```
//!
//! `oxcable` defines many simple devices itself. A list of these devices may be
//! found under [the `AudioDevice`
//! documentation](types/trait.AudioDevice.html#implementors).
//!
//! # Thread Safety
//!
//! Unfortunately, `oxcable` is not able to provide `AudioDevice` containers
//! that are `Send`. This is due to a limitation in the `rust-portaudio` crate,
//! in which audio streams are not `Send`. This prohibits binding `AudioDevice`
//! trait objects with `Send`.
//!
//! Therefore, when using generic containers, the signal chain must be
//! initialized in the thread it will eventually process audio.

extern crate byteorder;
extern crate num;
extern crate portaudio;
extern crate portmidi;
extern crate rand;

pub mod adsr;
pub mod chain;
pub mod delay;
pub mod dynamics;
pub mod filters;
pub mod graph;
pub mod io;
pub mod mixers;
pub mod oscillator;
pub mod reverb;
pub mod tick;
pub mod tremolo;
pub mod types;
pub mod utils;
pub mod voice_array;
pub mod wrappers;
<|endoftext|>


<commit_before>use syntax::ast;
use syntax::codemap::{self, DUMMY_SP, Span, respan};
use syntax::ext::base::ExtCtxt;
use syntax::ext::expand;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse::{self, ParseSess};
use syntax::ptr::P;

use expr::ExprBuilder;
use invoke::{Invoke, Identity};

/// A Builder for macro invocations.
///
/// Note that there are no commas added between args, as otherwise
/// that macro invocations that could be expressed would be limited.
/// You will need to add all required symbols with `with_arg` or
/// `with_argss`.
pub struct MacBuilder<F=Identity> {
    callback: F,
    span: Span,
    tokens: Vec<ast::TokenTree>,
    path: Option<ast::Path>,
}

impl MacBuilder {
    pub fn new() -> Self {
        MacBuilder::new_with_callback(Identity)
    }
}

impl<F> MacBuilder<F>
    where F: Invoke<ast::Mac>
{
    pub fn new_with_callback(callback: F) -> Self {
        MacBuilder {
            callback: callback,
            span: DUMMY_SP,
            tokens: vec![],
            path: None,
        }
    }

    pub fn span(mut self, span: Span) -> Self {
        self.span = span;
        self
    }

    pub fn path(mut self, path: ast::Path) -> Self {
        self.path = Some(path);
        self
    }

    pub fn build(self) -> F::Result {
        let mac = ast::Mac_::MacInvocTT(
            self.path.expect("No path set for macro"), self.tokens, 0);
        self.callback.invoke(respan(self.span, mac))
    }

    pub fn with_args<I, T>(self, iter: I) -> Self
        where I: IntoIterator<Item=T>, T: ToTokens
    {
        iter.into_iter().fold(self, |self_, expr| self_.with_arg(expr))
    }

    pub fn with_arg<T>(mut self, expr: T) -> Self
        where T: ToTokens
    {
        let parse_sess = parse::new_parse_sess();
        let cx = make_ext_ctxt(&parse_sess);
        let tokens = expr.to_tokens(&cx);
        assert!(tokens.len() == 1);
        self.tokens.push(tokens[0].clone());
        self
    }

    pub fn expr(self) -> ExprBuilder<Self> {
        ExprBuilder::new_with_callback(self)
    }

}

impl<F> Invoke<P<ast::Expr>> for MacBuilder<F>
    where F: Invoke<ast::Mac>,
{
    type Result = Self;

    fn invoke(self, expr: P<ast::Expr>) -> Self {
        self.with_arg(expr)
    }
}

fn make_ext_ctxt(sess: &ParseSess) -> ExtCtxt {
    let info = codemap::ExpnInfo {
        call_site: codemap::DUMMY_SP,
        callee: codemap::NameAndSpan {
            name: "test".to_string(),
            format: codemap::MacroAttribute,
            allow_internal_unstable: false,
            span: None
        }
    };

    let cfg = vec![];
    let ecfg = expand::ExpansionConfig {
        crate_name: String::new(),
        features: None,
        recursion_limit: 64,
        trace_mac: false,
    };

    let mut cx = ExtCtxt::new(&sess, cfg, ecfg);
    cx.bt_push(info);

    cx
}
<commit_msg>Simplify constructing an ExpansionConfig.<commit_after>use syntax::ast;
use syntax::codemap::{self, DUMMY_SP, Span, respan};
use syntax::ext::base::ExtCtxt;
use syntax::ext::expand;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse::{self, ParseSess};
use syntax::ptr::P;

use expr::ExprBuilder;
use invoke::{Invoke, Identity};

/// A Builder for macro invocations.
///
/// Note that there are no commas added between args, as otherwise
/// that macro invocations that could be expressed would be limited.
/// You will need to add all required symbols with `with_arg` or
/// `with_argss`.
pub struct MacBuilder<F=Identity> {
    callback: F,
    span: Span,
    tokens: Vec<ast::TokenTree>,
    path: Option<ast::Path>,
}

impl MacBuilder {
    pub fn new() -> Self {
        MacBuilder::new_with_callback(Identity)
    }
}

impl<F> MacBuilder<F>
    where F: Invoke<ast::Mac>
{
    pub fn new_with_callback(callback: F) -> Self {
        MacBuilder {
            callback: callback,
            span: DUMMY_SP,
            tokens: vec![],
            path: None,
        }
    }

    pub fn span(mut self, span: Span) -> Self {
        self.span = span;
        self
    }

    pub fn path(mut self, path: ast::Path) -> Self {
        self.path = Some(path);
        self
    }

    pub fn build(self) -> F::Result {
        let mac = ast::Mac_::MacInvocTT(
            self.path.expect("No path set for macro"), self.tokens, 0);
        self.callback.invoke(respan(self.span, mac))
    }

    pub fn with_args<I, T>(self, iter: I) -> Self
        where I: IntoIterator<Item=T>, T: ToTokens
    {
        iter.into_iter().fold(self, |self_, expr| self_.with_arg(expr))
    }

    pub fn with_arg<T>(mut self, expr: T) -> Self
        where T: ToTokens
    {
        let parse_sess = parse::new_parse_sess();
        let cx = make_ext_ctxt(&parse_sess);
        let tokens = expr.to_tokens(&cx);
        assert!(tokens.len() == 1);
        self.tokens.push(tokens[0].clone());
        self
    }

    pub fn expr(self) -> ExprBuilder<Self> {
        ExprBuilder::new_with_callback(self)
    }

}

impl<F> Invoke<P<ast::Expr>> for MacBuilder<F>
    where F: Invoke<ast::Mac>,
{
    type Result = Self;

    fn invoke(self, expr: P<ast::Expr>) -> Self {
        self.with_arg(expr)
    }
}

fn make_ext_ctxt(sess: &ParseSess) -> ExtCtxt {
    let info = codemap::ExpnInfo {
        call_site: codemap::DUMMY_SP,
        callee: codemap::NameAndSpan {
            name: "test".to_string(),
            format: codemap::MacroAttribute,
            allow_internal_unstable: false,
            span: None
        }
    };

    let cfg = vec![];
    let ecfg = expand::ExpansionConfig::default(String::new());

    let mut cx = ExtCtxt::new(&sess, cfg, ecfg);
    cx.bt_push(info);

    cx
}
<|endoftext|>