<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::StorageBinding;
use dom::bindings::codegen::Bindings::StorageBinding::StorageMethods;
use dom::bindings::error::{Error, ErrorResult};
use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{Root, RootedReference};
use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
use dom::event::{Event, EventBubbles, EventCancelable};
use dom::storageevent::StorageEvent;
use dom::urlhelper::UrlHelper;
use ipc_channel::ipc;
use net_traits::storage_thread::{StorageThread, StorageThreadMsg, StorageType};
use page::IterablePage;
use script_runtime::ScriptChan;
use script_thread::{MainThreadRunnable, MainThreadScriptChan, ScriptThread};
use task_source::dom_manipulation::DOMManipulationTask;
use url::Url;
use util::str::DOMString;

#[dom_struct]
pub struct Storage {
    reflector_: Reflector,
    storage_type: StorageType
}

impl Storage {
    fn new_inherited(storage_type: StorageType) -> Storage {
        Storage {
            reflector_: Reflector::new(),
            storage_type: storage_type
        }
    }

    pub fn new(global: &GlobalRef, storage_type: StorageType) -> Root<Storage> {
        reflect_dom_object(box Storage::new_inherited(storage_type), *global, StorageBinding::Wrap)
    }

    fn get_url(&self) -> Url {
        let global_root = self.global();
        let global_ref = global_root.r();
        global_ref.get_url()
    }

    fn get_storage_thread(&self) -> StorageThread {
        let global_root = self.global();
        let global_ref = global_root.r();
        global_ref.as_window().storage_thread()
    }

}

