<commit_before>extern crate threadpool;

use threadpool::ThreadPool;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::rc::Rc;
use std::fmt::{Formatter, Error, Debug};
use std::collections::vec_deque::VecDeque;

#[cfg(test)]
mod test;

pub struct Subscription{
	pubsub: PubSub,
	channel_id: String,
	id: u64
}

impl Debug for Subscription{
	fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error>{
		fmt.write_str(&format!("Sub(channel={})", self.channel_id))
	}
}

impl Subscription{
	pub fn cancel(self){/* self is dropped */}

	pub fn notify_others(&self, msg: &str){
		self.pubsub.notify(&self.channel_id, msg, Some(self.id));
	}
}
impl Drop for Subscription{
	fn drop(&mut self){
		self.pubsub.unregister(self);
	}
}

pub struct SubActivator{
	sub: Subscription
}
impl SubActivator{
	pub fn activate<F>(self, func: F) -> Subscription
	where F: FnMut(String) + 'static + Send{
		self.sub.pubsub.activate(&self.sub.channel_id, self.sub.id, func);
		self.sub
	}
}

struct SubData{
	running: RAIIBool,
	backlog: VecDeque<String>,
	func: Option<Arc<Mutex<Box<FnMut(String) + Send>>>>
}

struct InnerPubSub{
	channels: HashMap<String, HashMap<u64, SubData>>,
	//id will stay unique for hundreds of years, even at ~1 billion/sec
	next_id: u64,
	thread_pool: Rc<ThreadPool>
}
#[derive(Clone)]
pub struct PubSub{
	inner: Arc<Mutex<InnerPubSub>>
}
unsafe impl Send for PubSub{}
unsafe impl Sync for PubSub{}

#[derive(Clone)]
pub struct RAIIBool{
	value: Arc<Mutex<bool>>
}
impl RAIIBool{
	fn new(value: bool) -> RAIIBool{
		RAIIBool{
			value: Arc::new(Mutex::new(value))
		}
	}
	fn get(&self) -> bool{
		*self.value.lock().unwrap()
	}
	fn set(&self, value: bool){
		*self.value.lock().unwrap() = value;
	}
	fn new_guard(&self, value: bool) -> RAIIBoolGuard{
		RAIIBoolGuard::new(self.clone(), value)
	}
}

pub struct RAIIBoolGuard{
	data: RAIIBool,
	value: bool
}
impl RAIIBoolGuard{
	fn new(data: RAIIBool, value: bool) -> RAIIBoolGuard{
		RAIIBoolGuard{
			data: data,
			value: value
		}
	}
	fn done(self){}
}
impl Drop for RAIIBoolGuard{
	fn drop(&mut self){
		self.data.set(self.value);
	}
}

impl PubSub{
	pub fn new(num_threads: usize) -> PubSub{
		PubSub{
			inner: Arc::new(Mutex::new(InnerPubSub{
				channels: HashMap::new(),
				next_id: 0,
				thread_pool: Rc::new(ThreadPool::new(num_threads))
			}))
		}
	}
	fn internal_subscribe<F>(&self, channel: &str, func: Option<F>) -> Subscription
	where F: FnMut(String) + 'static + Send{
		let mut data = self.inner.lock().unwrap();
		if !data.channels.contains_key(channel){
			data.channels.insert(channel.to_string(), HashMap::new());
		}
		let id = data.next_id;
		data.next_id += 1;
		let sub_data = SubData{
			running: RAIIBool::new(false),
			backlog: VecDeque::new(),
			func: func.map(|f|Arc::new(Mutex::new(Box::new(f) as Box<_>)))
		};

		let subscriptions = data.channels.get_mut(channel).unwrap();
		subscriptions.insert(id, sub_data);
		Subscription{
			pubsub: self.clone(),
			channel_id: channel.to_string(),
			id: id
		}
	}
	pub fn subscribe<F>(&self, channel: &str, func: F) -> Subscription
	where F: FnMut(String) + 'static + Send{
		self.internal_subscribe(channel, Some(func))
	}

	#[allow(unused_assignments)]
	pub fn lazy_subscribe(&self, channel: &str) -> SubActivator{
		let mut func = Some(|_|{});//used to give type info to 'func'
		func = None;
		SubActivator{
			sub: self.internal_subscribe(channel, func)
		}
	}
	fn activate<F>(&self, channel: &str, id: u64, func: F)
	where F: FnMut(String) + 'static + Send{
		let mut inner = self.inner.lock().unwrap();
		let pool = inner.thread_pool.clone();
		let subs = inner.channels.get_mut(channel).unwrap();//channel will always exist
		let sub_data = subs.get_mut(&id).unwrap();//sub id will always exist
		sub_data.func = Some(Arc::new(Mutex::new(Box::new(func))));
		self.schedule_worker(sub_data, channel, id, &pool);
	}
	pub fn num_channels(&self) -> usize{
		let data = self.inner.lock().unwrap();
		data.channels.len()
	}
	fn unregister(&self, sub: &Subscription){
		let mut inner = self.inner.lock().unwrap();
		let mut remove_channel = false;
		{
			let sub_list = inner.channels.get_mut(&sub.channel_id).unwrap();
			sub_list.remove(&sub.id);
			if sub_list.len() == 0{
				remove_channel = true;
			}
		}
		if remove_channel{
			inner.channels.remove(&sub.channel_id);
		}
	}
	fn schedule_worker(&self, sub_data: &mut SubData, channel: &str, id: u64, pool: &Rc<ThreadPool>){
		if !sub_data.running.get(){
			let thread_running = sub_data.running.clone();
			if let Some(func) = sub_data.func.clone(){
				thread_running.set(true);
				let pubsub = self.clone();
				let channel = channel.to_string();
				let id = id.clone();
				pool.execute(move ||{
					use std::ops::DerefMut;

					let finish_guard = thread_running.new_guard(false);
					let mut guard = func.lock().unwrap();
					let mut func = guard.deref_mut();
					let mut running = true;
					while running{
						let mut notification_message = None;
						{
							let mut inner = pubsub.inner.lock().unwrap();
							if let Some(subs) = inner.channels.get_mut(&channel){
								if let Some(sub_data) = subs.get_mut(&id){
									if let Some(msg) = sub_data.backlog.pop_front(){
										notification_message = Some(msg);
									}
								}
							}
						}//unlock 'inner'
						if let Some(msg) = notification_message{
							func(msg);
						}else{
							running = false;
						}
					}
					finish_guard.done();
				});
			}
		}
	}
	pub fn notify(&self, channel: &str, msg: &str, exception: Option<u64>){
		let mut inner = self.inner.lock().unwrap();
		let pool = inner.thread_pool.clone();
		if let Some(subscriptions) = inner.channels.get_mut(channel){
			for (id,sub_data) in subscriptions{
				if Some(*id) != exception{
					sub_data.backlog.push_back(msg.to_string());
					self.schedule_worker(sub_data, channel, *id, &pool);
				}
			}
		}
	}
}
<commit_msg>make RAIIBool and RAIIBoolGuard private<commit_after>extern crate threadpool;

use threadpool::ThreadPool;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::rc::Rc;
use std::fmt::{Formatter, Error, Debug};
use std::collections::vec_deque::VecDeque;

#[cfg(test)]
mod test;

pub struct Subscription{
	pubsub: PubSub,
	channel_id: String,
	id: u64
}

impl Debug for Subscription{
	fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error>{
		fmt.write_str(&format!("Sub(channel={})", self.channel_id))
	}
}

impl Subscription{
	pub fn cancel(self){/* self is dropped */}

	pub fn notify_others(&self, msg: &str){
		self.pubsub.notify(&self.channel_id, msg, Some(self.id));
	}
}
impl Drop for Subscription{
	fn drop(&mut self){
		self.pubsub.unregister(self);
	}
}

pub struct SubActivator{
	sub: Subscription
}
impl SubActivator{
	pub fn activate<F>(self, func: F) -> Subscription
	where F: FnMut(String) + 'static + Send{
		self.sub.pubsub.activate(&self.sub.channel_id, self.sub.id, func);
		self.sub
	}
}

struct SubData{
	running: RAIIBool,
	backlog: VecDeque<String>,
	func: Option<Arc<Mutex<Box<FnMut(String) + Send>>>>
}

struct InnerPubSub{
	channels: HashMap<String, HashMap<u64, SubData>>,
	//id will stay unique for hundreds of years, even at ~1 billion/sec
	next_id: u64,
	thread_pool: Rc<ThreadPool>
}
#[derive(Clone)]
pub struct PubSub{
	inner: Arc<Mutex<InnerPubSub>>
}
unsafe impl Send for PubSub{}
unsafe impl Sync for PubSub{}

#[derive(Clone)]
struct RAIIBool{
	value: Arc<Mutex<bool>>
}
impl RAIIBool{
	fn new(value: bool) -> RAIIBool{
		RAIIBool{
			value: Arc::new(Mutex::new(value))
		}
	}
	fn get(&self) -> bool{
		*self.value.lock().unwrap()
	}
	fn set(&self, value: bool){
		*self.value.lock().unwrap() = value;
	}
	fn new_guard(&self, value: bool) -> RAIIBoolGuard{
		RAIIBoolGuard::new(self.clone(), value)
	}
}

struct RAIIBoolGuard{
	data: RAIIBool,
	value: bool
}
impl RAIIBoolGuard{
	fn new(data: RAIIBool, value: bool) -> RAIIBoolGuard{
		RAIIBoolGuard{
			data: data,
			value: value
		}
	}
	fn done(self){}
}
impl Drop for RAIIBoolGuard{
	fn drop(&mut self){
		self.data.set(self.value);
	}
}

impl PubSub{
	pub fn new(num_threads: usize) -> PubSub{
		PubSub{
			inner: Arc::new(Mutex::new(InnerPubSub{
				channels: HashMap::new(),
				next_id: 0,
				thread_pool: Rc::new(ThreadPool::new(num_threads))
			}))
		}
	}
	fn internal_subscribe<F>(&self, channel: &str, func: Option<F>) -> Subscription
	where F: FnMut(String) + 'static + Send{
		let mut data = self.inner.lock().unwrap();
		if !data.channels.contains_key(channel){
			data.channels.insert(channel.to_string(), HashMap::new());
		}
		let id = data.next_id;
		data.next_id += 1;
		let sub_data = SubData{
			running: RAIIBool::new(false),
			backlog: VecDeque::new(),
			func: func.map(|f|Arc::new(Mutex::new(Box::new(f) as Box<_>)))
		};