impl StorageMethods for Storage {
    // https://html.spec.whatwg.org/multipage/#dom-storage-length
    fn Length(&self) -> u32 {
        let (sender, receiver) = ipc::channel().unwrap();

        self.get_storage_thread().send(StorageThreadMsg::Length(sender, self.get_url(), self.storage_type)).unwrap();
        receiver.recv().unwrap() as u32
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-key
    fn Key(&self, index: u32) -> Option<DOMString> {
        let (sender, receiver) = ipc::channel().unwrap();

        self.get_storage_thread()
            .send(StorageThreadMsg::Key(sender, self.get_url(), self.storage_type, index))
            .unwrap();
        receiver.recv().unwrap().map(DOMString::from)
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-getitem
    fn GetItem(&self, name: DOMString) -> Option<DOMString> {
        let (sender, receiver) = ipc::channel().unwrap();
        let name = String::from(name);

        let msg = StorageThreadMsg::GetItem(sender, self.get_url(), self.storage_type, name);
        self.get_storage_thread().send(msg).unwrap();
        receiver.recv().unwrap().map(DOMString::from)
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-setitem
    fn SetItem(&self, name: DOMString, value: DOMString) -> ErrorResult {
        let (sender, receiver) = ipc::channel().unwrap();
        let name = String::from(name);
        let value = String::from(value);

        let msg = StorageThreadMsg::SetItem(sender, self.get_url(), self.storage_type, name.clone(), value.clone());
        self.get_storage_thread().send(msg).unwrap();
        match receiver.recv().unwrap() {
            Err(_) => Err(Error::QuotaExceeded),
            Ok((changed, old_value)) => {
              if changed {
                  self.broadcast_change_notification(Some(name), old_value, Some(value));
              }
              Ok(())
            }
        }
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-removeitem
    fn RemoveItem(&self, name: DOMString) {
        let (sender, receiver) = ipc::channel().unwrap();
        let name = String::from(name);

        let msg = StorageThreadMsg::RemoveItem(sender, self.get_url(), self.storage_type, name.clone());
        self.get_storage_thread().send(msg).unwrap();
        if let Some(old_value) = receiver.recv().unwrap() {
            self.broadcast_change_notification(Some(name), Some(old_value), None);
        }
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-clear
    fn Clear(&self) {
        let (sender, receiver) = ipc::channel().unwrap();

        self.get_storage_thread().send(StorageThreadMsg::Clear(sender, self.get_url(), self.storage_type)).unwrap();
        if receiver.recv().unwrap() {
            self.broadcast_change_notification(None, None, None);
        }
    }

    // https://html.spec.whatwg.org/multipage/#the-storage-interface:supported-property-names
    fn SupportedPropertyNames(&self) -> Vec<DOMString> {
        let (sender, receiver) = ipc::channel().unwrap();

        self.get_storage_thread().send(StorageThreadMsg::Keys(sender, self.get_url(), self.storage_type)).unwrap();
        receiver.recv().unwrap().iter().cloned().map(DOMString::from).collect() // FIXME: inefficient?
    }

    // check-tidy: no specs after this line
    fn NamedGetter(&self, name: DOMString, found: &mut bool) -> Option<DOMString> {
        let item = self.GetItem(name);
        *found = item.is_some();
        item
    }

    fn NamedSetter(&self, name: DOMString, value: DOMString) -> ErrorResult {
        self.SetItem(name, value)
    }

    fn NamedDeleter(&self, name: DOMString) {
        self.RemoveItem(name);
    }
}

impl Storage {
    /// https://html.spec.whatwg.org/multipage/#send-a-storage-notification
    fn broadcast_change_notification(&self, key: Option<String>, old_value: Option<String>,
                                     new_value: Option<String>) {
        let global_root = self.global();
        let global_ref = global_root.r();
        let task_source = global_ref.as_window().dom_manipulation_task_source();
        let chan = MainThreadScriptChan(global_ref.as_window().main_thread_script_chan().clone()).clone();
        let trusted_storage = Trusted::new(self, chan);
        task_source.queue(DOMManipulationTask::SendStorageNotification(
            box StorageEventRunnable::new(trusted_storage, key, old_value, new_value))).unwrap();
    }
}

pub struct StorageEventRunnable {
    element: Trusted<Storage>,
    key: Option<String>,
    old_value: Option<String>,
    new_value: Option<String>
}

impl StorageEventRunnable {
    fn new(storage: Trusted<Storage>, key: Option<String>, old_value: Option<String>,
           new_value: Option<String>) -> StorageEventRunnable {
        StorageEventRunnable { element: storage, key: key, old_value: old_value, new_value: new_value }
    }
}

impl MainThreadRunnable for StorageEventRunnable {
    fn handler(self: Box<StorageEventRunnable>, script_thread: &ScriptThread) {
        let this = *self;
        let storage_root = this.element.root();
        let storage = storage_root.r();
        let global_root = storage.global();
        let global_ref = global_root.r();
        let ev_window = global_ref.as_window();
        let ev_url = storage.get_url();

        let storage_event = StorageEvent::new(
            global_ref,
            atom!("storage"),
            EventBubbles::DoesNotBubble, EventCancelable::NotCancelable,
            this.key.map(DOMString::from), this.old_value.map(DOMString::from), this.new_value.map(DOMString::from),
            DOMString::from(ev_url.to_string()),
            Some(storage)
        );

        let root_page = script_thread.root_page();
        for it_page in root_page.iter() {
            let it_window_root = it_page.window();
            let it_window = it_window_root.r();
            assert!(UrlHelper::SameOrigin(&ev_url, &it_window.get_url()));
            // TODO: Such a Document object is not necessarily fully active, but events fired on such
            // objects are ignored by the event loop until the Document becomes fully active again.
            if ev_window.pipeline() != it_window.pipeline() {
                storage_event.upcast::<Event>().fire(it_window.upcast());
            }
        }
    }
}
<commit_msg>Auto merge of #10799 - frewsxcv:no-clone, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::StorageBinding;
use dom::bindings::codegen::Bindings::StorageBinding::StorageMethods;
use dom::bindings::error::{Error, ErrorResult};
use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{Root, RootedReference};
use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
use dom::event::{Event, EventBubbles, EventCancelable};
use dom::storageevent::StorageEvent;
use dom::urlhelper::UrlHelper;
use ipc_channel::ipc;
use net_traits::storage_thread::{StorageThread, StorageThreadMsg, StorageType};
use page::IterablePage;
use script_runtime::ScriptChan;
use script_thread::{MainThreadRunnable, MainThreadScriptChan, ScriptThread};
use task_source::dom_manipulation::DOMManipulationTask;
use url::Url;
use util::str::DOMString;

#[dom_struct]
pub struct Storage {
    reflector_: Reflector,
    storage_type: StorageType
}

impl Storage {
    fn new_inherited(storage_type: StorageType) -> Storage {
        Storage {
            reflector_: Reflector::new(),
            storage_type: storage_type
        }
    }

    pub fn new(global: &GlobalRef, storage_type: StorageType) -> Root<Storage> {
        reflect_dom_object(box Storage::new_inherited(storage_type), *global, StorageBinding::Wrap)
    }

    fn get_url(&self) -> Url {
        let global_root = self.global();
        let global_ref = global_root.r();
        global_ref.get_url()
    }

    fn get_storage_thread(&self) -> StorageThread {
        let global_root = self.global();
        let global_ref = global_root.r();
        global_ref.as_window().storage_thread()
    }

}

impl StorageMethods for Storage {
    // https://html.spec.whatwg.org/multipage/#dom-storage-length
    fn Length(&self) -> u32 {
        let (sender, receiver) = ipc::channel().unwrap();

        self.get_storage_thread().send(StorageThreadMsg::Length(sender, self.get_url(), self.storage_type)).unwrap();
        receiver.recv().unwrap() as u32
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-key
    fn Key(&self, index: u32) -> Option<DOMString> {
        let (sender, receiver) = ipc::channel().unwrap();

        self.get_storage_thread()
            .send(StorageThreadMsg::Key(sender, self.get_url(), self.storage_type, index))
            .unwrap();
        receiver.recv().unwrap().map(DOMString::from)
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-getitem
    fn GetItem(&self, name: DOMString) -> Option<DOMString> {
        let (sender, receiver) = ipc::channel().unwrap();
        let name = String::from(name);

        let msg = StorageThreadMsg::GetItem(sender, self.get_url(), self.storage_type, name);
        self.get_storage_thread().send(msg).unwrap();
        receiver.recv().unwrap().map(DOMString::from)
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-setitem
    fn SetItem(&self, name: DOMString, value: DOMString) -> ErrorResult {
        let (sender, receiver) = ipc::channel().unwrap();
        let name = String::from(name);
        let value = String::from(value);

        let msg = StorageThreadMsg::SetItem(sender, self.get_url(), self.storage_type, name.clone(), value.clone());
        self.get_storage_thread().send(msg).unwrap();
        match receiver.recv().unwrap() {
            Err(_) => Err(Error::QuotaExceeded),
            Ok((changed, old_value)) => {
              if changed {
                  self.broadcast_change_notification(Some(name), old_value, Some(value));
              }
              Ok(())
            }
        }
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-removeitem
    fn RemoveItem(&self, name: DOMString) {
        let (sender, receiver) = ipc::channel().unwrap();
        let name = String::from(name);

        let msg = StorageThreadMsg::RemoveItem(sender, self.get_url(), self.storage_type, name.clone());
        self.get_storage_thread().send(msg).unwrap();
        if let Some(old_value) = receiver.recv().unwrap() {
            self.broadcast_change_notification(Some(name), Some(old_value), None);
        }
    }

    // https://html.spec.whatwg.org/multipage/#dom-storage-clear
    fn Clear(&self) {
        let (sender, receiver) = ipc::channel().unwrap();

        self.get_storage_thread().send(StorageThreadMsg::Clear(sender, self.get_url(), self.storage_type)).unwrap();
        if receiver.recv().unwrap() {
            self.broadcast_change_notification(None, None, None);
        }
    }

    // https://html.spec.whatwg.org/multipage/#the-storage-interface:supported-property-names
    fn SupportedPropertyNames(&self) -> Vec<DOMString> {
        let (sender, receiver) = ipc::channel().unwrap();

        self.get_storage_thread().send(StorageThreadMsg::Keys(sender, self.get_url(), self.storage_type)).unwrap();
        receiver.recv()
                .unwrap()
                .into_iter()
                .map(DOMString::from)
                .collect()
    }

    // check-tidy: no specs after this line
    fn NamedGetter(&self, name: DOMString, found: &mut bool) -> Option<DOMString> {
        let item = self.GetItem(name);
        *found = item.is_some();
        item
    }

    fn NamedSetter(&self, name: DOMString, value: DOMString) -> ErrorResult {
        self.SetItem(name, value)
    }

    fn NamedDeleter(&self, name: DOMString) {
        self.RemoveItem(name);
    }
}

impl Storage {
    /// https://html.spec.whatwg.org/multipage/#send-a-storage-notification
    fn broadcast_change_notification(&self, key: Option<String>, old_value: Option<String>,
                                     new_value: Option<String>) {
        let global_root = self.global();
        let global_ref = global_root.r();
        let task_source = global_ref.as_window().dom_manipulation_task_source();
        let chan = MainThreadScriptChan(global_ref.as_window().main_thread_script_chan().clone()).clone();
        let trusted_storage = Trusted::new(self, chan);
        task_source.queue(DOMManipulationTask::SendStorageNotification(
            box StorageEventRunnable::new(trusted_storage, key, old_value, new_value))).unwrap();
    }
}

pub struct StorageEventRunnable {
    element: Trusted<Storage>,
    key: Option<String>,
    old_value: Option<String>,
    new_value: Option<String>
}

impl StorageEventRunnable {
    fn new(storage: Trusted<Storage>, key: Option<String>, old_value: Option<String>,
           new_value: Option<String>) -> StorageEventRunnable {
        StorageEventRunnable { element: storage, key: key, old_value: old_value, new_value: new_value }
    }
}

impl MainThreadRunnable for StorageEventRunnable {
    fn handler(self: Box<StorageEventRunnable>, script_thread: &ScriptThread) {
        let this = *self;
        let storage_root = this.element.root();
        let storage = storage_root.r();
        let global_root = storage.global();
        let global_ref = global_root.r();
        let ev_window = global_ref.as_window();
        let ev_url = storage.get_url();

        let storage_event = StorageEvent::new(
            global_ref,
            atom!("storage"),
            EventBubbles::DoesNotBubble, EventCancelable::NotCancelable,
            this.key.map(DOMString::from), this.old_value.map(DOMString::from), this.new_value.map(DOMString::from),
            DOMString::from(ev_url.to_string()),
            Some(storage)
        );

        let root_page = script_thread.root_page();
        for it_page in root_page.iter() {
            let it_window_root = it_page.window();
            let it_window = it_window_root.r();
            assert!(UrlHelper::SameOrigin(&ev_url, &it_window.get_url()));
            // TODO: Such a Document object is not necessarily fully active, but events fired on such
            // objects are ignored by the event loop until the Document becomes fully active again.
            if ev_window.pipeline() != it_window.pipeline() {
                storage_event.upcast::<Event>().fire(it_window.upcast());
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::path;
use command_handler::CommandResult;

fn change_directory(path: &path::PathBuf) -> i32 {
    match env::set_current_dir(path) {
        Err(err) => {println!("Error : {}, {:?}", err, path); return 1},
        Ok(_) => {return 0}
    }
}

fn build_new_path(command_path: &str) -> Option<path::PathBuf> {
    let mut desired_path = path::PathBuf::new();
    let user_path = path::PathBuf::from(command_path);
    if user_path.is_relative() {
        let current_path = env::current_dir();
        match current_path {
            Ok(p) => {
                desired_path.push(p);
                desired_path.push(user_path);
            },
            Err(e) => {
                println!("Error : {}", e);
                return None;
            }
        }
    } else {
        desired_path.push(user_path);
    }
    return Some(desired_path)
}

pub fn cd (command_vector: &Vec<String> ) -> CommandResult {
    if command_vector.len() == 2 {
        match build_new_path(&command_vector[1]) {
            Some(n) => return CommandResult { child: None, status: change_directory(&n) },
            None => return CommandResult { child: None, status: 1 }
        }
    } else if command_vector.len() == 1 {
        match env::home_dir() {
            Some(n) => CommandResult { child: None, status: change_directory(&n) },
            None => {
                println!("No known home directory");
                return CommandResult { child: None, status: 1 }
            }
        }
    } else {
        println!("Error : Invalid path");
        return CommandResult { child: None, status: 1 }
    }
}
<commit_msg>changed cd to use home_dir from the dirs crate<commit_after>extern crate dirs;

use std::env;
use std::path;
use command_handler::CommandResult;

fn change_directory(path: &path::PathBuf) -> i32 {
    match env::set_current_dir(path) {
        Err(err) => {println!("Error : {}, {:?}", err, path); return 1},
        Ok(_) => {return 0}
    }
}

fn build_new_path(command_path: &str) -> Option<path::PathBuf> {
    let mut desired_path = path::PathBuf::new();
    let user_path = path::PathBuf::from(command_path);
    if user_path.is_relative() {
        let current_path = env::current_dir();
        match current_path {
            Ok(p) => {
                desired_path.push(p);
                desired_path.push(user_path);
            },
            Err(e) => {
                println!("Error : {}", e);
                return None;
            }
        }
    } else {
        desired_path.push(user_path);
    }
    return Some(desired_path)
}

pub fn cd (command_vector: &Vec<String> ) -> CommandResult {
    if command_vector.len() == 2 {
        match build_new_path(&command_vector[1]) {
            Some(n) => return CommandResult { child: None, status: change_directory(&n) },
            None => return CommandResult { child: None, status: 1 }
        }
    } else if command_vector.len() == 1 {
        match dirs::home_dir() {
            Some(n) => CommandResult { child: None, status: change_directory(&n) },
            None => {
                println!("No known home directory");
                return CommandResult { child: None, status: 1 }
            }
        }
    } else {
        println!("Error : Invalid path");
        return CommandResult { child: None, status: 1 }
    }
}
<|endoftext|>


<commit_before>//! jsonrpc io
use std::sync::Arc;
use std::sync::mpsc;
use std::collections::HashMap;
use serde_json;

use control::{Ready, ResponseHandler, Handler, Data, Subscription};
use commander::{MethodCommand, SyncMethod, SyncMethodCommand, NotificationCommand, SubscriptionCommand};
use request_handler::RequestHandler;
use params::Params;
use id::Id;
use version::Version;
use request::Request;
use response::{Response, Failure};
use error::{Error, ErrorCode};
use super::Value;

struct DelegateMethod<T, F> where
	F: Fn(&T, Params) -> Data,
	F: Send + Sync,
	T: Send + Sync {
	delegate: Arc<T>,
	closure: F,
}

impl<T, F> MethodCommand for DelegateMethod<T, F> where
	F: Fn(&T, Params) -> Data,
	F: Send + Sync,
	T: Send + Sync {
	fn execute(&self, params: Params, ready: Ready) {
		let closure = &self.closure;
		ready.ready(closure(&self.delegate, params))
	}
}

struct DelegateAsyncMethod<T, F> where
	F: Fn(&T, Params, Ready),
	F: Send + Sync,
	T: Send + Sync {
	delegate: Arc<T>,
	closure: F,
}

impl<T, F> MethodCommand for DelegateAsyncMethod<T, F> where
	F: Fn(&T, Params, Ready),
	F: Send + Sync,
	T: Send + Sync {
	fn execute(&self, params: Params, ready: Ready) {
		let closure = &self.closure;
		closure(&self.delegate, params, ready)
	}
}

struct DelegateNotification<T, F> where
	F: Fn(&T, Params),
	F: Send + Sync,
	T: Send + Sync {
	delegate: Arc<T>,
	closure: F,
}

impl<T, F> NotificationCommand for DelegateNotification<T, F> where
	F: Fn(&T, Params),
	F: Send + Sync,
	T: Send + Sync {
	fn execute(&self, params: Params) {
		let closure = &self.closure;
		closure(&self.delegate, params)
	}
}

struct DelegateSubscription<T, F> where
	F: Fn(&T, Subscription),
	F: Send + Sync,
	T: Send + Sync {
	delegate: Arc<T>,
	closure: F,
}

impl<T, F> SubscriptionCommand for DelegateSubscription<T, F> where
	F: Fn(&T, Subscription),
	F: Send + Sync,
	T: Send + Sync {
	fn execute(&self, subscription: Subscription) {
		let closure = &self.closure;
		closure(&self.delegate, subscription)
	}
}

/// A set of RPC methods and notifications tied to single `delegate` struct.
pub struct IoDelegate<T> where T: Send + Sync + 'static {
	delegate: Arc<T>,
	methods: HashMap<String, Box<MethodCommand>>,
	notifications: HashMap<String, Box<NotificationCommand>>,
	subscriptions: HashMap<(String, String), Box<SubscriptionCommand>>,
}

impl<T> IoDelegate<T> where T: Send + Sync + 'static {
	/// Creates new `IoDelegate`
	pub fn new(delegate: Arc<T>) -> Self {
		IoDelegate {
			delegate: delegate,
			methods: HashMap::new(),
			notifications: HashMap::new(),
			subscriptions: HashMap::new(),
		}
	}

	/// Add new supported method
	pub fn add_method<F>(&mut self, name: &str, closure: F) where F: Fn(&T, Params) -> Result<Value, Error> + Send + Sync + 'static {
		let delegate = self.delegate.clone();
		self.methods.insert(name.to_owned(), Box::new(DelegateMethod {
			delegate: delegate,
			closure: closure
		}));
	}

	/// Add new supported asynchronous method
	pub fn add_async_method<F>(&mut self, name: &str, closure: F) where F: Fn(&T, Params, Ready) + Send + Sync + 'static {
		let delegate = self.delegate.clone();
		self.methods.insert(name.to_owned(), Box::new(DelegateAsyncMethod {
			delegate: delegate,
			closure: closure
		}));
	}

	/// Add new supported subscription
	pub fn add_subscription<F>(&mut self, subscribe: &str, unsubscribe: &str, closure: F) where F: Fn(&T, Subscription) + Send + Sync + 'static {
		let delegate = self.delegate.clone();
		self.subscriptions.insert((subscribe.into(), unsubscribe.into()), Box::new(DelegateSubscription {
			delegate: delegate,
			closure: closure,
		}));
	}

	/// Add new supported notification
	pub fn add_notification<F>(&mut self, name: &str, closure: F) where F: Fn(&T, Params) + Send + Sync + 'static {
		let delegate = self.delegate.clone();
		self.notifications.insert(name.to_owned(), Box::new(DelegateNotification {
			delegate: delegate,
			closure: closure
		}));
	}
}

/// Should be used to handle jsonrpc io.
///
/// ```rust
/// extern crate jsonrpc_core;
/// use jsonrpc_core::*;
///
/// fn main() {
/// 	let io = IoHandler::new();
/// 	struct SayHello;
///
/// 	// Implement `SyncMethodCommand` or `AsyncMethodCommand`
/// 	impl SyncMethodCommand for SayHello {
/// 		fn execute(&self, _params: Params) -> Result<Value, Error>  {
/// 			Ok(Value::String("hello".to_string()))
/// 		}
/// 	}
///
/// 	io.add_method("say_hello", SayHello);
/// 	// Or just use closures
/// 	io.add_async_method("say_hello_async", |_params: Params, ready: Ready| {
///			ready.ready(Ok(Value::String("hello".to_string())))
/// 	});
///
/// 	let request1 = r#"{"jsonrpc": "2.0", "method": "say_hello", "params": [42, 23], "id": 1}"#;
/// 	let request2 = r#"{"jsonrpc": "2.0", "method": "say_hello_async", "params": [42, 23], "id": 1}"#;
/// 	let response = r#"{"jsonrpc":"2.0","result":"hello","id":1}"#;
///
/// 	assert_eq!(io.handle_request_sync(request1), Some(response.to_string()));
/// 	assert_eq!(io.handle_request_sync(request2), Some(response.to_string()));
/// }
/// ```
pub struct IoHandler {
	request_handler: RequestHandler
}

fn read_request(request_str: &str) -> Result<Request, Error> {
	serde_json::from_str(request_str).map_err(|_| Error::new(ErrorCode::ParseError))
}

fn write_response(response: Response) -> String {
	// this should never fail
	serde_json::to_string(&response).unwrap()
}

impl IoHandler {
	/// Creates new `IoHandler`
	pub fn new() -> Self {
		IoHandler {
			request_handler: RequestHandler::new()
		}
	}

	/// Add supported method
	pub fn add_method<C>(&self, name: &str, command: C) where C: SyncMethodCommand + 'static {
		self.request_handler.add_method(name.into(), SyncMethod {
			command: command
		})
	}

	/// Add supported asynchronous method
	pub fn add_async_method<C>(&self, name: &str, command: C) where C: MethodCommand + 'static {
		self.request_handler.add_method(name.into(), command)
	}

	/// Add supported notification
	pub fn add_notification<C>(&self, name: &str, command: C) where C: NotificationCommand + 'static {
		self.request_handler.add_notification(name.into(), command)
	}

	/// Add supported subscription
	pub fn add_subscription<C>(&self, subscribe: &str, unsubscribe: &str, command: C) where C: SubscriptionCommand + 'static {
		self.request_handler.add_subscription(subscribe.into(), unsubscribe.into(), command);
	}

	/// Add delegate with supported methods.
	pub fn add_delegate<D>(&self, delegate: IoDelegate<D>) where D: Send + Sync {
		self.request_handler.add_methods(delegate.methods);
		self.request_handler.add_notifications(delegate.notifications);
		self.request_handler.add_subscriptions(delegate.subscriptions);
	}

	/// Handle given request synchronously - will block until response is available.
	/// If you have any asynchronous methods in your RPC it is much wiser to use
	/// `handle_request` instead and deal with asynchronous requests in a non-blocking fashion.
	pub fn handle_request_sync(&self, request_str: &str) -> Option<String> {
		let (tx, rx) = mpsc::channel();
		self.handle_request(request_str, move |response: Option<String>| {
			tx.send(response).expect("Receiver is never dropped.");
		});
		// Wait for response.
		rx.recv().expect("Transmitting end is never dropped.")
	}

	/// Handle given request asynchronously.
	pub fn handle_request<H: ResponseHandler<Option<String>> + 'static>(&self, request_str: &str, response_handler: H) {
		trace!(target: "rpc", "Request: {}", request_str);

		let handler = Handler::new(response_handler, move |response: Option<Response>| {
			let response = response.map(write_response);
			debug!(target: "rpc", "Response: {:?}", response);
			response
		});

		let request = read_request(request_str);
		match request {
			Ok(request) => self.request_handler.handle_request(request, handler, None),
			Err(error) => handler.send(Some(Response::from(Failure {
				id: Id::Null,
				jsonrpc: Version::V2,
				error: error
			}))),
		}
	}
}

#[cfg(test)]
mod tests {
	use std::time::Duration;
	use std::thread;
	use super::super::*;

	#[test]
	fn test_io_handler() {
		let io = IoHandler::new();

		struct SayHello;
		impl SyncMethodCommand for SayHello {
			fn execute(&self, _params: Params) -> Result<Value, Error> {
				Ok(Value::String("hello".to_string()))
			}
		}

		io.add_method("say_hello", SayHello);

		let request = r#"{"jsonrpc": "2.0", "method": "say_hello", "params": [42, 23], "id": 1}"#;
		let response = r#"{"jsonrpc":"2.0","result":"hello","id":1}"#;

		assert_eq!(io.handle_request_sync(request), Some(response.to_string()));
	}

	#[test]
	fn test_async_io_handler() {
		let io = IoHandler::new();

		struct SayHelloAsync;
		impl MethodCommand for SayHelloAsync {
			fn execute(&self, _params: Params, ready: Ready) {
				ready.ready(Ok(Value::String("hello".to_string())))
			}
		}

		io.add_async_method("say_hello", SayHelloAsync);

		let request = r#"{"jsonrpc": "2.0", "method": "say_hello", "params": [42, 23], "id": 1}"#;
		let response = r#"{"jsonrpc":"2.0","result":"hello","id":1}"#;

		assert_eq!(io.handle_request_sync(request), Some(response.to_string()));
	}

	#[test]
	fn test_async_io_handler_thread() {
		let io = IoHandler::new();

		struct SayHelloAsync;
		impl MethodCommand for SayHelloAsync {
			fn execute(&self, _params: Params, ready: Ready) {
				thread::spawn(|| {
					thread::sleep(Duration::from_secs(1));
					ready.ready(Ok(Value::String("hello".to_string())))
				});
			}
		}

		io.add_async_method("say_hello", SayHelloAsync);

		let request = r#"{"jsonrpc": "2.0", "method": "say_hello", "params": [42, 23], "id": 1}"#;
		let response = r#"{"jsonrpc":"2.0","result":"hello","id":1}"#;

		assert_eq!(io.handle_request_sync(request), Some(response.to_string()));
	}

}
<commit_msg>Session support<commit_after>//! jsonrpc io
use std::sync::Arc;
use std::sync::mpsc;
use std::collections::HashMap;
use serde_json;

use control::{Ready, ResponseHandler, Handler, Data, Subscription, Session};
use commander::{MethodCommand, SyncMethod, SyncMethodCommand, NotificationCommand, SubscriptionCommand};
use request_handler::RequestHandler;
use params::Params;
use id::Id;
use version::Version;
use request::Request;
use response::{Response, Failure};
use error::{Error, ErrorCode};
use super::Value;

struct DelegateMethod<T, F> where
	F: Fn(&T, Params) -> Data,
	F: Send + Sync,
	T: Send + Sync {
	delegate: Arc<T>,
	closure: F,
}

impl<T, F> MethodCommand for DelegateMethod<T, F> where
	F: Fn(&T, Params) -> Data,
	F: Send + Sync,
	T: Send + Sync {
	fn execute(&self, params: Params, ready: Ready) {
		let closure = &self.closure;
		ready.ready(closure(&self.delegate, params))
	}
}

struct DelegateAsyncMethod<T, F> where
	F: Fn(&T, Params, Ready),
	F: Send + Sync,
	T: Send + Sync {
	delegate: Arc<T>,
	closure: F,
}

impl<T, F> MethodCommand for DelegateAsyncMethod<T, F> where
	F: Fn(&T, Params, Ready),
	F: Send + Sync,
	T: Send + Sync {
	fn execute(&self, params: Params, ready: Ready) {
		let closure = &self.closure;
		closure(&self.delegate, params, ready)
	}
}

struct DelegateNotification<T, F> where
	F: Fn(&T, Params),
	F: Send + Sync,
	T: Send + Sync {
	delegate: Arc<T>,
	closure: F,
}

impl<T, F> NotificationCommand for DelegateNotification<T, F> where
	F: Fn(&T, Params),
	F: Send + Sync,
	T: Send + Sync {
	fn execute(&self, params: Params) {
		let closure = &self.closure;
		closure(&self.delegate, params)
	}
}

struct DelegateSubscription<T, F> where
	F: Fn(&T, Subscription),
	F: Send + Sync,
	T: Send + Sync {
	delegate: Arc<T>,
	closure: F,
}

impl<T, F> SubscriptionCommand for DelegateSubscription<T, F> where
	F: Fn(&T, Subscription),
	F: Send + Sync,
	T: Send + Sync {
	fn execute(&self, subscription: Subscription) {
		let closure = &self.closure;
		closure(&self.delegate, subscription)
	}
}

/// A set of RPC methods and notifications tied to single `delegate` struct.
pub struct IoDelegate<T> where T: Send + Sync + 'static {
	delegate: Arc<T>,
	methods: HashMap<String, Box<MethodCommand>>,
	notifications: HashMap<String, Box<NotificationCommand>>,
	subscriptions: HashMap<(String, String), Box<SubscriptionCommand>>,
}

impl<T> IoDelegate<T> where T: Send + Sync + 'static {
	/// Creates new `IoDelegate`
	pub fn new(delegate: Arc<T>) -> Self {
		IoDelegate {
			delegate: delegate,
			methods: HashMap::new(),
			notifications: HashMap::new(),
			subscriptions: HashMap::new(),
		}
	}