		let subscriptions = data.channels.get_mut(channel).unwrap();
		subscriptions.insert(id, sub_data);
		Subscription{
			pubsub: self.clone(),
			channel_id: channel.to_string(),
			id: id
		}
	}
	pub fn subscribe<F>(&self, channel: &str, func: F) -> Subscription
	where F: FnMut(String) + 'static + Send{
		self.internal_subscribe(channel, Some(func))
	}

	#[allow(unused_assignments)]
	pub fn lazy_subscribe(&self, channel: &str) -> SubActivator{
		let mut func = Some(|_|{});//used to give type info to 'func'
		func = None;
		SubActivator{
			sub: self.internal_subscribe(channel, func)
		}
	}
	fn activate<F>(&self, channel: &str, id: u64, func: F)
	where F: FnMut(String) + 'static + Send{
		let mut inner = self.inner.lock().unwrap();
		let pool = inner.thread_pool.clone();
		let subs = inner.channels.get_mut(channel).unwrap();//channel will always exist
		let sub_data = subs.get_mut(&id).unwrap();//sub id will always exist
		sub_data.func = Some(Arc::new(Mutex::new(Box::new(func))));
		self.schedule_worker(sub_data, channel, id, &pool);
	}
	pub fn num_channels(&self) -> usize{
		let data = self.inner.lock().unwrap();
		data.channels.len()
	}
	fn unregister(&self, sub: &Subscription){
		let mut inner = self.inner.lock().unwrap();
		let mut remove_channel = false;
		{
			let sub_list = inner.channels.get_mut(&sub.channel_id).unwrap();
			sub_list.remove(&sub.id);
			if sub_list.len() == 0{
				remove_channel = true;
			}
		}
		if remove_channel{
			inner.channels.remove(&sub.channel_id);
		}
	}
	fn schedule_worker(&self, sub_data: &mut SubData, channel: &str, id: u64, pool: &Rc<ThreadPool>){
		if !sub_data.running.get(){
			let thread_running = sub_data.running.clone();
			if let Some(func) = sub_data.func.clone(){
				thread_running.set(true);
				let pubsub = self.clone();
				let channel = channel.to_string();
				let id = id.clone();
				pool.execute(move ||{
					use std::ops::DerefMut;

					let finish_guard = thread_running.new_guard(false);
					let mut guard = func.lock().unwrap();
					let mut func = guard.deref_mut();
					let mut running = true;
					while running{
						let mut notification_message = None;
						{
							let mut inner = pubsub.inner.lock().unwrap();
							if let Some(subs) = inner.channels.get_mut(&channel){
								if let Some(sub_data) = subs.get_mut(&id){
									if let Some(msg) = sub_data.backlog.pop_front(){
										notification_message = Some(msg);
									}
								}
							}
						}//unlock 'inner'
						if let Some(msg) = notification_message{
							func(msg);
						}else{
							running = false;
						}
					}
					finish_guard.done();
				});
			}
		}
	}
	pub fn notify(&self, channel: &str, msg: &str, exception: Option<u64>){
		let mut inner = self.inner.lock().unwrap();
		let pool = inner.thread_pool.clone();
		if let Some(subscriptions) = inner.channels.get_mut(channel){
			for (id,sub_data) in subscriptions{
				if Some(*id) != exception{
					sub_data.backlog.push_back(msg.to_string());
					self.schedule_worker(sub_data, channel, *id, &pool);
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>use std::io::Write;

struct WriterLog<W: Write> {
    writer: std::sync::Mutex<W>,
}

impl<W: Write + Send + Sync> WriterLog<W> {

    fn new(writer: W) -> WriterLog<W> {
        WriterLog { writer: std::sync::Mutex::new(writer) }
    }
}

impl<W: Write + Send + Sync> log::Log for WriterLog<W> {

    // TODO: Add support for log filtering. For now we just output everything as
    // there is no way to change the log verbosity.

    fn enabled(&self, _metadata: &log::Metadata) -> bool {
        true
    }

    fn log(&self, record: &log::Record) {
        let now = std::time::SystemTime::now();

        // We consider failures to write to the log stream critical. Otherwise,
        // if there is some other issue with the system it is not possible to
        // properly communicate it. Thus, we panic on all write errors.
        let mut writer = self.writer.lock()
            .expect("failed to acquire log output stream lock");

        || -> Result<(), std::io::Error> {
            write! {
                writer,
                "[{level} {timestamp} ",
                level = record.level(),
                timestamp = humantime::format_rfc3339_nanos(now)
            }?;
            match record.file() {
                Some(file) => write!(writer, "{file}")?,
                None => write!(writer, "<unknown>")?,
            }
            match record.line() {
                Some(line) => write!(writer, ":{line}]")?,
                None => write!(writer, ":<unknown>]")?,
            }

            write!(writer, " {}\n", record.args())?;

            Ok(())
        }().expect("failed to write to the log output stream")
    }

    fn flush(&self) {
        // Similarly to write errors, we also panic on flush errors as there is
        // nothing we can do otherwise.
        self.writer
            .lock()
            .expect("failed to acquire log output stream lock")
            .flush()
            .expect("failed to flush the log output stream");
    }
}

pub fn init(verbosity: log::LevelFilter) {
    use lazy_static::lazy_static;

    lazy_static! {
        static ref LOGGER: WriterLog<std::io::Stdout> = {
            WriterLog::new(std::io::stdout())
        };
    }

    log::set_logger(&*LOGGER)
        .expect("failed to initialize logger");

    log::set_max_level(verbosity);
}
<commit_msg>Create a wrapper for logging to multiple sources.<commit_after>use std::io::Write;

struct MultiLog {
    loggers: Vec<Box<dyn log::Log>>,
}

impl MultiLog {

    fn new() -> MultiLog {
        MultiLog {
            loggers: Vec::new(),
        }
    }

    fn push<L: log::Log + 'static>(&mut self, logger: L) {
        self.loggers.push(Box::new(logger));
    }
}

impl log::Log for MultiLog {

    fn enabled(&self, metadata: &log::Metadata) -> bool {
        self.loggers.iter().any(|logger| logger.enabled(metadata))
    }

    fn log(&self, record: &log::Record) {
        for log in &self.loggers {
            log.log(record);
        }
    }

    fn flush(&self) {
        for logger in &self.loggers {
            logger.flush();
        }
    }
}

struct WriterLog<W: Write> {
    writer: std::sync::Mutex<W>,
}

impl<W: Write + Send + Sync> WriterLog<W> {

    fn new(writer: W) -> WriterLog<W> {
        WriterLog { writer: std::sync::Mutex::new(writer) }
    }
}

impl<W: Write + Send + Sync> log::Log for WriterLog<W> {

    // TODO: Add support for log filtering. For now we just output everything as
    // there is no way to change the log verbosity.

    fn enabled(&self, _metadata: &log::Metadata) -> bool {
        true
    }

    fn log(&self, record: &log::Record) {
        let now = std::time::SystemTime::now();

        // We consider failures to write to the log stream critical. Otherwise,
        // if there is some other issue with the system it is not possible to
        // properly communicate it. Thus, we panic on all write errors.
        let mut writer = self.writer.lock()
            .expect("failed to acquire log output stream lock");

        || -> Result<(), std::io::Error> {
            write! {
                writer,
                "[{level} {timestamp} ",
                level = record.level(),
                timestamp = humantime::format_rfc3339_nanos(now)
            }?;
            match record.file() {
                Some(file) => write!(writer, "{file}")?,
                None => write!(writer, "<unknown>")?,
            }
            match record.line() {
                Some(line) => write!(writer, ":{line}]")?,
                None => write!(writer, ":<unknown>]")?,
            }

            write!(writer, " {}\n", record.args())?;

            Ok(())
        }().expect("failed to write to the log output stream")
    }

    fn flush(&self) {
        // Similarly to write errors, we also panic on flush errors as there is
        // nothing we can do otherwise.
        self.writer
            .lock()
            .expect("failed to acquire log output stream lock")
            .flush()
            .expect("failed to flush the log output stream");
    }
}

pub fn init(verbosity: log::LevelFilter) {
    use lazy_static::lazy_static;

    lazy_static! {
        static ref LOGGER: WriterLog<std::io::Stdout> = {
            WriterLog::new(std::io::stdout())
        };
    }

    log::set_logger(&*LOGGER)
        .expect("failed to initialize logger");

    log::set_max_level(verbosity);
}
<|endoftext|>


<commit_before>#![feature(phase)]

#![unstable]

#[macro_use]
#[no_link]
extern crate compile_msg;

extern crate libc;

use std::ffi::{CString};
use std::sync::mpsc::{Sender};
use std::sync::Mutex;
use std::thread::Thread;

#[doc(hidden)]
pub mod ffi;

/// This static variable  will store the android_app* on creation, and set it back to 0 at
///  destruction.
/// Apart from this, the static is never written, so there is no risk of race condition.
static mut ANDROID_APP: *mut ffi::android_app = 0 as *mut ffi::android_app;

/// This is the structure that serves as user data in the android_app*
#[doc(hidden)]
struct Context {
    senders: Mutex<Vec<Sender<Event>>>,
}

/// An event triggered by the Android environment.
pub enum Event {
    EventUp,
    EventDown,
    EventMove(i32, i32),
}

impl Copy for Event {}

#[cfg(not(target_os = "android"))]
compile_note!("You are not compiling for Android");

#[macro_export]
macro_rules! android_start(
    ($main: ident) => (
        pub mod __android_start {
            extern crate android_glue;

            // this function is here because we are sure that it will be included by the linker
            // so we call app_dummy in it, in order to be sure that the native glue will be included
            #[start]
            pub fn start(_: int, _: *const *const u8) -> int {
                unsafe { android_glue::ffi::app_dummy() };
                1
            }

            #[no_mangle]
            #[inline(never)]
            #[allow(non_snake_case)]
            pub extern "C" fn android_main(app: *mut ()) {
                android_glue::android_main2(app, move|| super::$main());
            }
        }
    )
);

/// This is the function that must be called by `android_main`
#[doc(hidden)]
pub fn android_main2<F>(app: *mut (), main_function: F)
    where F: FnOnce(), F: Send
{
    use std::{mem, ptr};

    write_log("Entering android_main");

    unsafe { ANDROID_APP = std::mem::transmute(app) };
    let app: &mut ffi::android_app = unsafe { std::mem::transmute(app) };

    // creating the context that will be passed to the callback
    let context = Context { senders: Mutex::new(Vec::new()) };
    app.onAppCmd = commands_callback;
    app.onInputEvent = inputs_callback;
    app.userData = unsafe { std::mem::transmute(&context) };

    // executing the main function in parallel
    let g = Thread::spawn(move|| {
        std::io::stdio::set_stdout(box std::io::LineBufferedWriter::new(ToLogWriter));
        std::io::stdio::set_stderr(box std::io::LineBufferedWriter::new(ToLogWriter));
        main_function()
    });

    // polling for events forever
    // note that this must be done in the same thread as android_main because ALooper are
    //  thread-local
    unsafe {
        loop {
            let mut events = mem::uninitialized();
            let mut source = mem::uninitialized();

            // passing -1 means that we are blocking
            let ident = ffi::ALooper_pollAll(-1, ptr::null_mut(), &mut events,
                &mut source);

            // processing the event
            if !source.is_null() {
                let source: *mut ffi::android_poll_source = mem::transmute(source);
                ((*source).process)(ANDROID_APP, source);
            }
        }
    }

    // terminating the application
    unsafe { ANDROID_APP = 0 as *mut ffi::android_app };
}

/// Writer that will redirect what is written to it to the logs.
struct ToLogWriter;

impl Writer for ToLogWriter {
    fn write(&mut self, buf: &[u8]) -> std::io::IoResult<()> {
        let message = CString::from_slice(buf).as_slice_with_nul().as_ptr();
        let tag = b"RustAndroidGlueStdouterr";
        let tag = CString::from_slice(tag).as_slice_with_nul().as_ptr();
        unsafe { ffi::__android_log_write(3, tag, message) };
        Ok(())
    }
}

/// The callback for inputs.
pub extern fn inputs_callback(_: *mut ffi::android_app, event: *const ffi::AInputEvent)
    -> libc::int32_t
{
    fn send_event(event: Event) {
        let senders = get_context().senders.lock().ok().unwrap();
        for sender in senders.iter() {
            sender.send(event);
        }
    }
    let action = unsafe { ffi::AMotionEvent_getAction(event) };
    let action_code = action & ffi::AMOTION_EVENT_ACTION_MASK;
    match action_code {
        ffi::AMOTION_EVENT_ACTION_UP
            | ffi::AMOTION_EVENT_ACTION_OUTSIDE
            | ffi::AMOTION_EVENT_ACTION_CANCEL
            | ffi::AMOTION_EVENT_ACTION_POINTER_UP =>
        {
            send_event(Event::EventUp);
        },
        ffi::AMOTION_EVENT_ACTION_DOWN
            | ffi::AMOTION_EVENT_ACTION_POINTER_DOWN =>
        {
            send_event(Event::EventDown);
        },
        _ => {
            let x = unsafe { ffi::AMotionEvent_getX(event, 0) };
            let y = unsafe { ffi::AMotionEvent_getY(event, 0) };
            send_event(Event::EventMove(x as i32, y as i32));
        },
    }
    0
}

/// The callback for commands.
#[doc(hidden)]
pub extern fn commands_callback(_: *mut ffi::android_app, command: libc::int32_t) {
    let context = get_context();

    match command {
        ffi::APP_CMD_INIT_WINDOW => {

        },

        ffi::APP_CMD_SAVE_STATE => {

        },

        ffi::APP_CMD_TERM_WINDOW => {

        },

        ffi::APP_CMD_GAINED_FOCUS => {

        },

        ffi::APP_CMD_LOST_FOCUS => {

        },

        _ => ()
    }
}

/// Returns the current Context.
fn get_context() -> &'static Context {
    let context = unsafe { (*ANDROID_APP).userData };
    unsafe { std::mem::transmute(context) }
}

/// Adds a sender where events will be sent to.
pub fn add_sender(sender: Sender<Event>) {
    get_context().senders.lock().ok().unwrap().push(sender);
}

/// Returns a handle to the native window.
pub unsafe fn get_native_window() -> ffi::NativeWindowType {
    if ANDROID_APP.is_null() {
        panic!("The application was not initialized from android_main");
    }

    loop {
        let value = (*ANDROID_APP).window;
        if !value.is_null() {
            return value;
        }

        // spin-locking
        std::io::timer::sleep(std::time::Duration::milliseconds(10));
    }
}

///
pub fn write_log(message: &str) {
    let message = message.as_bytes();
    let message = CString::from_slice(message).as_slice_with_nul().as_ptr();
    let tag = b"RustAndroidGlueStdouterr";
    let tag = CString::from_slice(tag).as_slice_with_nul().as_ptr();
    unsafe { ffi::__android_log_write(3, tag, message) };
}
<commit_msg>Updated for Rust alpha 1.0 (44a287e6e 2015-01-08 17:03:40)<commit_after>#![feature(box_syntax)]

#![unstable]

#[macro_use]
#[no_link]
extern crate compile_msg;

extern crate libc;

use std::ffi::{CString};
use std::sync::mpsc::{Sender};
use std::sync::Mutex;
use std::thread::Thread;

#[doc(hidden)]
pub mod ffi;

/// This static variable  will store the android_app* on creation, and set it back to 0 at
///  destruction.
/// Apart from this, the static is never written, so there is no risk of race condition.
static mut ANDROID_APP: *mut ffi::android_app = 0 as *mut ffi::android_app;

/// This is the structure that serves as user data in the android_app*
#[doc(hidden)]
struct Context {
    senders: Mutex<Vec<Sender<Event>>>,
}

/// An event triggered by the Android environment.
pub enum Event {
    EventUp,
    EventDown,
    EventMove(i32, i32),
}

impl Copy for Event {}

#[cfg(not(target_os = "android"))]
compile_note!("You are not compiling for Android");

#[macro_export]
macro_rules! android_start(
    ($main: ident) => (
        pub mod __android_start {
            extern crate android_glue;

            // this function is here because we are sure that it will be included by the linker
            // so we call app_dummy in it, in order to be sure that the native glue will be included
            #[start]
            pub fn start(_: int, _: *const *const u8) -> int {
                unsafe { android_glue::ffi::app_dummy() };
                1
            }

            #[no_mangle]
            #[inline(never)]
            #[allow(non_snake_case)]
            pub extern "C" fn android_main(app: *mut ()) {
                android_glue::android_main2(app, move|| super::$main());
            }
        }
    )
);

/// This is the function that must be called by `android_main`
#[doc(hidden)]
pub fn android_main2<F>(app: *mut (), main_function: F)
    where F: FnOnce(), F: Send
{
    use std::{mem, ptr};

    write_log("Entering android_main");

    unsafe { ANDROID_APP = std::mem::transmute(app) };
    let app: &mut ffi::android_app = unsafe { std::mem::transmute(app) };

    // creating the context that will be passed to the callback
    let context = Context { senders: Mutex::new(Vec::new()) };
    app.onAppCmd = commands_callback;
    app.onInputEvent = inputs_callback;
    app.userData = unsafe { std::mem::transmute(&context) };

    // executing the main function in parallel
    let g = Thread::spawn(move|| {
        std::io::stdio::set_stdout(box std::io::LineBufferedWriter::new(ToLogWriter));
        std::io::stdio::set_stderr(box std::io::LineBufferedWriter::new(ToLogWriter));
        main_function()
    });

    // polling for events forever
    // note that this must be done in the same thread as android_main because ALooper are
    //  thread-local
    unsafe {
        loop {
            let mut events = mem::uninitialized();
            let mut source = mem::uninitialized();

            // passing -1 means that we are blocking
            let ident = ffi::ALooper_pollAll(-1, ptr::null_mut(), &mut events,
                &mut source);

            // processing the event
            if !source.is_null() {
                let source: *mut ffi::android_poll_source = mem::transmute(source);
                ((*source).process)(ANDROID_APP, source);
            }
        }
    }

    // terminating the application
    unsafe { ANDROID_APP = 0 as *mut ffi::android_app };
}

/// Writer that will redirect what is written to it to the logs.
struct ToLogWriter;

impl Writer for ToLogWriter {
    fn write(&mut self, buf: &[u8]) -> std::io::IoResult<()> {
        let message = CString::from_slice(buf).as_slice_with_nul().as_ptr();
        let tag = b"RustAndroidGlueStdouterr";
        let tag = CString::from_slice(tag).as_slice_with_nul().as_ptr();
        unsafe { ffi::__android_log_write(3, tag, message) };
        Ok(())
    }
}

/// The callback for inputs.
pub extern fn inputs_callback(_: *mut ffi::android_app, event: *const ffi::AInputEvent)
    -> libc::int32_t
{
    fn send_event(event: Event) {
        let senders = get_context().senders.lock().ok().unwrap();
        for sender in senders.iter() {
            sender.send(event);
        }
    }
    let action = unsafe { ffi::AMotionEvent_getAction(event) };
    let action_code = action & ffi::AMOTION_EVENT_ACTION_MASK;
    match action_code {
        ffi::AMOTION_EVENT_ACTION_UP
            | ffi::AMOTION_EVENT_ACTION_OUTSIDE
            | ffi::AMOTION_EVENT_ACTION_CANCEL
            | ffi::AMOTION_EVENT_ACTION_POINTER_UP =>
        {
            send_event(Event::EventUp);
        },
        ffi::AMOTION_EVENT_ACTION_DOWN
            | ffi::AMOTION_EVENT_ACTION_POINTER_DOWN =>
        {
            send_event(Event::EventDown);
        },
        _ => {
            let x = unsafe { ffi::AMotionEvent_getX(event, 0) };
            let y = unsafe { ffi::AMotionEvent_getY(event, 0) };
            send_event(Event::EventMove(x as i32, y as i32));
        },
    }
    0
}

/// The callback for commands.
#[doc(hidden)]
pub extern fn commands_callback(_: *mut ffi::android_app, command: libc::int32_t) {
    let context = get_context();

    match command {
        ffi::APP_CMD_INIT_WINDOW => {

        },

        ffi::APP_CMD_SAVE_STATE => {

        },

        ffi::APP_CMD_TERM_WINDOW => {

        },

        ffi::APP_CMD_GAINED_FOCUS => {

        },

        ffi::APP_CMD_LOST_FOCUS => {

        },

        _ => ()
    }
}

/// Returns the current Context.
fn get_context() -> &'static Context {
    let context = unsafe { (*ANDROID_APP).userData };
    unsafe { std::mem::transmute(context) }
}

/// Adds a sender where events will be sent to.
pub fn add_sender(sender: Sender<Event>) {
    get_context().senders.lock().ok().unwrap().push(sender);
}

/// Returns a handle to the native window.
pub unsafe fn get_native_window() -> ffi::NativeWindowType {
    if ANDROID_APP.is_null() {
        panic!("The application was not initialized from android_main");
    }

    loop {
        let value = (*ANDROID_APP).window;
        if !value.is_null() {
            return value;
        }

        // spin-locking
        std::io::timer::sleep(std::time::Duration::milliseconds(10));
    }
}

///
pub fn write_log(message: &str) {
    let message = message.as_bytes();
    let message = CString::from_slice(message).as_slice_with_nul().as_ptr();
    let tag = b"RustAndroidGlueStdouterr";
    let tag = CString::from_slice(tag).as_slice_with_nul().as_ptr();
    unsafe { ffi::__android_log_write(3, tag, message) };
}
<|endoftext|>


<commit_before>use security_framework::certificate::SecCertificate;
use security_framework::policy::SecPolicy;
use security_framework::secure_transport::ProtocolSide;
use security_framework::trust::SecTrust;

pub fn validate_cert_chain(encoded_certs: Vec<&[u8]>, hostname: &str) -> bool {
    let mut certs = Vec::new();
    for encoded_cert in encoded_certs {
        let cert = SecCertificate::from_der(encoded_cert);
        match cert {
            Ok(cert) => certs.push(cert),
            Err(_) => return false,
        }
    }

    let ssl_policy = fail_on_error!(SecPolicy::for_ssl(ProtocolSide::Client, hostname));
    let trust = fail_on_error!(SecTrust::create_with_certificates(&certs[..], &[ssl_policy]));

    // Deliberately swallow errors here: any error is likely to do with the
    // hostname or cert chain, and if those are invalid then by definition the
    // cert does not validate.
    match trust.evaluate() {
        Ok(result) => result.success(),
        Err(_) => false
    }
}

#[cfg(test)]
mod test {
    use os_x::validate_cert_chain;

    fn certifi_chain() -> Vec<&'static[u8]> {
        let leaf = include_bytes!("../fixtures/certifi-leaf.crt");
        let first_inter = include_bytes!("../fixtures/certifi-first-intermediate.crt");
        let second_inter = include_bytes!("../fixtures/certifi-second-intermediate.crt");

        vec![leaf, first_inter, second_inter]
    }

    #[test]
    fn can_validate_good_chain() {
        let chain = certifi_chain();
        let valid = validate_cert_chain(chain, "certifi.io");
        assert_eq!(valid, true);
    }

    #[test]
    fn fails_on_bad_hostname() {
        let chain = certifi_chain();
        let valid = validate_cert_chain(chain, "lukasa.co.uk");
        assert_eq!(valid, false);
    }

    #[test]
    fn fails_on_bad_cert() {
        let mut good_chain = certifi_chain();
        let originals = good_chain.split_first_mut().unwrap();
        let leaf = originals.0;
        let intermediates = originals.1;

        // Deliberately truncate the leaf cert.
        let mut certs = vec![&leaf[1..50]];
        certs.extend(intermediates.iter());
        let valid = validate_cert_chain(certs, "certifi.io");
        assert_eq!(valid, false);
    }
}
<commit_msg>Fixup test module name.<commit_after>use security_framework::certificate::SecCertificate;
use security_framework::policy::SecPolicy;
use security_framework::secure_transport::ProtocolSide;
use security_framework::trust::SecTrust;

pub fn validate_cert_chain(encoded_certs: Vec<&[u8]>, hostname: &str) -> bool {
    let mut certs = Vec::new();
    for encoded_cert in encoded_certs {
        let cert = SecCertificate::from_der(encoded_cert);
        match cert {
            Ok(cert) => certs.push(cert),
            Err(_) => return false,
        }
    }

    let ssl_policy = fail_on_error!(SecPolicy::for_ssl(ProtocolSide::Client, hostname));
    let trust = fail_on_error!(SecTrust::create_with_certificates(&certs[..], &[ssl_policy]));

    // Deliberately swallow errors here: any error is likely to do with the
    // hostname or cert chain, and if those are invalid then by definition the
    // cert does not validate.
    match trust.evaluate() {
        Ok(result) => result.success(),
        Err(_) => false
    }
}

#[cfg(test)]
mod test {
    use osx::validate_cert_chain;

    fn certifi_chain() -> Vec<&'static[u8]> {
        let leaf = include_bytes!("../fixtures/certifi-leaf.crt");
        let first_inter = include_bytes!("../fixtures/certifi-first-intermediate.crt");
        let second_inter = include_bytes!("../fixtures/certifi-second-intermediate.crt");

        vec![leaf, first_inter, second_inter]
    }

    #[test]
    fn can_validate_good_chain() {
        let chain = certifi_chain();
        let valid = validate_cert_chain(chain, "certifi.io");
        assert_eq!(valid, true);
    }

    #[test]
    fn fails_on_bad_hostname() {
        let chain = certifi_chain();
        let valid = validate_cert_chain(chain, "lukasa.co.uk");
        assert_eq!(valid, false);
    }

    #[test]
    fn fails_on_bad_cert() {
        let mut good_chain = certifi_chain();
        let originals = good_chain.split_first_mut().unwrap();
        let leaf = originals.0;
        let intermediates = originals.1;

        // Deliberately truncate the leaf cert.
        let mut certs = vec![&leaf[1..50]];
        certs.extend(intermediates.iter());
        let valid = validate_cert_chain(certs, "certifi.io");
        assert_eq!(valid, false);
    }
}
<|endoftext|>