	/// Add new supported method
	pub fn add_method<F>(&mut self, name: &str, closure: F) where F: Fn(&T, Params) -> Result<Value, Error> + Send + Sync + 'static {
		let delegate = self.delegate.clone();
		self.methods.insert(name.to_owned(), Box::new(DelegateMethod {
			delegate: delegate,
			closure: closure
		}));
	}

	/// Add new supported asynchronous method
	pub fn add_async_method<F>(&mut self, name: &str, closure: F) where F: Fn(&T, Params, Ready) + Send + Sync + 'static {
		let delegate = self.delegate.clone();
		self.methods.insert(name.to_owned(), Box::new(DelegateAsyncMethod {
			delegate: delegate,
			closure: closure
		}));
	}

	/// Add new supported subscription
	pub fn add_subscription<F>(&mut self, subscribe: &str, unsubscribe: &str, closure: F) where F: Fn(&T, Subscription) + Send + Sync + 'static {
		let delegate = self.delegate.clone();
		self.subscriptions.insert((subscribe.into(), unsubscribe.into()), Box::new(DelegateSubscription {
			delegate: delegate,
			closure: closure,
		}));
	}

	/// Add new supported notification
	pub fn add_notification<F>(&mut self, name: &str, closure: F) where F: Fn(&T, Params) + Send + Sync + 'static {
		let delegate = self.delegate.clone();
		self.notifications.insert(name.to_owned(), Box::new(DelegateNotification {
			delegate: delegate,
			closure: closure
		}));
	}
}

/// Should be used to handle jsonrpc io.
///
/// ```rust
/// extern crate jsonrpc_core;
/// use jsonrpc_core::*;
///
/// fn main() {
/// 	let io = IoHandler::new();
/// 	struct SayHello;
///
/// 	// Implement `SyncMethodCommand` or `AsyncMethodCommand`
/// 	impl SyncMethodCommand for SayHello {
/// 		fn execute(&self, _params: Params) -> Result<Value, Error>  {
/// 			Ok(Value::String("hello".to_string()))
/// 		}
/// 	}
///
/// 	io.add_method("say_hello", SayHello);
/// 	// Or just use closures
/// 	io.add_async_method("say_hello_async", |_params: Params, ready: Ready| {
///			ready.ready(Ok(Value::String("hello".to_string())))
/// 	});
///
/// 	let request1 = r#"{"jsonrpc": "2.0", "method": "say_hello", "params": [42, 23], "id": 1}"#;
/// 	let request2 = r#"{"jsonrpc": "2.0", "method": "say_hello_async", "params": [42, 23], "id": 1}"#;
/// 	let response = r#"{"jsonrpc":"2.0","result":"hello","id":1}"#;
///
/// 	assert_eq!(io.handle_request_sync(request1), Some(response.to_string()));
/// 	assert_eq!(io.handle_request_sync(request2), Some(response.to_string()));
/// }
/// ```
pub struct IoHandler {
	request_handler: RequestHandler
}

fn read_request(request_str: &str) -> Result<Request, Error> {
	serde_json::from_str(request_str).map_err(|_| Error::new(ErrorCode::ParseError))
}

fn write_response(response: Response) -> String {
	// this should never fail
	serde_json::to_string(&response).unwrap()
}

impl IoHandler {
	/// Creates new `IoHandler`
	pub fn new() -> Self {
		IoHandler {
			request_handler: RequestHandler::new()
		}
	}