<commit_before>/*
 * PIC emulation
 */

use vm;

use std::rc::Rc;
use std::cell::RefCell;

const PIC_MASTER_CMD: u16 = 0x20;
const PIC_MASTER_DATA: u16 = 0x21;
const PIC_SLAVE_CMD: u16 = 0xA0;
const PIC_SLAVE_DATA: u16 = 0xA1;

const ICW1_INIT: u8 = 0x10;
const ICW1_ICW4: u8 = 0x01;
const ICW4_8086: u8 = 0x01;

const PIC_READ_IRR: u8 = 0x0A;
const PIC_READ_ISR: u8 = 0x0B;
const PIC_EOI: u8 = 0x20;

/**
 * i8259 PIC chip
 */
struct I8259A
{
    irr: u8,    // IRR register
    isr: u8,    // ISR register
    imr: u8,    // IRQ mask
    offset: u8, // Interrupt vector base
    icw3: u8,   // ICW3 value during initialization (cascade IRQ)
    next_icw: usize,    // During init, next ICW word expected during init
    cmd_latch: u8,      // Latched value to be read next time from command port
}

impl I8259A
{
    fn default() -> I8259A {
        I8259A {
            irr: 0,
            isr: 0,
            imr: 0,
            offset: 0,
            icw3: 0,
            next_icw: 0,
            cmd_latch: 0,
        }
    }

    fn is_initialized(&self) -> bool {
        self.next_icw == 1
    }

    fn slave_irq(&self) -> u8 {
        self.icw3
    }

    /* Assert an IRQ line */
    fn assert_irq(&mut self, irq: u8) {
        assert!(irq < 8);

        if !self.is_initialized() {
            return;
        }

        let mask = 1u8 << irq;
        if (self.imr & mask) != 0 {
            return;
        }

        /* We only update IRR here because we're not sure when
         * interrupt event is going to be injected in guest.
         * So ISR will be updated once guest will try to access it */
        self.irr |= mask;

        /* Notify VM state we need to inject this vector */
        vm::raise_external_interrupt(irq + self.offset);
    }

    /* Write to command port */
    fn write_command(&mut self, cmd: u8) {
        if cmd & ICW1_INIT != 0 {
            /* Start initialization
             * We support only ICW1 + ICW4 (and ICW4 should set 8086 tyoe) */
            assert!(cmd & !(ICW1_INIT | ICW1_ICW4) == 0);
            self.next_icw = 2;
            self.imr = 0;

            /* What happens to raised but not yet injected guest interrupts at this point?
             * Intel spec is not entirely clear on that regard, however continuing to deliver
             * those interrupts can be bad since guest might now change IRQ offsets
             * and, accordingly, it's IDT.
             *
             * We can't yet reinject any of those interrupts since we don't know new offsets, so we
             * do that in following steps:
             * 1. Cancel any interrupts that might have been raised according to our current IRR.
             *    Don't touch IRR value.
             * 2. Upon completed init reinject all pending IRR interrupts with updated offsets.
             */
            if self.irr != 0 {
                vm::cancel_all_external_interrupts();
            }

            /* Also, what if an interrupt was delivered (ISR != 0) but not EOI-ed by the guest?
             * Stricktly speaking this is a guest bug.
             * It might deliver a racy EOI after init so let's keep ISR hanging as well */
        } else if cmd == PIC_READ_IRR {
            self.cmd_latch = self.irr;
        } else if cmd == PIC_READ_ISR {
            self.cmd_latch = self.isr;
        } else if cmd == PIC_EOI {
            if self.isr != 0 {
                /* TODO: abstract away (and optimize) bsf */
                let mut isr = self.isr;
                let mut pos = 0;
                while (isr & 0x1) == 0 {
                    pos += 1;
                    isr >>= 1;
                }

                self.isr = self.isr & !(1 << pos);
            }
        } else {
            debug!("Unsupported PIC command {:x}", cmd);
        }
    }

    /* Read from command port */
    fn read_command(&mut self) -> u8 {
        return self.cmd_latch;
    }

    /* Write to data port */
    fn write_data(&mut self, data: u8) {
        match self.next_icw {
            2 => {
                self.offset = data;
                self.next_icw = 3;
            },

            3 => {
                self.icw3 = data;
                self.next_icw = 4;
            },

            4 => {
                assert!(data == ICW4_8086); /* Just check that ICW4 is the only one we support */
                self.next_icw = 1; /* Init sequence complete */

                /* Re-inject pre-reset pending interrupts from IRR.
                 * See comments in write_command ICW1 */
                for i in 0..8 {
                    if (self.irr & (1_u8 << i)) != 0 {
                        vm::raise_external_interrupt(i + self.offset);
                    }
                }
            },

            _ => {
                self.imr = data; /* Outside init sequence all writes go to IMR by default */
            }
        }
    }

    /* Read from data port */
    fn read_data(&mut self) -> u8 {
        self.imr
    }
}

/**
 * Cascade PIC setup
 */
struct PIC
{
    master: I8259A,
    slave: I8259A,
}

impl PIC
{
    fn new() -> PIC {
        PIC {
            master: I8259A::default(),
            slave: I8259A::default(),
        }
    }

    fn assert_irq(&mut self, irq: u8) {
        assert!(irq <= 15);
        if irq < 8 {
            self.master.assert_irq(irq);
        } else {
            let slave_irq = self.master.slave_irq();
            self.master.assert_irq(slave_irq);
            self.slave.assert_irq(irq - 8);
        }
    }

    fn ack(&mut self, vec: u8) {
        unimplemented!();
    }
}

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

#[cfg(test)]
mod i8259a_test
{
    use super::I8259A;

    fn init_common(offset: u8, mask: u8, cascade: u8) -> I8259A {
        let mut dev = I8259A::default();
        assert!(!dev.is_initialized());

        dev.write_command(super::ICW1_INIT | super::ICW1_ICW4);
        assert!(!dev.is_initialized());

        dev.write_data(offset);
        assert!(!dev.is_initialized());

        dev.write_data(cascade);
        assert!(!dev.is_initialized());

        dev.write_data(super::ICW4_8086);
        assert!(dev.is_initialized());

        dev.write_data(mask);
        assert!(dev.read_data() == mask);

        return dev;
    }

    /* Init with ICW4 */
    #[test] fn init() {
        let dev = init_common(0x08, 0xAB, 0x02);
        assert!(dev.is_initialized());
    }
}

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

struct PICDev
{
    pic: RefCell<PIC>,
}

impl vm::io_handler for PICDev
{
    fn io_read(&self, port: u16, size: u8) -> vm::IoOperandType
    {
        assert!(size == 1);

        let mut dev = self.pic.borrow_mut();
        vm::IoOperandType::byte(
            match port {
                PIC_MASTER_DATA => dev.master.read_data(),
                PIC_MASTER_CMD => dev.master.read_command(),

                PIC_SLAVE_DATA => dev.slave.read_data(),
                PIC_SLAVE_CMD => dev.slave.read_command(),

                _ => 0,
            }
        )
    }

    fn io_write(&self, port: u16, data: vm::IoOperandType)
    {
        let mut dev = self.pic.borrow_mut();
        let data8 = data.unwrap_byte();

        match port {
            PIC_MASTER_DATA => dev.master.write_data(data8),
            PIC_MASTER_CMD => dev.master.write_command(data8),

            PIC_SLAVE_DATA => dev.slave.write_data(data8),
            PIC_SLAVE_CMD => dev.slave.write_command(data8),

            _ => panic!(),
        }
    }
}

impl vm::interrupt_controller for PICDev
{
    fn assert_irq(&self, irq: u8)
    {
        let mut dev = self.pic.borrow_mut();
        dev.assert_irq(irq)
    }

    fn ack(&self, vec: u8)
    {
        let mut dev = self.pic.borrow_mut();
        dev.ack(vec)
    }
}

pub fn init()
{
	let dev = Rc::new(PICDev {
        pic: RefCell::new(PIC::new()),
    });

    vm::register_interrupt_controller(dev.clone());

    vm::register_io_region(dev.clone(), PIC_MASTER_CMD, 1);
    vm::register_io_region(dev.clone(), PIC_MASTER_DATA, 1);
    vm::register_io_region(dev.clone(), PIC_SLAVE_CMD, 1);
    vm::register_io_region(dev.clone(), PIC_SLAVE_DATA, 1);
}

<commit_msg>PIC: Interrupt ACK and EOI<commit_after>/*
 * PIC emulation
 */

use vm;

use std::rc::Rc;
use std::cell::RefCell;

const PIC_MASTER_CMD: u16 = 0x20;
const PIC_MASTER_DATA: u16 = 0x21;
const PIC_SLAVE_CMD: u16 = 0xA0;
const PIC_SLAVE_DATA: u16 = 0xA1;

const ICW1_INIT: u8 = 0x10;
const ICW1_ICW4: u8 = 0x01;
const ICW4_8086: u8 = 0x01;

const PIC_READ_IRR: u8 = 0x0A;
const PIC_READ_ISR: u8 = 0x0B;
const PIC_EOI: u8 = 0x20;

/**
 * i8259 PIC chip
 */
struct I8259A
{
    irr: u8,    // IRR register
    isr: u8,    // ISR register
    imr: u8,    // IRQ mask
    offset: u8, // Interrupt vector base
    icw3: u8,   // ICW3 value during initialization (cascade IRQ)
    next_icw: usize,    // During init, next ICW word expected during init
    cmd_latch: u8,      // Latched value to be read next time from command port
}

impl I8259A
{
    fn default() -> I8259A {
        I8259A {
            irr: 0,
            isr: 0,
            imr: 0,
            offset: 0,
            icw3: 0,
            next_icw: 0,
            cmd_latch: 0,
        }
    }

    fn is_initialized(&self) -> bool {
        self.next_icw == 1
    }

    fn slave_irq(&self) -> u8 {
        self.icw3
    }

    /* Assert an IRQ line */
    fn assert_irq(&mut self, irq: u8) {
        assert!(irq < 8);

        if !self.is_initialized() {
            return;
        }

        let mask = 1u8 << irq;
        if (self.imr & mask) != 0 {
            return;
        }

        /* We only update IRR here because we're not sure when
         * interrupt event is going to be injected in guest.
         * That what ack is for. */
        self.irr |= mask;

        /* Notify VM state we need to inject this vector */
        vm::raise_external_interrupt(irq + self.offset);
    }

    /* Acknowledge interrupt delivery to guest */
    fn ack(&mut self, vec: u8) {
        assert!(vec >= self.offset);
        let irq = vec - self.offset;

        /* Acked bit should be in IRR */
        assert!(0 != (self.irr & (1_u8 << irq)));

        /* Move IRR bit to ISR */
        self.isr |= 1_u8 << irq;
        self.irr &= !(1_u8 << irq);
    }