	/// Add supported method
	pub fn add_method<C>(&self, name: &str, command: C) where C: SyncMethodCommand + 'static {
		self.request_handler.add_method(name.into(), SyncMethod {
			command: command
		})
	}

	/// Add supported asynchronous method
	pub fn add_async_method<C>(&self, name: &str, command: C) where C: MethodCommand + 'static {
		self.request_handler.add_method(name.into(), command)
	}

	/// Add supported notification
	pub fn add_notification<C>(&self, name: &str, command: C) where C: NotificationCommand + 'static {
		self.request_handler.add_notification(name.into(), command)
	}

	/// Add supported subscription
	pub fn add_subscription<C>(&self, subscribe: &str, unsubscribe: &str, command: C) where C: SubscriptionCommand + 'static {
		self.request_handler.add_subscription(subscribe.into(), unsubscribe.into(), command);
	}

	/// Add delegate with supported methods.
	pub fn add_delegate<D>(&self, delegate: IoDelegate<D>) where D: Send + Sync {
		self.request_handler.add_methods(delegate.methods);
		self.request_handler.add_notifications(delegate.notifications);
		self.request_handler.add_subscriptions(delegate.subscriptions);
	}

	/// Handle given request synchronously - will block until response is available.
	/// If you have any asynchronous methods in your RPC it is much wiser to use
	/// `handle_request` instead and deal with asynchronous requests in a non-blocking fashion.
	pub fn handle_request_sync(&self, request_str: &str) -> Option<String> {
		let (tx, rx) = mpsc::channel();
		self.handle_request(request_str, move |response: Option<String>| {
			tx.send(response).expect("Receiver is never dropped.");
		});
		// Wait for response.
		rx.recv().expect("Transmitting end is never dropped.")
	}

	/// Handle given request asynchronously.
	pub fn handle_request<H: ResponseHandler<Option<String>> + 'static>(&self, request_str: &str, response_handler: H) {
		self.handle(request_str, response_handler, None);
	}

	fn handle<H: ResponseHandler<Option<String>> + 'static>(&self, request_str: &str, response_handler: H, session: Option<Session>) {
		trace!(target: "rpc", "Request: {} in session.", request_str);

		let handler = Handler::new(response_handler, move |response: Option<Response>| {
			let response = response.map(write_response);
			debug!(target: "rpc", "Response: {:?}", response);
			response
		});

		let request = read_request(request_str);
		match request {
			Ok(request) => self.request_handler.handle_request(request, handler, session),
			Err(error) => handler.send(Some(Response::from(Failure {
				id: Id::Null,
				jsonrpc: Version::V2,
				error: error
			}))),
		}
	}

	/// Opens up a new session to handle many request and subscriptions.
	/// It should represent a single client.
	pub fn session(&self) -> IoSession {
		IoSession {
			io_handler: self,
			session: Session::default(),
		}
	}
}

/// Represents a single client connected to this RPC server.
/// The client may send many requests.
pub struct IoSession<'a> {
	io_handler: &'a IoHandler,
	session: Session,
}

impl<'a> IoSession<'a> {
	/// Handle a request within this session.
	pub fn handle_request<H: ResponseHandler<Option<String>> + 'static>(&self, request_str: &str, handler: H) {
		self.io_handler.handle(request_str, handler, Some(self.session.clone()));
	}
}

#[cfg(test)]
mod tests {
	use std::sync::mpsc;
	use std::time::Duration;
	use std::thread;
	use super::super::*;

	#[test]
	fn test_io_handler() {
		let io = IoHandler::new();

		struct SayHello;
		impl SyncMethodCommand for SayHello {
			fn execute(&self, _params: Params) -> Result<Value, Error> {
				Ok(Value::String("hello".to_string()))
			}
		}

		io.add_method("say_hello", SayHello);

		let request = r#"{"jsonrpc": "2.0", "method": "say_hello", "params": [42, 23], "id": 1}"#;
		let response = r#"{"jsonrpc":"2.0","result":"hello","id":1}"#;

		assert_eq!(io.handle_request_sync(request), Some(response.to_string()));
	}

	#[test]
	fn test_async_io_handler() {
		let io = IoHandler::new();

		struct SayHelloAsync;
		impl MethodCommand for SayHelloAsync {
			fn execute(&self, _params: Params, ready: Ready) {
				ready.ready(Ok(Value::String("hello".to_string())))
			}
		}

		io.add_async_method("say_hello", SayHelloAsync);

		let request = r#"{"jsonrpc": "2.0", "method": "say_hello", "params": [42, 23], "id": 1}"#;
		let response = r#"{"jsonrpc":"2.0","result":"hello","id":1}"#;

		assert_eq!(io.handle_request_sync(request), Some(response.to_string()));
	}

	#[test]
	fn test_async_io_handler_thread() {
		let io = IoHandler::new();

		struct SayHelloAsync;
		impl MethodCommand for SayHelloAsync {
			fn execute(&self, _params: Params, ready: Ready) {
				thread::spawn(|| {
					thread::sleep(Duration::from_secs(1));
					ready.ready(Ok(Value::String("hello".to_string())))
				});
			}
		}

		io.add_async_method("say_hello", SayHelloAsync);

		let request = r#"{"jsonrpc": "2.0", "method": "say_hello", "params": [42, 23], "id": 1}"#;
		let response = r#"{"jsonrpc":"2.0","result":"hello","id":1}"#;

		assert_eq!(io.handle_request_sync(request), Some(response.to_string()));
	}

	#[test]
	fn test_session_handler_with_subscription() {
		let io = IoHandler::new();

		struct SayHelloSubscription;
		impl SubscriptionCommand for SayHelloSubscription {
			fn execute(&self, subscription: Subscription) {
				match subscription {
					Subscription::Open { subscriber, .. } => {
						let subscriber = subscriber.assign_id(Value::U64(1));
						thread::spawn(move || {
							thread::sleep(Duration::from_millis(10));
							subscriber.send(Ok(Value::String("hello".to_string())));
							thread::sleep(Duration::from_millis(10));
							subscriber.send(Ok(Value::String("world".to_string())));
						});
					},
					Subscription::Close { id, .. } => {
						assert_eq!(id, Value::U64(1));
					},
				}
			}
		}

		io.add_subscription("say_hello", "stop_saying_hello", SayHelloSubscription);

		let request = r#"{"jsonrpc": "2.0", "method": "say_hello", "params": [42, 23], "id": 1}"#;
		let id = r#"{"jsonrpc":"2.0","result":1,"id":1}"#.to_owned();
		let response1 = r#"{"jsonrpc":"2.0","result":"hello","id":1}"#.to_owned();
		let response2 = r#"{"jsonrpc":"2.0","result":"world","id":1}"#.to_owned();

		let (tx, rx) = mpsc::channel();
		let session = io.session();
		session.handle_request(request, move |res| tx.send(res).unwrap());

		assert_eq!(rx.recv().unwrap(), Some(id));
		assert_eq!(rx.recv().unwrap(), Some(response1));
		assert_eq!(rx.recv().unwrap(), Some(response2));
		drop(session);
		assert!(rx.recv().is_err());
	}

}
<|endoftext|>


<commit_before>//! Glium compatibility module

use backend::graphics::egl::{EGLGraphicsBackend, SwapBuffersError};
use glium::Frame;
use glium::SwapBuffersError as GliumSwapBuffersError;
use glium::backend::{Backend, Context};
use glium::debug::DebugCallbackBehavior;
use std::ops::Deref;
use std::os::raw::c_void;

use std::rc::Rc;

impl From<SwapBuffersError> for GliumSwapBuffersError {
    fn from(error: SwapBuffersError) -> Self {
        match error {
            SwapBuffersError::ContextLost => GliumSwapBuffersError::ContextLost,
            SwapBuffersError::AlreadySwapped => GliumSwapBuffersError::AlreadySwapped,
        }
    }
}

/// Wrapper to expose `glium` compatibility
pub struct GliumGraphicsBackend<T: EGLGraphicsBackend> {
    context: Rc<Context>,
    backend: Rc<InternalBackend<T>>,
}

struct InternalBackend<T: EGLGraphicsBackend>(T);

impl<T: EGLGraphicsBackend + 'static> GliumGraphicsBackend<T> {
    fn new(backend: T) -> GliumGraphicsBackend<T> {
        let internal = Rc::new(InternalBackend(backend));

        GliumGraphicsBackend {
            // cannot fail
            context: unsafe {
                Context::new::<_, ()>(internal.clone(), false, DebugCallbackBehavior::default()).unwrap()
            },
            backend: internal,
        }
    }

    /// Start drawing on the backbuffer.
    ///
    /// This function returns a `Frame`, which can be used to draw on it. When the `Frame` is
    /// destroyed, the buffers are swapped.
    ///
    /// Note that destroying a `Frame` is immediate, even if vsync is enabled.
    #[inline]
    pub fn draw(&self) -> Frame {
        Frame::new(
            self.context.clone(),
            self.backend.get_framebuffer_dimensions(),
        )
    }
}

impl<T: EGLGraphicsBackend> Deref for GliumGraphicsBackend<T> {
    type Target = Context;

    fn deref(&self) -> &Context {
        &self.context
    }
}

/// Converter trait to expose `glium` compatibility for all `EGLGraphicsBackend`s
pub trait IntoGlium: EGLGraphicsBackend + Sized {
    /// Wrap the given `EGLGraphicsBackend` to a `GliumGraphicBackend`
    fn into_glium(self) -> GliumGraphicsBackend<Self>;
}

impl<T: EGLGraphicsBackend + 'static> IntoGlium for T {
    fn into_glium(self) -> GliumGraphicsBackend<Self> {
        GliumGraphicsBackend::new(self)
    }
}

unsafe impl<T: EGLGraphicsBackend> Backend for InternalBackend<T> {
    fn swap_buffers(&self) -> Result<(), GliumSwapBuffersError> {
        self.0.swap_buffers().map_err(Into::into)
    }

    unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
        self.0.get_proc_address(symbol) as *const c_void
    }

    fn get_framebuffer_dimensions(&self) -> (u32, u32) {
        self.0.get_framebuffer_dimensions()
    }

    fn is_current(&self) -> bool {
        self.0.is_current()
    }

    unsafe fn make_current(&self) {
        self.0.make_current().expect("Context was lost")
    }
}
<commit_msg>glium: impl Facade<commit_after>//! Glium compatibility module

use backend::graphics::egl::{EGLGraphicsBackend, SwapBuffersError};
use glium::Frame;
use glium::SwapBuffersError as GliumSwapBuffersError;
use glium::backend::{Backend, Context, Facade};
use glium::debug::DebugCallbackBehavior;
use std::ops::Deref;
use std::os::raw::c_void;

use std::rc::Rc;

impl From<SwapBuffersError> for GliumSwapBuffersError {
    fn from(error: SwapBuffersError) -> Self {
        match error {
            SwapBuffersError::ContextLost => GliumSwapBuffersError::ContextLost,
            SwapBuffersError::AlreadySwapped => GliumSwapBuffersError::AlreadySwapped,
        }
    }
}

/// Wrapper to expose `glium` compatibility
pub struct GliumGraphicsBackend<T: EGLGraphicsBackend> {
    context: Rc<Context>,
    backend: Rc<InternalBackend<T>>,
}

struct InternalBackend<T: EGLGraphicsBackend>(T);

impl<T: EGLGraphicsBackend + 'static> GliumGraphicsBackend<T> {
    fn new(backend: T) -> GliumGraphicsBackend<T> {
        let internal = Rc::new(InternalBackend(backend));

        GliumGraphicsBackend {
            // cannot fail
            context: unsafe {
                Context::new::<_, ()>(internal.clone(), false, DebugCallbackBehavior::default()).unwrap()
            },
            backend: internal,
        }
    }

    /// Start drawing on the backbuffer.
    ///
    /// This function returns a `Frame`, which can be used to draw on it. When the `Frame` is
    /// destroyed, the buffers are swapped.
    ///
    /// Note that destroying a `Frame` is immediate, even if vsync is enabled.
    #[inline]
    pub fn draw(&self) -> Frame {
        Frame::new(
            self.context.clone(),
            self.backend.get_framebuffer_dimensions(),
        )
    }
}

impl<T: EGLGraphicsBackend> Deref for GliumGraphicsBackend<T> {
    type Target = Context;

    fn deref(&self) -> &Context {
        &self.context
    }
}

impl<T: EGLGraphicsBackend> Facade for GliumGraphicsBackend<T> {
    fn get_context(&self) -> &Rc<Context> {
        &self.context
    }
}

/// Converter trait to expose `glium` compatibility for all `EGLGraphicsBackend`s
pub trait IntoGlium: EGLGraphicsBackend + Sized {
    /// Wrap the given `EGLGraphicsBackend` to a `GliumGraphicBackend`
    fn into_glium(self) -> GliumGraphicsBackend<Self>;
}

impl<T: EGLGraphicsBackend + 'static> IntoGlium for T {
    fn into_glium(self) -> GliumGraphicsBackend<Self> {
        GliumGraphicsBackend::new(self)
    }
}

unsafe impl<T: EGLGraphicsBackend> Backend for InternalBackend<T> {
    fn swap_buffers(&self) -> Result<(), GliumSwapBuffersError> {
        self.0.swap_buffers().map_err(Into::into)
    }

    unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void {
        self.0.get_proc_address(symbol) as *const c_void
    }

    fn get_framebuffer_dimensions(&self) -> (u32, u32) {
        self.0.get_framebuffer_dimensions()
    }

    fn is_current(&self) -> bool {
        self.0.is_current()
    }

    unsafe fn make_current(&self) {
        self.0.make_current().expect("Context was lost")
    }
}
<|endoftext|>


<commit_before>use bot::BotEnv;
use listeners::{Timeouts, PollTagger, AutoReplyListener, ReactionAuthorize};
use commands::*;

use lalafell::listeners::CommandListener;

use serenity::client::{EventHandler, Context};
use serenity::model::channel::Message;
use serenity::model::gateway::{Game, Ready};

use std::sync::Arc;

pub struct Handler {
  listeners: Vec<Box<EventHandler + Send + Sync>>
}

impl Handler {
  pub fn new(env: Arc<BotEnv>) -> Self {
    let listeners: Vec<Box<EventHandler + Send + Sync>> = vec![
      box command_listener(env.clone()),
      box ReactionAuthorize,
      box Timeouts,
      box PollTagger,
      box AutoReplyListener::default()
    ];
    // FIXME: ListenerManager for config listeners
    // for listener in &bot.config.listeners {
    //   let listener = ListenerManager::from_config(bot.clone(), listener).chain_err(|| format!("could not create listener {}", listener.name))?;
    //   listeners.push(listener);
    // }
    Handler { listeners }
  }
}

impl EventHandler for Handler {
  fn message(&self, ctx: Context, msg: Message) {
    for listener in &self.listeners {
      listener.message(ctx.clone(), msg.clone());
    }
  }

  fn ready(&self, ctx: Context, _: Ready) {
    ctx.shard.set_game(Some(Game::playing("with other Lalafell.")));
  }
}

macro_rules! command_listener {
  (env => $env:expr, $($($alias:expr),+ => $name:ident),+) => {{
    let mut command_listener = CommandListener::default();
    $(
      command_listener.add_command(&[$($alias),*], box $name::new($env.clone()));
    )*
    command_listener
  }}
}

// 15/17 (not 18, not porting archive yet) = 94.12% ported

fn command_listener<'a>(env: Arc<BotEnv>) -> CommandListener<'a> {
  command_listener! {
    env => env,
    "race" => RaceCommand,
    "tag" => TagCommand,
    "autotag" => AutoTagCommand,
    "viewtag" => ViewTagCommand,
    "updatetags" => UpdateTagsCommand,
    "updatetag" => UpdateTagCommand,
    "verify" => VerifyCommand,
    "referencecount" => ReferenceCountCommand,
    "poll" => PollCommand,
    "pollresults" => PollResultsCommand,
    "timeout" => TimeoutCommand,
    "untimeout" => UntimeoutCommand,
    // "archive" => ArchiveCommand,
    "viewedits" => ViewEditsCommand,
    "imagedump", "dump" => ImageDumpCommand,
    "configure", "config" => ConfigureCommand,
    "randomreaction", "reaction" => RandomReactionCommand,
    "search" => SearchCommand
  }
}
<commit_msg>fix: allow all listeners to get their events<commit_after>use bot::BotEnv;
use listeners::{Timeouts, PollTagger, AutoReplyListener, ReactionAuthorize};
use commands::*;

use lalafell::listeners::CommandListener;

use serenity::prelude::RwLock;
use serenity::client::{EventHandler, Context};
use serenity::model::id::GuildId;
use serenity::model::event::MessageUpdateEvent;
use serenity::model::channel::{Message, GuildChannel, Reaction};
use serenity::model::guild::Member;
use serenity::model::gateway::{Game, Ready};

use std::sync::Arc;

pub struct Handler {
  listeners: Vec<Box<EventHandler + Send + Sync>>
}

impl Handler {
  pub fn new(env: Arc<BotEnv>) -> Self {
    let listeners: Vec<Box<EventHandler + Send + Sync>> = vec![
      box command_listener(env.clone()),
      box ReactionAuthorize,
      box Timeouts,
      box PollTagger,
      box AutoReplyListener::default()
    ];
    // FIXME: ListenerManager for config listeners
    // for listener in &bot.config.listeners {
    //   let listener = ListenerManager::from_config(bot.clone(), listener).chain_err(|| format!("could not create listener {}", listener.name))?;
    //   listeners.push(listener);
    // }
    Handler { listeners }
  }
}

impl EventHandler for Handler {
  fn message(&self, ctx: Context, msg: Message) {
    for listener in &self.listeners {
      listener.message(ctx.clone(), msg.clone());
    }
  }

  fn message_update(&self, ctx: Context, update: MessageUpdateEvent) {
    for listener in &self.listeners {
      listener.message_update(ctx.clone(), update.clone());
    }
  }

  fn guild_member_addition(&self, ctx: Context, guild: GuildId, member: Member) {
    for listener in &self.listeners {
      listener.guild_member_addition(ctx.clone(), guild, member.clone());
    }
  }

  fn reaction_add(&self, ctx: Context, reaction: Reaction) {
    for listener in &self.listeners {
      listener.reaction_add(ctx.clone(), reaction.clone());
    }
  }

  fn reaction_remove(&self, ctx: Context, reaction: Reaction) {
    for listener in &self.listeners {
      listener.reaction_remove(ctx.clone(), reaction.clone());
    }
  }

  fn channel_create(&self, ctx: Context, channel: Arc<RwLock<GuildChannel>>) {
    for listener in &self.listeners {
      listener.channel_create(ctx.clone(), channel.clone());
    }
  }

  fn ready(&self, ctx: Context, _: Ready) {
    ctx.shard.set_game(Some(Game::playing("with other Lalafell.")));
  }
}

macro_rules! command_listener {
  (env => $env:expr, $($($alias:expr),+ => $name:ident),+) => {{
    let mut command_listener = CommandListener::default();
    $(
      command_listener.add_command(&[$($alias),*], box $name::new($env.clone()));
    )*
    command_listener
  }}
}

// 15/17 (not 18, not porting archive yet) = 94.12% ported

fn command_listener<'a>(env: Arc<BotEnv>) -> CommandListener<'a> {
  command_listener! {
    env => env,
    "race" => RaceCommand,
    "tag" => TagCommand,
    "autotag" => AutoTagCommand,
    "viewtag" => ViewTagCommand,
    "updatetags" => UpdateTagsCommand,
    "updatetag" => UpdateTagCommand,
    "verify" => VerifyCommand,
    "referencecount" => ReferenceCountCommand,
    "poll" => PollCommand,
    "pollresults" => PollResultsCommand,
    "timeout" => TimeoutCommand,
    "untimeout" => UntimeoutCommand,
    // "archive" => ArchiveCommand,
    "viewedits" => ViewEditsCommand,
    "imagedump", "dump" => ImageDumpCommand,
    "configure", "config" => ConfigureCommand,
    "randomreaction", "reaction" => RandomReactionCommand,
    "search" => SearchCommand
  }
}
<|endoftext|>


<commit_before>
//! Immediate mode gui. See [`ui::Ui`](struct.Ui.html) for more info.

use std::mem;
use gl;
use gl::types::*;
use cable_math::Vec2;

use color::Color;
use font::{Font, CachedFont};
use input::{InputManager, Key, State};
use matrix_stack::MatrixStack;
use shader::{Shader, ShaderPrototype};
use buffer::{Vertex, VertexBuffer, PrimitiveMode, BufferUsage};

const FONT_SIZE: f32 = 14.0;

/// A struct for using a imediate mode gui.
pub struct Ui {
    pub style: Style,

    mat_stack: MatrixStack,
    font: CachedFont,
    shader: Shader,
    draw_data: Vec<Vert>,
    draw_vbo: VertexBuffer<Vert>,

    caret: Vec2<f32>,
    caret_start: Vec2<f32>,
    line_size: f32,
    line_dir: LineDir,
    held: Option<Id>,

    // Input state
    mouse_pos: Vec2<f32>,
    mouse_state: State,
}

impl Ui {
    /// Creates a new imediate mode gui system with the given font. Note that the font will be
    /// copied internally, so you can pass a reference to a font you are using elsewhere in your
    /// program.
    pub fn new(font: &Font) -> Ui {
        Ui {
            style: Default::default(),

            mat_stack: MatrixStack::new(),
            font: CachedFont::from_font(font.clone()),
            shader: build_shader(),
            draw_data: Vec::with_capacity(500),
            draw_vbo: VertexBuffer::with_capacity(PrimitiveMode::Triangles, BufferUsage::DynamicDraw, 500),

            caret: Vec2::zero(),
            caret_start: Vec2::zero(),
            line_size: 0.0,
            line_dir: LineDir::Vertical,
            held: None,

            mouse_pos: Vec2::zero(),
            mouse_state: State::Up,
        }
    }

    /// Updates this imgui system. This should be called once per frame, before using any of the
    /// gui creation functions.
    pub fn update(&mut self, input: &InputManager, window_size: Vec2<u32>) {
        self.mat_stack.ortho(0.0, window_size.x as f32, 0.0, window_size.y as f32, -1.0, 1.0);

        self.mouse_pos = input.mouse_pos();
        self.mouse_state = input.mouse_key(0);

        if self.mouse_state.up() && !self.mouse_state.released() {
            self.held = None;
        }

        self.caret = Vec2::zero();
    }

    /// Shows all components added since the last call to `draw`. This function update the matrix
    /// buffers and binds new shaders. No special opengl state is required to be set when calling
    /// this function. Note that this function does not necessarily reset the state it changes.
    pub fn draw(&mut self) {
        self.mat_stack.update_buffer();

        self.draw_vbo.clear();
        self.draw_vbo.put(0, &self.draw_data);
        self.draw_data.clear();

        self.shader.bind();
        self.draw_vbo.draw();
        self.font.draw();
    }

    /// Moves the internal caret to the given position. Consecutive items will be inserted at
    /// the caret.
    pub fn set_caret(&mut self, pos: Vec2<f32>, line_dir: LineDir) {
        self.caret = pos;
        self.caret_start = pos;
        self.line_dir = line_dir;
        self.line_size = 0.0;
    }

    /// Advances the caret to the next line. The direction of a line depends on the line direction
    /// set by [`set_caret`].
    ///
    /// [`set_caret`]: struct.Ui.html#method.set_caret
    pub fn next_line(&mut self) {
        match self.line_dir {
            LineDir::Horizontal => {
                self.caret.y += self.line_size + self.style.line_spacing;
                self.caret.x = self.caret_start.x;
                self.line_size = 0.0;
            },
            LineDir::Vertical => {
                self.caret.x += self.line_size + self.style.line_spacing;
                self.caret.y = self.caret_start.y;
                self.line_size = 0.0;
            },
        }
    }