    /* Write to command port */
    fn write_command(&mut self, cmd: u8) {
        if cmd & ICW1_INIT != 0 {
            /* Start initialization
             * We support only ICW1 + ICW4 (and ICW4 should set 8086 tyoe) */
            assert!(cmd & !(ICW1_INIT | ICW1_ICW4) == 0);
            self.next_icw = 2;
            self.imr = 0;

            /* What happens to raised but not yet injected guest interrupts at this point?
             * Intel spec is not entirely clear on that regard, however continuing to deliver
             * those interrupts can be bad since guest might now change IRQ offsets
             * and, accordingly, it's IDT.
             *
             * We can't yet reinject any of those interrupts since we don't know new offsets, so we
             * do that in following steps:
             * 1. Cancel any interrupts that might have been raised according to our current IRR.
             *    Don't touch IRR value.
             * 2. Upon completed init reinject all pending IRR interrupts with updated offsets.
             */
            if self.irr != 0 {
                vm::cancel_all_external_interrupts();
            }

            /* Also, what if an interrupt was delivered (ISR != 0) but not EOI-ed by the guest?
             * Strictly speaking this is a guest bug.
             * It might deliver a racy EOI after init so let's keep ISR hanging as well */
        } else if cmd == PIC_READ_IRR {
            self.cmd_latch = self.irr;
        } else if cmd == PIC_READ_ISR {
            self.cmd_latch = self.isr;
        } else if cmd == PIC_EOI {
            if self.isr != 0 {
                /* TODO: abstract away (and optimize) bsf */
                let mut isr = self.isr;
                let mut pos = 0;
                while (isr & 0x1) == 0 {
                    pos += 1;
                    isr >>= 1;
                }

                self.isr = self.isr & !(1 << pos);
            }
        } else {
            debug!("Unsupported PIC command {:x}", cmd);
        }
    }

    /* Read from command port */
    fn read_command(&mut self) -> u8 {
        return self.cmd_latch;
    }

    /* Read from data port */
    fn read_data(&mut self) -> u8 {
        self.imr
    }

    /* Write to data port */
    fn write_data(&mut self, data: u8) {
        match self.next_icw {
            2 => {
                self.offset = data;
                self.next_icw = 3;
            },

            3 => {
                self.icw3 = data;
                self.next_icw = 4;
            },

            4 => {
                assert!(data == ICW4_8086); /* Just check that ICW4 is the only one we support */
                self.next_icw = 1; /* Init sequence complete */

                /* Re-inject pre-reset pending interrupts from IRR.
                 * See comments in write_command ICW1 */
                for i in 0..8 {
                    if (self.irr & (1_u8 << i)) != 0 {
                        vm::raise_external_interrupt(i + self.offset);
                    }
                }
            },

            _ => {
                self.imr = data; /* Outside init sequence all writes go to IMR by default */
            }
        }
    }
}

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

/**
 * Cascade PIC setup
 */
struct PIC
{
    master: I8259A,
    slave: I8259A,
}

impl PIC
{
    fn new() -> PIC {
        PIC {
            master: I8259A::default(),
            slave: I8259A::default(),
        }
    }

    fn assert_irq(&mut self, irq: u8) {
        assert!(irq <= 15);
        if irq < 8 {
            self.master.assert_irq(irq);
        } else {
            let slave_irq = self.master.slave_irq();
            self.master.assert_irq(slave_irq);
            self.slave.assert_irq(irq - 8);
        }
    }

    fn ack(&mut self, vec: u8) {
        if vec >= self.slave.offset {
            self.slave.ack(vec);
        } else {
            self.master.ack(vec);
        }
    }
}

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

#[cfg(test)]
mod i8259a_test
{
    use super::I8259A;

    fn init_common(offset: u8, mask: u8, cascade: u8) -> I8259A {
        let mut dev = I8259A::default();
        assert!(!dev.is_initialized());

        dev.write_command(super::ICW1_INIT | super::ICW1_ICW4);
        assert!(!dev.is_initialized());

        dev.write_data(offset);
        assert!(!dev.is_initialized());

        dev.write_data(cascade);
        assert!(!dev.is_initialized());

        dev.write_data(super::ICW4_8086);
        assert!(dev.is_initialized());

        dev.write_data(mask);
        assert!(dev.read_data() == mask);

        return dev;
    }

    /* Init with ICW4 */
    #[test] fn init() {
        let dev = init_common(0x08, 0xAB, 0x02);
        assert!(dev.is_initialized());
    }
}

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

struct PICDev
{
    pic: RefCell<PIC>,
}

impl vm::io_handler for PICDev
{
    fn io_read(&self, port: u16, size: u8) -> vm::IoOperandType
    {
        assert!(size == 1);

        let mut dev = self.pic.borrow_mut();
        vm::IoOperandType::byte(
            match port {
                PIC_MASTER_DATA => dev.master.read_data(),
                PIC_MASTER_CMD => dev.master.read_command(),

                PIC_SLAVE_DATA => dev.slave.read_data(),
                PIC_SLAVE_CMD => dev.slave.read_command(),

                _ => 0,
            }
        )
    }

    fn io_write(&self, port: u16, data: vm::IoOperandType)
    {
        let mut dev = self.pic.borrow_mut();
        let data8 = data.unwrap_byte();

        match port {
            PIC_MASTER_DATA => dev.master.write_data(data8),
            PIC_MASTER_CMD => dev.master.write_command(data8),

            PIC_SLAVE_DATA => dev.slave.write_data(data8),
            PIC_SLAVE_CMD => dev.slave.write_command(data8),

            _ => panic!(),
        }
    }
}

impl vm::interrupt_controller for PICDev
{
    fn assert_irq(&self, irq: u8)
    {
        let mut dev = self.pic.borrow_mut();
        dev.assert_irq(irq)
    }

    fn ack(&self, vec: u8)
    {
        let mut dev = self.pic.borrow_mut();
        dev.ack(vec)
    }
}

pub fn init()
{
	let dev = Rc::new(PICDev {
        pic: RefCell::new(PIC::new()),
    });

    vm::register_interrupt_controller(dev.clone());

    vm::register_io_region(dev.clone(), PIC_MASTER_CMD, 1);
    vm::register_io_region(dev.clone(), PIC_MASTER_DATA, 1);
    vm::register_io_region(dev.clone(), PIC_SLAVE_CMD, 1);
    vm::register_io_region(dev.clone(), PIC_SLAVE_DATA, 1);
}

<|endoftext|>


<commit_before>//! Minimal wrapper around internal Perl API.

use std::ptr;
use std::mem;
use std::os::raw::{ c_int };
use perl_sys::funcs::*;

pub use perl_sys::types::*;
pub use perl_sys::consts::*;

pub type Stack = OuroborosStack;

#[derive(Copy, Clone)]
pub struct Interpreter (PerlThreadContext);

impl Interpreter {
    pub unsafe fn new(pthx: PerlThreadContext) -> Interpreter { Interpreter(pthx) }
}

// Contains result of failed JMPENV_PUSH() while propagating through Rust.
struct Xcpt(c_int);

// Wrapper to safely call potentially dying perl functions (which is pretty much all of them because
// magic and ties).
//
// Put actual call into Perl inside a closure. `ouroboros_xcpt_try()` will call the closure while
// capturing Perl exceptions, so they don't skip Rust code except the closure itself, which should
// be fine, since closure is FnMut and has no destructors.
//
// If it returns zero, we assume that closure did not die and `v` was assigned to, making it safe to
// return, otherwise we panic and possibly incorrect value of `v` is not revealed.
//
// This only works with POD return types and non-panicing $body, which should always be the case for
// Perl API.
macro_rules! xcpt_try {
    ( $pthx:expr, $( $body:stmt )* ) => {{
        let mut v = mem::zeroed();
        {
            let mut callback: &mut FnMut() = &mut || ptr::write(&mut v, { $( $body )* });
            let rc = ouroboros_xcpt_try($pthx,
                                        mem::transmute(xcpt_bouncer as extern "C" fn(_)),
                                        mem::transmute(&mut callback));
            if rc != 0 {
                panic!(Xcpt(rc));
            }
        }
        v
    }}
}

// Helper function for calling Rust closure from C.
extern "C" fn xcpt_bouncer(closure: &mut &mut FnMut()) {
    (*closure)();
}

macro_rules! perl_api_inner {
    (
        fn $name:ident ( $( $pname:ident : $ptype:ty ),* ) = $imp:ident;
        $( $rest:tt )*
    ) => (
        perl_api_inner! {
            fn $name ( $( $pname : $ptype ),* ) -> () = $imp;
            $( $rest )*
        }
    );

    (
        fn $name:ident ( $( $pname:ident : $ptype:ty ),* ) -> $rtype:ty = $imp:ident;
        $( $rest:tt )*
    ) => (
        pub unsafe fn $name ( &self, $( $pname : $ptype ),* ) -> $rtype {
            xcpt_try! { self.0, $imp( self.0, $( $pname ),* ) }
        }
        perl_api_inner! { $( $rest )* }
    );

    () => ();
}

macro_rules! perl_api {
    ( $( $tt:tt )* ) => ( impl Interpreter { perl_api_inner! { $( $tt )* } } )
}

perl_api! {
    fn sv_iv(sv: *mut SV) -> IV = ouroboros_sv_iv;
    fn sv_uv(sv: *mut SV) -> UV = ouroboros_sv_uv;
    fn sv_nv(sv: *mut SV) -> NV = ouroboros_sv_nv;

    fn sv_refcnt_inc(sv: *mut SV) = ouroboros_sv_refcnt_inc_void_nn;
    fn sv_refcnt_dec(sv: *mut SV) = ouroboros_sv_refcnt_dec_nn;

    fn av_clear(av: *mut AV) = Perl_av_clear;
    fn av_delete(av: *mut AV, key: SSize_t, flags: I32) -> *mut SV = Perl_av_delete;
    fn av_exists(av: *mut AV, key: SSize_t) -> c_bool = Perl_av_exists;
    fn av_extend(av: *mut AV, key: SSize_t) = Perl_av_extend;
    fn av_fetch(av: *mut AV, key: SSize_t, flags: I32) -> *mut *mut SV = Perl_av_fetch;
    fn av_fill(av: *mut AV, fill: SSize_t) = Perl_av_fill;
    fn av_len(av: *mut AV) -> SSize_t = Perl_av_len;
    fn av_make(size: SSize_t, strp: *mut *mut SV) -> *mut AV = Perl_av_make;
    fn av_pop(av: *mut AV) -> *mut SV = Perl_av_pop;
    fn av_push(av: *mut AV, val: *mut SV) = Perl_av_push;
    fn av_shift(av: *mut AV) -> *mut SV = Perl_av_shift;
    fn av_store(av: *mut AV, key: SSize_t, sv: *mut SV) -> *mut *mut SV = Perl_av_store;
    fn av_undef(av: *mut AV) = Perl_av_undef;
    fn av_unshift(av: *mut AV, num: SSize_t) = Perl_av_unshift;

    fn st_init(stack: &mut Stack) = ouroboros_stack_init;
    fn st_prepush(stack: &mut Stack) = ouroboros_stack_prepush;
    fn st_putback(stack: &mut Stack) = ouroboros_stack_putback;
    fn st_extend(stack: &mut Stack, len: Size_t) = ouroboros_stack_extend;

    fn st_fetch(stack: &mut Stack, idx: SSize_t) -> *mut SV = ouroboros_stack_fetch;
    fn st_push(stack: &mut Stack, val: *mut SV) = ouroboros_stack_push_sv;
    fn st_push_iv(stack: &mut Stack, val: IV) = ouroboros_stack_push_iv;
    fn st_push_uv(stack: &mut Stack, val: UV) = ouroboros_stack_push_uv;
    fn st_push_nv(stack: &mut Stack, val: NV) = ouroboros_stack_push_nv;

    fn call_pv(name: *const i8, flags: I32) -> I32 = Perl_call_pv;

    fn new_xs(name: *const i8, func: XSUBADDR_t, file: *const i8) -> *mut CV = Perl_newXS;
    fn new_sv(len: STRLEN) -> *mut SV = Perl_newSV;
    fn new_sv_iv(val: IV) -> *mut SV = Perl_newSViv;
    fn new_sv_uv(val: UV) -> *mut SV = Perl_newSVuv;
    fn new_sv_nv(val: NV) -> *mut SV = Perl_newSVnv;
    fn new_sv_pvn(val: *const i8, len: STRLEN, flags: U32) -> *mut SV = Perl_newSVpvn_flags;

    fn get_av(name: *const i8, flags: I32) -> *mut AV = Perl_get_av;
}
<commit_msg>Use non-recursive macro.<commit_after>//! Minimal wrapper around internal Perl API.