    fn advance_caret(&mut self, comp_width: f32, comp_height: f32) {
        match self.line_dir {
            LineDir::Horizontal => {
                self.caret.x += comp_width + self.style.line_spacing;
                self.line_size = f32::max(comp_height, self.line_size);
            },
            LineDir::Vertical => {
                self.caret.y += comp_height + self.style.line_spacing;
                self.line_size = f32::max(comp_width, self.line_size);
            },
        }
    }

    /// Shows a new button with the given text at the given location. Returns true if the button
    /// was pressed. Note that this function needs to be called every frame you want to see the
    /// button.
    pub fn button(&mut self, text: &str) -> bool {
        let id = Id::from_str(text, CompType::Button);

        let width = self.font.font().width(text, FONT_SIZE) + self.style.internal_padding.x;
        let height = self.font.font().line_height(FONT_SIZE) + self.style.internal_padding.y;
        let pos = self.caret;
        self.advance_caret(width, height);

        let text_start = self.style.internal_padding.y/2.0 - self.font.font().descent(FONT_SIZE);

        let hovered = self.mouse_pos.x > pos.x && self.mouse_pos.y > pos.y &&
                      self.mouse_pos.x < pos.x + width && self.mouse_pos.y < pos.y + height;
        let held = hovered && self.mouse_state.down();

        let color = if held {
            self.style.hold_color
        } else if hovered {
            self.style.hover_color
        } else {
            self.style.button_color
        };
        quad(&mut self.draw_data, pos, Vec2::new(width, height), color);
        self.font.cache(text, FONT_SIZE, pos + Vec2::new(self.style.internal_padding.x/2.0, height - text_start));

        if hovered && self.mouse_state.pressed() {
            self.held = Some(id);
        }

        self.held == Some(id) && hovered && self.mouse_state.released()
    }
}

#[derive(Clone, Debug)]
pub struct Style {
    pub button_color: Color,
    pub hover_color: Color,
    pub hold_color: Color,

    pub internal_padding: Vec2<f32>,
    pub line_spacing: f32,
}
impl Default for Style {
    fn default() -> Style {
        Style {
            button_color: Color::hex("4c4665"),
            hover_color: Color::hex("575074"),
            hold_color: Color::hex("413c56"),
            internal_padding: Vec2::new(10.0, 6.0),
            line_spacing: 5.0,
        }
    }
}

pub enum LineDir {
    /// Components are layed out below each other
    Vertical,
    /// Components are layed out side by side
    Horizontal,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct Id(u64, CompType);
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum CompType {
    Button,
}

impl Id {
    fn from_str(text: &str, ty: CompType) -> Id {
        use std::collections::hash_map::DefaultHasher;
        use std::hash::{Hasher, Hash};

        let mut hasher = DefaultHasher::new();
        text.hash(&mut hasher);
        let id = hasher.finish();

        Id(id, ty)
    }
}

#[derive(Debug)]
#[repr(C)]
struct Vert {
    pos: Vec2<f32>,
    color: Color,
}

fn quad(buf: &mut Vec<Vert>, pos: Vec2<f32>, size: Vec2<f32>, color: Color){
    let min = pos;
    let max = pos + size;

    buf.push(Vert { pos: Vec2::new(min.x, min.y), color: color });
    buf.push(Vert { pos: Vec2::new(max.x, min.y), color: color });
    buf.push(Vert { pos: Vec2::new(max.x, max.y), color: color });

    buf.push(Vert { pos: Vec2::new(min.x, min.y), color: color });
    buf.push(Vert { pos: Vec2::new(max.x, max.y), color: color });
    buf.push(Vert { pos: Vec2::new(min.x, max.y), color: color });
}

// We cannot use the custom derive from within this crate
impl Vertex for Vert {
    fn bytes_per_vertex() -> usize { mem::size_of::<Vert>() }
    fn setup_attrib_pointers() {
        let stride = <Vert as Vertex>::bytes_per_vertex();
        let mut offset = 0;
        unsafe {
            gl::EnableVertexAttribArray(0);
            gl::VertexAttribPointer(0, 2, gl::FLOAT,
                                    false as GLboolean,
                                    stride as GLsizei, offset as *const GLvoid);
            offset += mem::size_of::<Vec2<f32>>();

            gl::EnableVertexAttribArray(1);
            gl::VertexAttribPointer(1, 4, gl::FLOAT,
                                    false as GLboolean,
                                    stride as GLsizei, offset as *const GLvoid);
        }
    }
    // Not used, we manualy declare inputs in the shader
    fn gen_shader_input_decl() -> String { String::new() }
}

const VERT_SRC: &'static str = "
    #version 330 core

    layout(location = 0) in vec2 pos;
    layout(location = 1) in vec4 color;

    out vec4 vert_col;

    // Matrix block is inserted automatically

    void main() {
        gl_Position = mvp * vec4(pos, 0.0, 1.0);
        vert_col = color;
    }
";
const FRAG_SRC: &'static str = "
    #version 330 core

    in vec4 vert_col;
    out vec4 color;

    void main() {
        color = vert_col;
    }
";

fn build_shader() -> Shader {
    let mut proto = ShaderPrototype::new_prototype(VERT_SRC, "", FRAG_SRC);
    proto.bind_to_matrix_storage();
    match proto.build() {
        Ok(shader) => shader,
        Err(err) => {
            println!("{}", err); // Print the error properly
            panic!();
        }
    }
}

<commit_msg>Added imgui sliders<commit_after>
//! Immediate mode gui. See [`ui::Ui`](struct.Ui.html) for more info.

use std::mem;
use gl;
use gl::types::*;
use std::ops::Range;
use std::collections::HashMap;
use std::fmt::Write;
use cable_math::Vec2;

use color::Color;
use font::{Font, CachedFont};
use input::{InputManager, State};
use matrix_stack::MatrixStack;
use shader::{Shader, ShaderPrototype};
use buffer::{Vertex, VertexBuffer, PrimitiveMode, BufferUsage};

const FONT_SIZE: f32 = 14.0;

/// A struct for using a imediate mode gui.
pub struct Ui {
    pub style: Style,

    mat_stack: MatrixStack,
    font: CachedFont,
    shader: Shader,
    draw_data: Vec<Vert>,
    draw_vbo: VertexBuffer<Vert>,

    caret: Vec2<f32>,
    caret_start: Vec2<f32>,
    line_size: f32,
    line_dir: LineDir,
    held: Option<Id>,

    internal_format_string: String,
    slider_map: HashMap<Id, f32>,

    // Input state
    mouse_pos: Vec2<f32>,
    mouse_state: State,
}

impl Ui {
    /// Creates a new imediate mode gui system with the given font. Note that the font will be
    /// copied internally, so you can pass a reference to a font you are using elsewhere in your
    /// program.
    pub fn new(font: &Font) -> Ui {
        Ui {
            style: Default::default(),

            mat_stack: MatrixStack::new(),
            font: CachedFont::from_font(font.clone()),
            shader: build_shader(),
            draw_data: Vec::with_capacity(500),
            draw_vbo: VertexBuffer::with_capacity(PrimitiveMode::Triangles, BufferUsage::DynamicDraw, 500),

            caret: Vec2::zero(),
            caret_start: Vec2::zero(),
            line_size: 0.0,
            line_dir: LineDir::Vertical,
            held: None,

            internal_format_string: String::new(),
            slider_map: HashMap::new(),

            mouse_pos: Vec2::zero(),
            mouse_state: State::Up,
        }
    }

    /// Updates this imgui system. This should be called once per frame, before using any of the
    /// gui creation functions.
    pub fn update(&mut self, input: &InputManager, window_size: Vec2<u32>) {
        self.mat_stack.ortho(0.0, window_size.x as f32, 0.0, window_size.y as f32, -1.0, 1.0);

        self.mouse_pos = input.mouse_pos();
        self.mouse_state = input.mouse_key(0);

        if self.mouse_state.up() && !self.mouse_state.released() {
            self.held = None;
        }

        self.caret = Vec2::zero();
    }

    /// Shows all components added since the last call to `draw`. This function update the matrix
    /// buffers and binds new shaders. No special opengl state is required to be set when calling
    /// this function. Note that this function does not necessarily reset the state it changes.
    pub fn draw(&mut self) {
        self.mat_stack.update_buffer();

        self.draw_vbo.clear();
        self.draw_vbo.put(0, &self.draw_data);
        self.draw_data.clear();

        self.shader.bind();
        self.draw_vbo.draw();
        self.font.draw();
    }

    /// Moves the internal caret to the given position. Consecutive items will be inserted at
    /// the caret.
    pub fn set_caret(&mut self, pos: Vec2<f32>, line_dir: LineDir) {
        self.caret = pos;
        self.caret_start = pos;
        self.line_dir = line_dir;
        self.line_size = 0.0;
    }

    /// Advances the caret to the next line. The direction of a line depends on the line direction
    /// set by [`set_caret`].
    ///
    /// [`set_caret`]: struct.Ui.html#method.set_caret
    pub fn next_line(&mut self) {
        match self.line_dir {
            LineDir::Horizontal => {
                self.caret.y += self.line_size + self.style.line_spacing;
                self.caret.x = self.caret_start.x;
                self.line_size = 0.0;
            },
            LineDir::Vertical => {
                self.caret.x += self.line_size + self.style.line_spacing;
                self.caret.y = self.caret_start.y;
                self.line_size = 0.0;
            },
        }
    }

    fn advance_caret(&mut self, comp_width: f32, comp_height: f32) {
        match self.line_dir {
            LineDir::Horizontal => {
                self.caret.x += comp_width + self.style.line_spacing;
                self.line_size = f32::max(comp_height, self.line_size);
            },
            LineDir::Vertical => {
                self.caret.y += comp_height + self.style.line_spacing;
                self.line_size = f32::max(comp_width, self.line_size);
            },
        }
    }

    fn default_height(&self) -> f32 {
        self.font.font().line_height(FONT_SIZE) + self.style.internal_padding.y
    }

    /// Shows a new button with the given text at the given location. Returns true if the button
    /// was pressed. Note that this function needs to be called every frame you want to see the
    /// button.
    pub fn button(&mut self, text: &str) -> bool {
        let id = Id::from_str(text, CompType::Button);

        let width = self.font.font().width(text, FONT_SIZE) + self.style.internal_padding.x;
        let height = self.default_height();
        let pos = self.caret;
        self.advance_caret(width, height);

        let text_start = self.style.internal_padding.y/2.0 - self.font.font().descent(FONT_SIZE);

        let hovered = self.mouse_pos.x > pos.x && self.mouse_pos.y > pos.y &&
                      self.mouse_pos.x < pos.x + width && self.mouse_pos.y < pos.y + height;
        if hovered && self.mouse_state.pressed() {
            self.held = Some(id);
        }

        let color = if self.held == Some(id) {
            self.style.hold_color
        } else if hovered {
            self.style.hover_color
        } else {
            self.style.base_color
        };
        quad(&mut self.draw_data, pos, Vec2::new(width, height), color);
        self.font.cache(text, FONT_SIZE, pos + Vec2::new(self.style.internal_padding.x/2.0, height - text_start));

        self.held == Some(id) && hovered && self.mouse_state.released()
    }

    // TODO: Maybe make this generic over different number types
    pub fn slider(&mut self, text: &str, range: Range<f32>) -> f32 {
        let id = Id::from_str(text, CompType::Slider);
        let mut value = *self.slider_map.entry(id).or_insert((range.start + range.end) / 2.0);

        let width = self.style.default_comp_width;
        let height = self.default_height();
        let pos = self.caret;
        self.advance_caret(width, height);

        let hovered = self.mouse_pos.x > pos.x && self.mouse_pos.y > pos.y &&
                      self.mouse_pos.x < pos.x + width && self.mouse_pos.y < pos.y + height;
        if hovered && self.mouse_state.pressed() {
            self.held = Some(id);
        }

        let slider_size = {
            let size = height - self.style.internal_padding.y;
            Vec2::new(size, size)
        };
        let slider_pos = {
            let norm_value = (value - range.start) / (range.end - range.start);
            let slide_distance = width - self.style.internal_padding.x - slider_size.x;
            pos + Vec2::new(self.style.internal_padding.x/2.0 + norm_value*slide_distance, self.style.internal_padding.y/2.0)
        };

        self.internal_format_string.clear();
        write!(self.internal_format_string, "{}: {:.*}", text, 2, value).unwrap();

        let text_pos = {
            let text_width = self.font.font().width(&self.internal_format_string, FONT_SIZE);
            let text_v_offset = self.style.internal_padding.y/2.0 - self.font.font().descent(FONT_SIZE);
            pos + Vec2::new(width/2.0 - text_width/2.0, height - text_v_offset)
        };

        if self.held == Some(id) {
            value = (self.mouse_pos.x - pos.x - self.style.internal_padding.x/2.0 - slider_size.x/2.0) /
                    (width - self.style.internal_padding.x - slider_size.x);
            if value > 1.0 { value = 1.0 }
            if value < 0.0 { value = 0.0 }
            value = range.start + value*(range.end - range.start);

            self.slider_map.insert(id, value);
        }

        // Main bar
        let color = if hovered { self.style.hover_color } else { self.style.base_color };
        quad(&mut self.draw_data, pos, Vec2::new(width, height), color);
        self.font.cache(&self.internal_format_string, FONT_SIZE, text_pos);
        // Slidy thing
        let color = if self.held == Some(id) { self.style.top_hold_color } else { self.style.top_color };
        quad(&mut self.draw_data, slider_pos, slider_size, color);

        value
    }
}

#[derive(Clone, Debug)]
pub struct Style {
    pub base_color: Color,
    pub hover_color: Color,
    pub hold_color: Color,
    pub top_color: Color,
    pub top_hold_color: Color,

    pub internal_padding: Vec2<f32>,
    pub line_spacing: f32,
    pub default_comp_width: f32,
}
impl Default for Style {
    fn default() -> Style {
        Style {
            base_color:      Color::hex("4c4665"),
            hover_color:     Color::hex("575074"),
            hold_color:      Color::hex("413c56"),
            top_color:       Color::hex("403147"),
            top_hold_color:  Color::hex("2a2738"),

            internal_padding: Vec2::new(10.0, 6.0),
            line_spacing: 5.0,
            default_comp_width: 150.0,
        }
    }
}

pub enum LineDir {
    /// Components are layed out below each other
    Vertical,
    /// Components are layed out side by side
    Horizontal,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
struct Id(u64, CompType);
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
enum CompType {
    Button,
    Slider,
}

impl Id {
    fn from_str(text: &str, ty: CompType) -> Id {
        use std::collections::hash_map::DefaultHasher;
        use std::hash::{Hasher, Hash};

        let mut hasher = DefaultHasher::new();
        text.hash(&mut hasher);
        let id = hasher.finish();

        Id(id, ty)
    }
}

#[derive(Debug)]
#[repr(C)]
struct Vert {
    pos: Vec2<f32>,
    color: Color,
}

fn quad(buf: &mut Vec<Vert>, pos: Vec2<f32>, size: Vec2<f32>, color: Color){
    let min = pos;
    let max = pos + size;

    buf.push(Vert { pos: Vec2::new(min.x, min.y), color: color });
    buf.push(Vert { pos: Vec2::new(max.x, min.y), color: color });
    buf.push(Vert { pos: Vec2::new(max.x, max.y), color: color });

    buf.push(Vert { pos: Vec2::new(min.x, min.y), color: color });
    buf.push(Vert { pos: Vec2::new(max.x, max.y), color: color });
    buf.push(Vert { pos: Vec2::new(min.x, max.y), color: color });
}

// We cannot use the custom derive from within this crate
impl Vertex for Vert {
    fn bytes_per_vertex() -> usize { mem::size_of::<Vert>() }
    fn setup_attrib_pointers() {
        let stride = <Vert as Vertex>::bytes_per_vertex();
        let mut offset = 0;
        unsafe {
            gl::EnableVertexAttribArray(0);
            gl::VertexAttribPointer(0, 2, gl::FLOAT,
                                    false as GLboolean,
                                    stride as GLsizei, offset as *const GLvoid);
            offset += mem::size_of::<Vec2<f32>>();

            gl::EnableVertexAttribArray(1);
            gl::VertexAttribPointer(1, 4, gl::FLOAT,
                                    false as GLboolean,
                                    stride as GLsizei, offset as *const GLvoid);
        }
    }
    // Not used, we manualy declare inputs in the shader
    fn gen_shader_input_decl() -> String { String::new() }
}

const VERT_SRC: &'static str = "
    #version 330 core

    layout(location = 0) in vec2 pos;
    layout(location = 1) in vec4 color;

    out vec4 vert_col;

    // Matrix block is inserted automatically

    void main() {
        gl_Position = mvp * vec4(pos, 0.0, 1.0);
        vert_col = color;
    }
";
const FRAG_SRC: &'static str = "
    #version 330 core

    in vec4 vert_col;
    out vec4 color;