use std::ptr;
use std::mem;
use std::os::raw::{ c_int };
use perl_sys::funcs::*;

pub use perl_sys::types::*;
pub use perl_sys::consts::*;

pub type Stack = OuroborosStack;

#[derive(Copy, Clone)]
pub struct Interpreter (PerlThreadContext);

impl Interpreter {
    pub unsafe fn new(pthx: PerlThreadContext) -> Interpreter { Interpreter(pthx) }
}

// Contains result of failed JMPENV_PUSH() while propagating through Rust.
struct Xcpt(c_int);

// Wrapper to safely call potentially dying perl functions (which is pretty much all of them because
// magic and ties).
//
// Put actual call into Perl inside a closure. `ouroboros_xcpt_try()` will call the closure while
// capturing Perl exceptions, so they don't skip Rust code except the closure itself, which should
// be fine, since closure is FnMut and has no destructors.
//
// If it returns zero, we assume that closure did not die and `v` was assigned to, making it safe to
// return, otherwise we panic and possibly incorrect value of `v` is not revealed.
//
// This only works with POD return types and non-panicing $body, which should always be the case for
// Perl API.
macro_rules! xcpt_try {
    ( $pthx:expr, $( $body:stmt )* ) => {{
        let mut v = mem::zeroed();
        {
            let mut callback: &mut FnMut() = &mut || ptr::write(&mut v, { $( $body )* });
            let rc = ouroboros_xcpt_try($pthx,
                                        mem::transmute(xcpt_bouncer as extern "C" fn(_)),
                                        mem::transmute(&mut callback));
            if rc != 0 {
                panic!(Xcpt(rc));
            }
        }
        v
    }}
}

// Helper function for calling Rust closure from C.
extern "C" fn xcpt_bouncer(closure: &mut &mut FnMut()) {
    (*closure)();
}

macro_rules! method {
    (
        fn $name:ident ( $( $pname:ident : $ptype:ty ),* ) = $imp:ident
    ) => (
        method! { fn $name ( $( $pname : $ptype ),* ) -> () = $imp }
    );

    (
        fn $name:ident ( $( $pname:ident : $ptype:ty ),* ) -> $rtype:ty = $imp:ident
    ) => (
        pub unsafe fn $name ( &self, $( $pname : $ptype ),* ) -> $rtype {
            xcpt_try! { self.0, $imp( self.0, $( $pname ),* ) }
        }
    );
}

impl Interpreter {
    method! { fn sv_iv(sv: *mut SV) -> IV = ouroboros_sv_iv }
    method! { fn sv_uv(sv: *mut SV) -> UV = ouroboros_sv_uv }
    method! { fn sv_nv(sv: *mut SV) -> NV = ouroboros_sv_nv }

    method! { fn sv_refcnt_inc(sv: *mut SV) = ouroboros_sv_refcnt_inc_void_nn }
    method! { fn sv_refcnt_dec(sv: *mut SV) = ouroboros_sv_refcnt_dec_nn }

    method! { fn av_clear(av: *mut AV) = Perl_av_clear }
    method! { fn av_delete(av: *mut AV, key: SSize_t, flags: I32) -> *mut SV = Perl_av_delete }
    method! { fn av_exists(av: *mut AV, key: SSize_t) -> c_bool = Perl_av_exists }
    method! { fn av_extend(av: *mut AV, key: SSize_t) = Perl_av_extend }
    method! { fn av_fetch(av: *mut AV, key: SSize_t, flags: I32) -> *mut *mut SV = Perl_av_fetch }
    method! { fn av_fill(av: *mut AV, fill: SSize_t) = Perl_av_fill }
    method! { fn av_len(av: *mut AV) -> SSize_t = Perl_av_len }
    method! { fn av_make(size: SSize_t, strp: *mut *mut SV) -> *mut AV = Perl_av_make }
    method! { fn av_pop(av: *mut AV) -> *mut SV = Perl_av_pop }
    method! { fn av_push(av: *mut AV, val: *mut SV) = Perl_av_push }
    method! { fn av_shift(av: *mut AV) -> *mut SV = Perl_av_shift }
    method! { fn av_store(av: *mut AV, key: SSize_t, sv: *mut SV) -> *mut *mut SV = Perl_av_store }
    method! { fn av_undef(av: *mut AV) = Perl_av_undef }
    method! { fn av_unshift(av: *mut AV, num: SSize_t) = Perl_av_unshift }

    method! { fn st_init(stack: &mut Stack) = ouroboros_stack_init }
    method! { fn st_prepush(stack: &mut Stack) = ouroboros_stack_prepush }
    method! { fn st_putback(stack: &mut Stack) = ouroboros_stack_putback }
    method! { fn st_extend(stack: &mut Stack, len: Size_t) = ouroboros_stack_extend }

    method! { fn st_fetch(stack: &mut Stack, idx: SSize_t) -> *mut SV = ouroboros_stack_fetch }
    method! { fn st_push(stack: &mut Stack, val: *mut SV) = ouroboros_stack_push_sv }
    method! { fn st_push_iv(stack: &mut Stack, val: IV) = ouroboros_stack_push_iv }
    method! { fn st_push_uv(stack: &mut Stack, val: UV) = ouroboros_stack_push_uv }
    method! { fn st_push_nv(stack: &mut Stack, val: NV) = ouroboros_stack_push_nv }

    method! { fn call_pv(name: *const i8, flags: I32) -> I32 = Perl_call_pv }

    method! { fn new_xs(name: *const i8, func: XSUBADDR_t, file: *const i8) -> *mut CV = Perl_newXS }
    method! { fn new_sv(len: STRLEN) -> *mut SV = Perl_newSV }
    method! { fn new_sv_iv(val: IV) -> *mut SV = Perl_newSViv }
    method! { fn new_sv_uv(val: UV) -> *mut SV = Perl_newSVuv }
    method! { fn new_sv_nv(val: NV) -> *mut SV = Perl_newSVnv }
    method! { fn new_sv_pvn(val: *const i8, len: STRLEN, flags: U32) -> *mut SV = Perl_newSVpvn_flags }