    void main() {
        color = vert_col;
    }
";

fn build_shader() -> Shader {
    let mut proto = ShaderPrototype::new_prototype(VERT_SRC, "", FRAG_SRC);
    proto.bind_to_matrix_storage();
    match proto.build() {
        Ok(shader) => shader,
        Err(err) => {
            println!("{}", err); // Print the error properly
            panic!();
        }
    }
}

<|endoftext|>


<commit_before>// Type encoding

import std::io;
import std::map::hashmap;
import std::option::some;
import std::option::none;
import std::uint;
import front::ast::*;
import middle::ty;
import pretty::ppaux::lit_to_str;
import util::common;

type ctxt =
    rec(fn(&def_id) -> str  ds, // Def -> str Callback:
        ty::ctxt tcx, // The type context.
        abbrev_ctxt abbrevs);

// Compact string representation for ty.t values. API ty_str & parse_from_str.
// Extra parameters are for converting to/from def_ids in the string rep.
// Whatever format you choose should not contain pipe characters.
type ty_abbrev = rec(uint pos, uint len, str s);

tag abbrev_ctxt { ac_no_abbrevs; ac_use_abbrevs(hashmap[ty::t, ty_abbrev]); }

fn cx_uses_abbrevs(&@ctxt cx) -> bool {
    alt (cx.abbrevs) {
        case (ac_no_abbrevs) { ret false; }
        case (ac_use_abbrevs(_)) { ret true; }
    }
}
fn ty_str(&@ctxt cx, &ty::t t) -> str {
    assert (!cx_uses_abbrevs(cx));
    auto sw = io::string_writer();
    enc_ty(sw.get_writer(), cx, t);
    ret sw.get_str();
}
fn enc_ty(&io::writer w, &@ctxt cx, &ty::t t) {
    alt (cx.abbrevs) {
        case (ac_no_abbrevs) {
            auto result_str;
            alt (cx.tcx.short_names_cache.find(t)) {
                case (some(?s)) { result_str = s; }
                case (none) {
                    auto sw = io::string_writer();
                    enc_sty(sw.get_writer(), cx, ty::struct(cx.tcx, t));
                    result_str = sw.get_str();
                    cx.tcx.short_names_cache.insert(t, result_str);
                }
            }
            w.write_str(result_str);
        }
        case (ac_use_abbrevs(?abbrevs)) {
            alt (abbrevs.find(t)) {
                case (some(?a)) { w.write_str(a.s); ret; }
                case (none) {
                    auto pos = w.get_buf_writer().tell();
                    auto ss = enc_sty(w, cx, ty::struct(cx.tcx, t));
                    auto end = w.get_buf_writer().tell();
                    auto len = end - pos;
                    fn estimate_sz(uint u) -> uint {
                        auto n = u;
                        auto len = 0u;
                        while (n != 0u) { len += 1u; n = n >> 4u; }
                        ret len;
                    }
                    auto abbrev_len =
                        3u + estimate_sz(pos) + estimate_sz(len);
                    if (abbrev_len < len) {
                        // I.e. it's actually an abbreviation.

                        auto s =
                            "#" + uint::to_str(pos, 16u) + ":" +
                            uint::to_str(len, 16u) + "#";
                        auto a = rec(pos=pos, len=len, s=s);
                        abbrevs.insert(t, a);
                    }
                    ret;
                }
            }
        }
    }
}
fn enc_mt(&io::writer w, &@ctxt cx, &ty::mt mt) {
    alt (mt.mut) {
        case (imm) { }
        case (mut) { w.write_char('m'); }
        case (maybe_mut) { w.write_char('?'); }
    }
    enc_ty(w, cx, mt.ty);
}
fn enc_sty(&io::writer w, &@ctxt cx, &ty::sty st) {
    alt (st) {
        case (ty::ty_nil) { w.write_char('n'); }
        case (ty::ty_bot) { w.write_char('z'); }
        case (ty::ty_bool) { w.write_char('b'); }
        case (ty::ty_int) { w.write_char('i'); }
        case (ty::ty_uint) { w.write_char('u'); }
        case (ty::ty_float) { w.write_char('l'); }
        case (ty::ty_machine(?mach)) {
            alt (mach) {
                case (common::ty_u8) { w.write_str("Mb"); }
                case (common::ty_u16) { w.write_str("Mw"); }
                case (common::ty_u32) { w.write_str("Ml"); }
                case (common::ty_u64) { w.write_str("Md"); }
                case (common::ty_i8) { w.write_str("MB"); }
                case (common::ty_i16) { w.write_str("MW"); }
                case (common::ty_i32) { w.write_str("ML"); }
                case (common::ty_i64) { w.write_str("MD"); }
                case (common::ty_f32) { w.write_str("Mf"); }
                case (common::ty_f64) { w.write_str("MF"); }
            }
        }
        case (ty::ty_char) { w.write_char('c'); }
        case (ty::ty_str) { w.write_char('s'); }
        case (ty::ty_istr) { w.write_char('S'); }
        case (ty::ty_tag(?def, ?tys)) {
            w.write_str("t[");
            w.write_str(cx.ds(def));
            w.write_char('|');
            for (ty::t t in tys) { enc_ty(w, cx, t); }
            w.write_char(']');
        }
        case (ty::ty_box(?mt)) { w.write_char('@'); enc_mt(w, cx, mt); }
        case (ty::ty_ptr(?mt)) { w.write_char('*'); enc_mt(w, cx, mt); }
        case (ty::ty_vec(?mt)) { w.write_char('V'); enc_mt(w, cx, mt); }
        case (ty::ty_ivec(?mt)) { w.write_char('I'); enc_mt(w, cx, mt); }
        case (ty::ty_port(?t)) { w.write_char('P'); enc_ty(w, cx, t); }
        case (ty::ty_chan(?t)) { w.write_char('C'); enc_ty(w, cx, t); }
        case (ty::ty_tup(?mts)) {
            w.write_str("T[");
            for (ty::mt mt in mts) { enc_mt(w, cx, mt); }
            w.write_char(']');
        }
        case (ty::ty_rec(?fields)) {
            w.write_str("R[");
            for (ty::field field in fields) {
                w.write_str(field.ident);
                w.write_char('=');
                enc_mt(w, cx, field.mt);
            }
            w.write_char(']');
        }
        case (ty::ty_fn(?proto, ?args, ?out, ?cf, ?constrs)) {
            enc_proto(w, proto);
            enc_ty_fn(w, cx, args, out, cf, constrs);
        }
        case (ty::ty_native_fn(?abi, ?args, ?out)) {
            w.write_char('N');
            alt (abi) {
                case (native_abi_rust) { w.write_char('r'); }
                case (native_abi_rust_intrinsic) {
                    w.write_char('i');
                }
                case (native_abi_cdecl) { w.write_char('c'); }
                case (native_abi_llvm) { w.write_char('l'); }
            }
            enc_ty_fn(w, cx, args, out, return, []);
        }
        case (ty::ty_obj(?methods)) {
            w.write_str("O[");
            for (ty::method m in methods) {
                enc_proto(w, m.proto);
                w.write_str(m.ident);
                enc_ty_fn(w, cx, m.inputs, m.output, m.cf, m.constrs);
            }
            w.write_char(']');
        }
        case (ty::ty_res(?def, ?ty)) {
            w.write_char('r');
            w.write_str(cx.ds(def));
            w.write_char('|');
            enc_ty(w, cx, ty);
        }
        case (ty::ty_var(?id)) {
            w.write_char('X');
            w.write_str(common::istr(id));
        }
        case (ty::ty_native) { w.write_char('E'); }
        case (ty::ty_param(?id)) {
            w.write_char('p');
            w.write_str(common::uistr(id));
        }
        case (ty::ty_type) { w.write_char('Y'); }
        case (ty::ty_task) { w.write_char('a'); }
    }
}
fn enc_proto(&io::writer w, proto proto) {
    alt (proto) {
        case (proto_iter) { w.write_char('W'); }
        case (proto_fn) { w.write_char('F'); }
    }
}
fn enc_ty_fn(&io::writer w, &@ctxt cx, &vec[ty::arg] args, &ty::t out,
             &controlflow cf, &vec[@ty::constr_def] constrs) {
    w.write_char('[');
    for (ty::arg arg in args) {
        alt (arg.mode) {
            case (ty::mo_alias(?mut)) {
                w.write_char('&');
                if (mut) { w.write_char('m'); }
            }
            case (ty::mo_val) { }
        }
        enc_ty(w, cx, arg.ty);
    }
    w.write_char(']');
    auto colon = true;
    for (@ty::constr_def c in constrs) {
        if (colon) {
            w.write_char(':');
            colon = false;
        } else { w.write_char(';'); }
        enc_constr(w, cx, c);
    }
    alt (cf) {
        case (noreturn) { w.write_char('!'); }
        case (_) { enc_ty(w, cx, out); }
    }

}
fn enc_constr(&io::writer w, &@ctxt cx, &@ty::constr_def c) {
    w.write_str(ty::path_to_str(c.node.path));
    w.write_char('(');
    w.write_str(cx.ds(c.node.id));
    w.write_char('|');
    auto semi = false;
    for (@constr_arg a in c.node.args) {
        if (semi) { w.write_char(';'); } else { semi = true; }
        alt (a.node) {
            case (carg_base) { w.write_char('*'); }
            case (carg_ident(?i)) {
                w.write_uint(i);
            }
            case (carg_lit(?l)) { w.write_str(lit_to_str(l)); }
        }
    }
    w.write_char(')');
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>Limit exports from metadata::tyencode<commit_after>// Type encoding

import std::io;
import std::map::hashmap;
import std::option::some;
import std::option::none;
import std::uint;
import front::ast::*;
import middle::ty;
import pretty::ppaux::lit_to_str;
import util::common;

export ctxt;
export ty_abbrev;
export ac_no_abbrevs;
export ac_use_abbrevs;
export enc_ty;
export ty_str;

type ctxt =
    rec(fn(&def_id) -> str  ds, // Def -> str Callback:
        ty::ctxt tcx, // The type context.
        abbrev_ctxt abbrevs);

// Compact string representation for ty.t values. API ty_str & parse_from_str.
// Extra parameters are for converting to/from def_ids in the string rep.
// Whatever format you choose should not contain pipe characters.
type ty_abbrev = rec(uint pos, uint len, str s);

tag abbrev_ctxt { ac_no_abbrevs; ac_use_abbrevs(hashmap[ty::t, ty_abbrev]); }

fn cx_uses_abbrevs(&@ctxt cx) -> bool {
    alt (cx.abbrevs) {
        case (ac_no_abbrevs) { ret false; }
        case (ac_use_abbrevs(_)) { ret true; }
    }
}
fn ty_str(&@ctxt cx, &ty::t t) -> str {
    assert (!cx_uses_abbrevs(cx));
    auto sw = io::string_writer();
    enc_ty(sw.get_writer(), cx, t);
    ret sw.get_str();
}
fn enc_ty(&io::writer w, &@ctxt cx, &ty::t t) {
    alt (cx.abbrevs) {
        case (ac_no_abbrevs) {
            auto result_str;
            alt (cx.tcx.short_names_cache.find(t)) {
                case (some(?s)) { result_str = s; }
                case (none) {
                    auto sw = io::string_writer();
                    enc_sty(sw.get_writer(), cx, ty::struct(cx.tcx, t));
                    result_str = sw.get_str();
                    cx.tcx.short_names_cache.insert(t, result_str);
                }
            }
            w.write_str(result_str);
        }
        case (ac_use_abbrevs(?abbrevs)) {
            alt (abbrevs.find(t)) {
                case (some(?a)) { w.write_str(a.s); ret; }
                case (none) {
                    auto pos = w.get_buf_writer().tell();
                    auto ss = enc_sty(w, cx, ty::struct(cx.tcx, t));
                    auto end = w.get_buf_writer().tell();
                    auto len = end - pos;
                    fn estimate_sz(uint u) -> uint {
                        auto n = u;
                        auto len = 0u;
                        while (n != 0u) { len += 1u; n = n >> 4u; }
                        ret len;
                    }
                    auto abbrev_len =
                        3u + estimate_sz(pos) + estimate_sz(len);
                    if (abbrev_len < len) {
                        // I.e. it's actually an abbreviation.

                        auto s =
                            "#" + uint::to_str(pos, 16u) + ":" +
                            uint::to_str(len, 16u) + "#";
                        auto a = rec(pos=pos, len=len, s=s);
                        abbrevs.insert(t, a);
                    }
                    ret;
                }
            }
        }
    }
}
fn enc_mt(&io::writer w, &@ctxt cx, &ty::mt mt) {
    alt (mt.mut) {
        case (imm) { }
        case (mut) { w.write_char('m'); }
        case (maybe_mut) { w.write_char('?'); }
    }
    enc_ty(w, cx, mt.ty);
}
fn enc_sty(&io::writer w, &@ctxt cx, &ty::sty st) {
    alt (st) {
        case (ty::ty_nil) { w.write_char('n'); }
        case (ty::ty_bot) { w.write_char('z'); }
        case (ty::ty_bool) { w.write_char('b'); }
        case (ty::ty_int) { w.write_char('i'); }
        case (ty::ty_uint) { w.write_char('u'); }
        case (ty::ty_float) { w.write_char('l'); }
        case (ty::ty_machine(?mach)) {
            alt (mach) {
                case (common::ty_u8) { w.write_str("Mb"); }
                case (common::ty_u16) { w.write_str("Mw"); }
                case (common::ty_u32) { w.write_str("Ml"); }
                case (common::ty_u64) { w.write_str("Md"); }
                case (common::ty_i8) { w.write_str("MB"); }
                case (common::ty_i16) { w.write_str("MW"); }
                case (common::ty_i32) { w.write_str("ML"); }
                case (common::ty_i64) { w.write_str("MD"); }
                case (common::ty_f32) { w.write_str("Mf"); }
                case (common::ty_f64) { w.write_str("MF"); }
            }
        }
        case (ty::ty_char) { w.write_char('c'); }
        case (ty::ty_str) { w.write_char('s'); }
        case (ty::ty_istr) { w.write_char('S'); }
        case (ty::ty_tag(?def, ?tys)) {
            w.write_str("t[");
            w.write_str(cx.ds(def));
            w.write_char('|');
            for (ty::t t in tys) { enc_ty(w, cx, t); }
            w.write_char(']');
        }
        case (ty::ty_box(?mt)) { w.write_char('@'); enc_mt(w, cx, mt); }
        case (ty::ty_ptr(?mt)) { w.write_char('*'); enc_mt(w, cx, mt); }
        case (ty::ty_vec(?mt)) { w.write_char('V'); enc_mt(w, cx, mt); }
        case (ty::ty_ivec(?mt)) { w.write_char('I'); enc_mt(w, cx, mt); }
        case (ty::ty_port(?t)) { w.write_char('P'); enc_ty(w, cx, t); }
        case (ty::ty_chan(?t)) { w.write_char('C'); enc_ty(w, cx, t); }
        case (ty::ty_tup(?mts)) {
            w.write_str("T[");
            for (ty::mt mt in mts) { enc_mt(w, cx, mt); }
            w.write_char(']');
        }
        case (ty::ty_rec(?fields)) {
            w.write_str("R[");
            for (ty::field field in fields) {
                w.write_str(field.ident);
                w.write_char('=');
                enc_mt(w, cx, field.mt);
            }
            w.write_char(']');
        }
        case (ty::ty_fn(?proto, ?args, ?out, ?cf, ?constrs)) {
            enc_proto(w, proto);
            enc_ty_fn(w, cx, args, out, cf, constrs);
        }
        case (ty::ty_native_fn(?abi, ?args, ?out)) {
            w.write_char('N');
            alt (abi) {
                case (native_abi_rust) { w.write_char('r'); }
                case (native_abi_rust_intrinsic) {
                    w.write_char('i');
                }
                case (native_abi_cdecl) { w.write_char('c'); }
                case (native_abi_llvm) { w.write_char('l'); }
            }
            enc_ty_fn(w, cx, args, out, return, []);
        }
        case (ty::ty_obj(?methods)) {
            w.write_str("O[");
            for (ty::method m in methods) {
                enc_proto(w, m.proto);
                w.write_str(m.ident);
                enc_ty_fn(w, cx, m.inputs, m.output, m.cf, m.constrs);
            }
            w.write_char(']');
        }
        case (ty::ty_res(?def, ?ty)) {
            w.write_char('r');
            w.write_str(cx.ds(def));
            w.write_char('|');
            enc_ty(w, cx, ty);
        }
        case (ty::ty_var(?id)) {
            w.write_char('X');
            w.write_str(common::istr(id));
        }
        case (ty::ty_native) { w.write_char('E'); }
        case (ty::ty_param(?id)) {
            w.write_char('p');
            w.write_str(common::uistr(id));
        }
        case (ty::ty_type) { w.write_char('Y'); }
        case (ty::ty_task) { w.write_char('a'); }
    }
}
fn enc_proto(&io::writer w, proto proto) {
    alt (proto) {
        case (proto_iter) { w.write_char('W'); }
        case (proto_fn) { w.write_char('F'); }
    }
}
fn enc_ty_fn(&io::writer w, &@ctxt cx, &vec[ty::arg] args, &ty::t out,
             &controlflow cf, &vec[@ty::constr_def] constrs) {
    w.write_char('[');
    for (ty::arg arg in args) {
        alt (arg.mode) {
            case (ty::mo_alias(?mut)) {
                w.write_char('&');
                if (mut) { w.write_char('m'); }
            }
            case (ty::mo_val) { }
        }
        enc_ty(w, cx, arg.ty);
    }
    w.write_char(']');
    auto colon = true;
    for (@ty::constr_def c in constrs) {
        if (colon) {
            w.write_char(':');
            colon = false;
        } else { w.write_char(';'); }
        enc_constr(w, cx, c);
    }
    alt (cf) {
        case (noreturn) { w.write_char('!'); }
        case (_) { enc_ty(w, cx, out); }
    }

}
fn enc_constr(&io::writer w, &@ctxt cx, &@ty::constr_def c) {
    w.write_str(ty::path_to_str(c.node.path));
    w.write_char('(');
    w.write_str(cx.ds(c.node.id));
    w.write_char('|');
    auto semi = false;
    for (@constr_arg a in c.node.args) {
        if (semi) { w.write_char(';'); } else { semi = true; }
        alt (a.node) {
            case (carg_base) { w.write_char('*'); }
            case (carg_ident(?i)) {
                w.write_uint(i);
            }
            case (carg_lit(?l)) { w.write_str(lit_to_str(l)); }
        }
    }
    w.write_char(')');
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>