    method! { fn get_av(name: *const i8, flags: I32) -> *mut AV = Perl_get_av }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::RingBuf;
use std::rc::Rc;
use std::num::Int;

/// Common buffer object for the two tee halves
struct TeeBuffer<A, I>
{
    backlog: RingBuf<A>,
    iter: I,
    /// The owner field indicates which id should read from the backlog
    owner: bool,
}

/// One half of an iterator pair where both return the same elements.
pub struct Tee<I: Iterator>
{
    rcbuffer: Rc<RefCell<TeeBuffer<I::Item, I>>>,
    id: bool,
}

pub fn new<I: Iterator>(iter: I) -> (Tee<I>, Tee<I>)
{
    let buffer = TeeBuffer{backlog: RingBuf::new(), iter: iter, owner: false};
    let t1 = Tee{rcbuffer: Rc::new(RefCell::new(buffer)), id: true};
    let t2 = Tee{rcbuffer: t1.rcbuffer.clone(), id: false};
    (t1, t2)
}

impl<I: Iterator> Iterator for Tee<I> where
    I::Item: Clone,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<I::Item>
    {
        // .borrow_mut may fail here -- but only if the user has tied some kind of weird
        // knot where the iterator refers back to itself.
        let mut buffer = self.rcbuffer.borrow_mut();
        if buffer.owner == self.id {
            match buffer.backlog.pop_front() {
                None => {}
                some_elt => return some_elt,
            }
        }
        match buffer.iter.next() {
            None => None,
            Some(elt) => {
                buffer.backlog.push_back(elt.clone());
                buffer.owner = !self.id;
                Some(elt)
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>)
    {
        let buffer = self.rcbuffer.borrow();
        let (mut lower, mut upper) = buffer.iter.size_hint();

        if buffer.owner == self.id {
            let log_len = buffer.backlog.len();
            lower = lower.saturating_add(log_len);
            upper = upper.and_then(|x| x.checked_add(log_len));
        }
        (lower, upper)
    }
}
<commit_msg>Reflect upstream rename RingBuf → VecDeque<commit_after>use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;
use std::num::Int;

/// Common buffer object for the two tee halves
struct TeeBuffer<A, I>
{
    backlog: VecDeque<A>,
    iter: I,
    /// The owner field indicates which id should read from the backlog
    owner: bool,
}

/// One half of an iterator pair where both return the same elements.
pub struct Tee<I: Iterator>
{
    rcbuffer: Rc<RefCell<TeeBuffer<I::Item, I>>>,
    id: bool,
}

pub fn new<I: Iterator>(iter: I) -> (Tee<I>, Tee<I>)
{
    let buffer = TeeBuffer{backlog: VecDeque::new(), iter: iter, owner: false};
    let t1 = Tee{rcbuffer: Rc::new(RefCell::new(buffer)), id: true};
    let t2 = Tee{rcbuffer: t1.rcbuffer.clone(), id: false};
    (t1, t2)
}

impl<I: Iterator> Iterator for Tee<I> where
    I::Item: Clone,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<I::Item>
    {
        // .borrow_mut may fail here -- but only if the user has tied some kind of weird
        // knot where the iterator refers back to itself.
        let mut buffer = self.rcbuffer.borrow_mut();
        if buffer.owner == self.id {
            match buffer.backlog.pop_front() {
                None => {}
                some_elt => return some_elt,
            }
        }
        match buffer.iter.next() {
            None => None,
            Some(elt) => {
                buffer.backlog.push_back(elt.clone());
                buffer.owner = !self.id;
                Some(elt)
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>)
    {
        let buffer = self.rcbuffer.borrow();
        let (mut lower, mut upper) = buffer.iter.size_hint();

        if buffer.owner == self.id {
            let log_len = buffer.backlog.len();
            lower = lower.saturating_add(log_len);
            upper = upper.and_then(|x| x.checked_add(log_len));
        }
        (lower, upper)
    }
}
<|endoftext|>


<commit_before>#![ crate_type = "lib" ]
#![ feature(globs) ]
#![ allow(non_snake_case) ]

extern crate libc;

use libusb::*;
use libc::{c_int, c_void, size_t, malloc, free};
use std::intrinsics;
use std::slice;
use std::result::Result;
use std::comm::{Receiver, Sender};
use std::mem::transmute;
use std::mem::size_of;
use std::vec::Vec;
use std::cell::UnsafeCell;

use std::sync::Arc;
use std::sync::atomic::{SeqCst, AtomicInt};
use std::task;

pub mod libusb;

pub struct ContextData {
	ctx: *mut libusb_context,
	open_device_count: AtomicInt
}

impl Drop for ContextData {
	fn drop(&mut self) {
		unsafe {
			assert!(self.open_device_count.load(SeqCst) == 0);
			// TODO: make sure backend thread is dead if the last device just closed
			libusb_exit(self.ctx);
		}
	}
}

pub struct Context {
	bx: Arc<UnsafeCell<ContextData>>
}

impl Context {
	pub fn new() -> Context {
		unsafe{
			let mut ctx: *mut libusb_context = intrinsics::init();
			let r = libusb_init(&mut ctx);
			assert!(r == 0);

			Context{
				bx: Arc::new(UnsafeCell::new(ContextData{
					ctx: ctx,
					open_device_count: AtomicInt::new(0)
				}))
			}
		}
	}

	pub fn ptr(&self) -> *mut libusb_context {
		unsafe{
			(*self.bx.get()).ctx
		}
	}

	pub fn set_debug(&self, level: int) {
		unsafe{
			libusb_set_debug(self.ptr(), level as c_int);
		}
	}

	pub fn list_devices(&self) -> Vec<Device> {
		unsafe{
			let mut list: *mut *mut libusb_device = intrinsics::init();
			let num_devices = libusb_get_device_list(self.ptr(), &mut list);
			let r = slice::raw::mut_buf_as_slice(list, num_devices as uint, |l|{
				l.iter().map(|i| Device{dev: *i, ctx: (*self).clone()}).collect()
			});

			libusb_free_device_list(list, 0);
			r
		}
	}

	pub fn find_by_vid_pid(&self, vid: uint, pid: uint) -> Option<Device> {
		self.list_devices().into_iter().find(|d| {
			let desc = d.descriptor();
			desc.idVendor as uint == vid && desc.idProduct as uint == pid
		})
	}

	fn device_opened(&self) {
		let count = unsafe { &mut (*self.bx.get()).open_device_count };
		let old_count = count.fetch_add(1, SeqCst);

		if old_count == 0 {
			let bx = self.bx.clone();

			fn threadfn(tbx: &Arc<UnsafeCell<ContextData>>) {
				unsafe {
					let ctx = (*tbx.get()).ctx;
					let count = &(*tbx.get()).open_device_count;

					while count.load(SeqCst) > 0 {
						libusb_handle_events(ctx);
					}
				}
			}

			task::spawn(proc() {threadfn(&bx);});
		}
	}

	fn device_closed(&self) {
		let count = unsafe { &mut (*self.bx.get()).open_device_count };
		count.fetch_sub(1, SeqCst);
	}
}

extern fn rust_usb_callback(transfer: *mut libusb_transfer) {
	unsafe {
		let chan: Box<Sender<()>> = transmute((*transfer).user_data);
		chan.send(());
	}
}

struct TH {
	t: *mut libusb_transfer,
	c: Sender<*mut libusb_transfer>,
}

impl Drop for TH{
	fn drop(&mut self) {
		unsafe {
			free((*self.t).buffer as *mut c_void);
			libusb_free_transfer(self.t);
		}
	}
}

extern fn rust_usb_stream_callback(transfer: *mut libusb_transfer) {
	unsafe {
		let chan: &Sender<*mut libusb_transfer> = transmute((*transfer).user_data);
		chan.send(transfer);
	}
}

impl Clone for Context{
	fn clone(&self) -> Context{
		Context{bx: self.bx.clone()}
	}
}

pub struct Device {
	dev: *mut libusb_device,
	ctx: Context
}

impl Device {
	pub fn descriptor(&self) -> Box<libusb_device_descriptor> {
		unsafe{
			let mut d: Box<libusb_device_descriptor> = box intrinsics::uninit();
			libusb_get_device_descriptor(self.dev, &mut *d as *mut libusb_device_descriptor);
			d
		}
	}

	pub fn bus(&self) -> int {
		unsafe {
			libusb_get_bus_number(self.dev) as int
		}
	}

	pub fn address(&self) -> int {
		unsafe {
			libusb_get_device_address(self.dev) as int
		}
	}

	pub fn open(&self) -> Result<DeviceHandle, int> {
		unsafe {
			let mut handle: *mut libusb_device_handle = intrinsics::uninit();
			let r = libusb_open(self.dev, &mut handle);
			if r == 0 {
				self.ctx.device_opened();
				Ok(DeviceHandle {
					bx: Arc::new(UnsafeCell::new(DeviceHandleData {
						dev: handle,
						ctx: self.ctx.clone()
					}))
				})
			}else{
				Err(r as int)
			}
		}
	}
}

impl Drop for Device {
	fn drop(&mut self) {
		unsafe {
			libusb_unref_device(self.dev);
		}
	}
}

impl Clone for Device {
	fn clone(&self) -> Device {
		unsafe {
			libusb_ref_device(self.dev);
		}
		Device{dev: self.dev, ctx: self.ctx.clone()}
	}
}

struct DeviceHandleData{
	dev: *mut libusb_device_handle,
	ctx: Context
}

impl Drop for DeviceHandleData {
	fn drop(&mut self) {
		unsafe {
			self.ctx.device_closed();
			libusb_close(self.dev);
		}
	}
}

pub struct DeviceHandle {
	bx: Arc<UnsafeCell<DeviceHandleData>>
}

impl DeviceHandle {
	pub fn ptr(&self) -> *mut libusb_device_handle {
		unsafe {
			(*self.bx.get()).dev
		}
	}

	pub fn claim_interface(&self,
		iface_num: uint) {
		unsafe {
		libusb_claim_interface(self.ptr(), iface_num as c_int);
		}
	}

	pub unsafe fn submit_transfer_sync(&self,
		endpoint: u8,
		transfer_type: libusb_transfer_type,
		length: uint,
		buffer: *mut u8) -> (libusb_transfer_status, uint) {

		let (chan, port) : (Sender<()>, Receiver<()>) = channel();

		let t = libusb_alloc_transfer(0);
		(*t).dev_handle = self.ptr();
		(*t).endpoint = endpoint;
		(*t).transfer_type = transfer_type as u8;
		(*t).timeout = 0;
		(*t).length = length as c_int;
		(*t).callback = rust_usb_callback;
		(*t).user_data = transmute(box chan);
		(*t).buffer = buffer;

		libusb_submit_transfer(t);
		port.recv();
		let r = ((*t).get_status(), (*t).actual_length as uint);
		libusb_free_transfer(t);
		return r;
	}

	pub fn read(&self,
			endpoint: u8,
			transfer_type: libusb_transfer_type,
			size: uint
			) -> Result<Vec<u8>, libusb_transfer_status> {
		let mut buf: Vec<u8> = Vec::from_elem(size, 0u8);
		unsafe {
			let ptr = buf.as_mut_ptr();
			let (status, actual_length) = self.submit_transfer_sync(
				endpoint, transfer_type, size, ptr);

			if status == LIBUSB_TRANSFER_COMPLETED {
				buf.truncate(actual_length);
				Ok(buf)
			} else {
				Err(status)
			}
		}
	}

	pub fn write(&self, endpoint: u8, transfer_type: libusb_transfer_type, buf: &[u8]) -> Result<(), libusb_transfer_status> {
		unsafe {
			let ptr = buf.as_ptr() as *mut u8;

			let (status, _) = self.submit_transfer_sync(
				endpoint, transfer_type, buf.len(), ptr);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_read(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, length: uint) -> Result<Vec<u8>, libusb_transfer_status> {

		let setup_length = size_of::<libusb_control_setup>();
		let total_length = setup_length + length as uint;
		let mut buf: Vec<u8> = Vec::from_elem(total_length, 0u8);

		unsafe{
			let ptr = fill_setup_buf(buf.as_mut_slice(), bmRequestType, bRequest, wValue, wIndex, length);

			let (status, actual_length) = self.submit_transfer_sync(
				0, LIBUSB_TRANSFER_TYPE_CONTROL, total_length, ptr);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(buf.slice(setup_length, setup_length+actual_length).to_vec())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_write(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, buf: &[u8]) -> Result<(), libusb_transfer_status> {
		unsafe {
			let mut setup_buf = Vec::from_elem(size_of::<libusb_control_setup>(), 0u8);
			fill_setup_buf(setup_buf.as_mut_slice(), bmRequestType, bRequest, wValue, wIndex, buf.len());
			setup_buf.push_all(buf);
			self.write(0, LIBUSB_TRANSFER_TYPE_CONTROL, setup_buf.slice_from(0))
		}
	}

	unsafe fn stream_transfers(&self, endpoint: u8,
			transfer_type: libusb_transfer_type, size: uint,
			num_transfers: uint) -> (Receiver<*mut libusb_transfer>, Vec<TH>) {

		let (chan, port) = channel();

		let transfers = Vec::from_fn(num_transfers, |_| { TH {
			t: libusb_alloc_transfer(0),
			c: chan.clone(),
		}});

		for th in transfers.iter() {
			(*th.t).dev_handle = self.ptr();
			(*th.t).endpoint = endpoint;
			(*th.t).transfer_type = transfer_type as u8;
			(*th.t).timeout = 0;
			(*th.t).length = size as i32;
			(*th.t).callback = rust_usb_stream_callback;
			(*th.t).buffer = malloc(size as size_t) as *mut u8;
			(*th.t).user_data = transmute(&th.c);
		}

		return (port, transfers);
	}

	pub fn read_stream(&self, endpoint: u8,
			transfer_type: libusb_transfer_type,
			size: uint, mut num_transfers: uint, cb: |Result<&[u8], libusb_transfer_status>| -> bool) {

		unsafe {
			let mut running = true;
			let (port, transfers) = self.stream_transfers(
				endpoint, transfer_type, size, num_transfers);

			for th in transfers.iter() {
				libusb_submit_transfer(th.t);
			}

			while num_transfers > 0 {
				let transfer: *mut libusb_transfer = port.recv();

				if (*transfer).get_status() == LIBUSB_TRANSFER_COMPLETED {
					slice::raw::buf_as_slice((*transfer).buffer as *const u8, size, |b| {
						running &= cb(Ok(b))
					});
				} else {
					running = false;
					running &= cb(Err((*transfer).get_status()));
				}

				if running {
					let r = libusb_submit_transfer(transfer);
					assert!(r == 0);
				} else {
					num_transfers -= 1;
				}
			}
		}
	}

	pub fn write_stream(&self, endpoint: u8,
			transfer_type: libusb_transfer_type,
			size: uint, num_transfers: uint, cb: |Result<(&mut[u8]), libusb_transfer_status>| -> bool) {

		unsafe {
			let mut running = true;
			let mut running_transfers = 0u;
			let (port, transfers) = self.stream_transfers(
				endpoint, transfer_type, size, num_transfers);

			for th in transfers.iter() {
				slice::raw::mut_buf_as_slice((*th.t).buffer, size, |b| {
					running &= cb(Ok(b));
				});
				if running {
					libusb_submit_transfer(th.t);
					running_transfers += 1;
				} else {
					break;
				}
			}

			while running_transfers > 0 {
				let transfer: *mut libusb_transfer = port.recv();

				if (*transfer).get_status() == LIBUSB_TRANSFER_COMPLETED {
					slice::raw::mut_buf_as_slice((*transfer).buffer, size, |b| {
						running &= cb(Ok(b))
					});
				} else {
					running = false;
					running &= cb(Err((*transfer).get_status()));
				}

				if running {
					let r = libusb_submit_transfer(transfer);
					assert!(r == 0);
				} else {
					running_transfers -= 1;
				}
			}
		}
	}
}

unsafe fn fill_setup_buf(buf: &mut [u8], bmRequestType: u8,
	bRequest: u8, wValue:u16, wIndex: u16, length: uint) -> *mut u8 {
	let ptr = buf.as_mut_ptr();
	let setup = ptr as *mut libusb_control_setup;

	// TODO: these are always little-endian
	(*setup).bmRequestType = bmRequestType;
	(*setup).bRequest = bRequest;
	(*setup).wValue = wValue;
	(*setup).wIndex = wIndex;
	(*setup).wLength = length as u16;

	return ptr;
}

impl Clone for DeviceHandle {
	fn clone(&self) -> DeviceHandle {
		DeviceHandle{bx: self.bx.clone()}
	}
}
<commit_msg>rust: slice::raw deprecation<commit_after>#![ crate_type = "lib" ]
#![ feature(globs) ]
#![ allow(non_snake_case) ]

extern crate libc;

use libusb::*;
use libc::{c_int, c_void, size_t, malloc, free};
use std::intrinsics;
use std::slice;
use std::result::Result;
use std::comm::{Receiver, Sender};
use std::mem::transmute;
use std::mem::size_of;
use std::vec::Vec;
use std::cell::UnsafeCell;

use std::sync::Arc;
use std::sync::atomic::{SeqCst, AtomicInt};
use std::task;

pub mod libusb;

pub struct ContextData {
	ctx: *mut libusb_context,
	open_device_count: AtomicInt
}

impl Drop for ContextData {
	fn drop(&mut self) {
		unsafe {
			assert!(self.open_device_count.load(SeqCst) == 0);
			// TODO: make sure backend thread is dead if the last device just closed
			libusb_exit(self.ctx);
		}
	}
}

pub struct Context {
	bx: Arc<UnsafeCell<ContextData>>
}

impl Context {
	pub fn new() -> Context {
		unsafe{
			let mut ctx: *mut libusb_context = intrinsics::init();
			let r = libusb_init(&mut ctx);
			assert!(r == 0);

			Context{
				bx: Arc::new(UnsafeCell::new(ContextData{
					ctx: ctx,
					open_device_count: AtomicInt::new(0)
				}))
			}
		}
	}

	pub fn ptr(&self) -> *mut libusb_context {
		unsafe{
			(*self.bx.get()).ctx
		}
	}

	pub fn set_debug(&self, level: int) {
		unsafe{
			libusb_set_debug(self.ptr(), level as c_int);
		}
	}

	pub fn list_devices(&self) -> Vec<Device> {
		unsafe{
			let mut list: *mut *mut libusb_device = intrinsics::init();
			let num_devices = libusb_get_device_list(self.ptr(), &mut list);
			let l = slice::from_raw_mut_buf(&list, num_devices as uint);
			let devices = l.iter().map(|i| Device{dev: *i, ctx: (*self).clone()}).collect();
			libusb_free_device_list(list, 0);
			devices
		}
	}

	pub fn find_by_vid_pid(&self, vid: uint, pid: uint) -> Option<Device> {
		self.list_devices().into_iter().find(|d| {
			let desc = d.descriptor();
			desc.idVendor as uint == vid && desc.idProduct as uint == pid
		})
	}

	fn device_opened(&self) {
		let count = unsafe { &mut (*self.bx.get()).open_device_count };
		let old_count = count.fetch_add(1, SeqCst);

		if old_count == 0 {
			let bx = self.bx.clone();

			fn threadfn(tbx: &Arc<UnsafeCell<ContextData>>) {
				unsafe {
					let ctx = (*tbx.get()).ctx;
					let count = &(*tbx.get()).open_device_count;

					while count.load(SeqCst) > 0 {
						libusb_handle_events(ctx);
					}
				}
			}

			task::spawn(proc() {threadfn(&bx);});
		}
	}

	fn device_closed(&self) {
		let count = unsafe { &mut (*self.bx.get()).open_device_count };
		count.fetch_sub(1, SeqCst);
	}
}

extern fn rust_usb_callback(transfer: *mut libusb_transfer) {
	unsafe {
		let chan: Box<Sender<()>> = transmute((*transfer).user_data);
		chan.send(());
	}
}

struct TH {
	t: *mut libusb_transfer,
	c: Sender<*mut libusb_transfer>,
}

impl Drop for TH{
	fn drop(&mut self) {
		unsafe {
			free((*self.t).buffer as *mut c_void);
			libusb_free_transfer(self.t);
		}
	}
}

extern fn rust_usb_stream_callback(transfer: *mut libusb_transfer) {
	unsafe {
		let chan: &Sender<*mut libusb_transfer> = transmute((*transfer).user_data);
		chan.send(transfer);
	}
}

impl Clone for Context{
	fn clone(&self) -> Context{
		Context{bx: self.bx.clone()}
	}
}

pub struct Device {
	dev: *mut libusb_device,
	ctx: Context
}

impl Device {
	pub fn descriptor(&self) -> Box<libusb_device_descriptor> {
		unsafe{
			let mut d: Box<libusb_device_descriptor> = box intrinsics::uninit();
			libusb_get_device_descriptor(self.dev, &mut *d as *mut libusb_device_descriptor);
			d
		}
	}

	pub fn bus(&self) -> int {
		unsafe {
			libusb_get_bus_number(self.dev) as int
		}
	}

	pub fn address(&self) -> int {
		unsafe {
			libusb_get_device_address(self.dev) as int
		}
	}

	pub fn open(&self) -> Result<DeviceHandle, int> {
		unsafe {
			let mut handle: *mut libusb_device_handle = intrinsics::uninit();
			let r = libusb_open(self.dev, &mut handle);
			if r == 0 {
				self.ctx.device_opened();
				Ok(DeviceHandle {
					bx: Arc::new(UnsafeCell::new(DeviceHandleData {
						dev: handle,
						ctx: self.ctx.clone()
					}))
				})
			}else{
				Err(r as int)
			}
		}
	}
}

impl Drop for Device {
	fn drop(&mut self) {
		unsafe {
			libusb_unref_device(self.dev);
		}
	}
}

impl Clone for Device {
	fn clone(&self) -> Device {
		unsafe {
			libusb_ref_device(self.dev);
		}
		Device{dev: self.dev, ctx: self.ctx.clone()}
	}
}

struct DeviceHandleData{
	dev: *mut libusb_device_handle,
	ctx: Context
}

impl Drop for DeviceHandleData {
	fn drop(&mut self) {
		unsafe {
			self.ctx.device_closed();
			libusb_close(self.dev);
		}
	}
}

pub struct DeviceHandle {
	bx: Arc<UnsafeCell<DeviceHandleData>>
}

impl DeviceHandle {
	pub fn ptr(&self) -> *mut libusb_device_handle {
		unsafe {
			(*self.bx.get()).dev
		}
	}

	pub fn claim_interface(&self,
		iface_num: uint) {
		unsafe {
		libusb_claim_interface(self.ptr(), iface_num as c_int);
		}
	}

	pub unsafe fn submit_transfer_sync(&self,
		endpoint: u8,
		transfer_type: libusb_transfer_type,
		length: uint,
		buffer: *mut u8) -> (libusb_transfer_status, uint) {

		let (chan, port) : (Sender<()>, Receiver<()>) = channel();

		let t = libusb_alloc_transfer(0);
		(*t).dev_handle = self.ptr();
		(*t).endpoint = endpoint;
		(*t).transfer_type = transfer_type as u8;
		(*t).timeout = 0;
		(*t).length = length as c_int;
		(*t).callback = rust_usb_callback;
		(*t).user_data = transmute(box chan);
		(*t).buffer = buffer;

		libusb_submit_transfer(t);
		port.recv();
		let r = ((*t).get_status(), (*t).actual_length as uint);
		libusb_free_transfer(t);
		return r;
	}

	pub fn read(&self,
			endpoint: u8,
			transfer_type: libusb_transfer_type,
			size: uint
			) -> Result<Vec<u8>, libusb_transfer_status> {
		let mut buf: Vec<u8> = Vec::from_elem(size, 0u8);
		unsafe {
			let ptr = buf.as_mut_ptr();
			let (status, actual_length) = self.submit_transfer_sync(
				endpoint, transfer_type, size, ptr);

			if status == LIBUSB_TRANSFER_COMPLETED {
				buf.truncate(actual_length);
				Ok(buf)
			} else {
				Err(status)
			}
		}
	}

	pub fn write(&self, endpoint: u8, transfer_type: libusb_transfer_type, buf: &[u8]) -> Result<(), libusb_transfer_status> {
		unsafe {
			let ptr = buf.as_ptr() as *mut u8;

			let (status, _) = self.submit_transfer_sync(
				endpoint, transfer_type, buf.len(), ptr);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_read(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, length: uint) -> Result<Vec<u8>, libusb_transfer_status> {

		let setup_length = size_of::<libusb_control_setup>();
		let total_length = setup_length + length as uint;
		let mut buf: Vec<u8> = Vec::from_elem(total_length, 0u8);

		unsafe{
			let ptr = fill_setup_buf(buf.as_mut_slice(), bmRequestType, bRequest, wValue, wIndex, length);

			let (status, actual_length) = self.submit_transfer_sync(
				0, LIBUSB_TRANSFER_TYPE_CONTROL, total_length, ptr);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(buf.slice(setup_length, setup_length+actual_length).to_vec())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_write(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, buf: &[u8]) -> Result<(), libusb_transfer_status> {
		unsafe {
			let mut setup_buf = Vec::from_elem(size_of::<libusb_control_setup>(), 0u8);
			fill_setup_buf(setup_buf.as_mut_slice(), bmRequestType, bRequest, wValue, wIndex, buf.len());
			setup_buf.push_all(buf);
			self.write(0, LIBUSB_TRANSFER_TYPE_CONTROL, setup_buf.slice_from(0))
		}
	}

	unsafe fn stream_transfers(&self, endpoint: u8,
			transfer_type: libusb_transfer_type, size: uint,
			num_transfers: uint) -> (Receiver<*mut libusb_transfer>, Vec<TH>) {

		let (chan, port) = channel();

		let transfers = Vec::from_fn(num_transfers, |_| { TH {
			t: libusb_alloc_transfer(0),
			c: chan.clone(),
		}});

		for th in transfers.iter() {
			(*th.t).dev_handle = self.ptr();
			(*th.t).endpoint = endpoint;
			(*th.t).transfer_type = transfer_type as u8;
			(*th.t).timeout = 0;
			(*th.t).length = size as i32;
			(*th.t).callback = rust_usb_stream_callback;
			(*th.t).buffer = malloc(size as size_t) as *mut u8;
			(*th.t).user_data = transmute(&th.c);
		}

		return (port, transfers);
	}

	pub fn read_stream(&self, endpoint: u8,
			transfer_type: libusb_transfer_type,
			size: uint, mut num_transfers: uint, cb: |Result<&[u8], libusb_transfer_status>| -> bool) {

		unsafe {
			let mut running = true;
			let (port, transfers) = self.stream_transfers(
				endpoint, transfer_type, size, num_transfers);

			for th in transfers.iter() {
				libusb_submit_transfer(th.t);
			}

			while num_transfers > 0 {
				let transfer: *mut libusb_transfer = port.recv();

				if (*transfer).get_status() == LIBUSB_TRANSFER_COMPLETED {
					let b = slice::from_raw_mut_buf(&(*transfer).buffer, size).as_slice();
					running &= cb(Ok(b));
				} else {
					running = false;
					running &= cb(Err((*transfer).get_status()));
				}

				if running {
					let r = libusb_submit_transfer(transfer);
					assert!(r == 0);
				} else {
					num_transfers -= 1;
				}
			}
		}
	}

	pub fn write_stream(&self, endpoint: u8,
			transfer_type: libusb_transfer_type,
			size: uint, num_transfers: uint, cb: |Result<(&mut[u8]), libusb_transfer_status>| -> bool) {

		unsafe {
			let mut running = true;
			let mut running_transfers = 0u;
			let (port, transfers) = self.stream_transfers(
				endpoint, transfer_type, size, num_transfers);

			for th in transfers.iter() {
				let b = slice::from_raw_mut_buf(&(*th.t).buffer, size);
				running &= cb(Ok(b));
				if running {
					libusb_submit_transfer(th.t);
					running_transfers += 1;
				} else {
					break;
				}
			}

			while running_transfers > 0 {
				let transfer: *mut libusb_transfer = port.recv();

				if (*transfer).get_status() == LIBUSB_TRANSFER_COMPLETED {
					let b = slice::from_raw_mut_buf(&(*transfer).buffer, size);
					running &= cb(Ok(b))
				} else {
					running = false;
					running &= cb(Err((*transfer).get_status()));
				}

				if running {
					let r = libusb_submit_transfer(transfer);
					assert!(r == 0);
				} else {
					running_transfers -= 1;
				}
			}
		}
	}
}

unsafe fn fill_setup_buf(buf: &mut [u8], bmRequestType: u8,
	bRequest: u8, wValue:u16, wIndex: u16, length: uint) -> *mut u8 {
	let ptr = buf.as_mut_ptr();
	let setup = ptr as *mut libusb_control_setup;

	// TODO: these are always little-endian
	(*setup).bmRequestType = bmRequestType;
	(*setup).bRequest = bRequest;
	(*setup).wValue = wValue;
	(*setup).wIndex = wIndex;
	(*setup).wLength = length as u16;

	return ptr;
}

impl Clone for DeviceHandle {
	fn clone(&self) -> DeviceHandle {
		DeviceHandle{bx: self.bx.clone()}
	}
}
<|endoftext|>