<commit_before>use super::server::Server;
use crate::*;
use std::collections::HashMap;
use std::net::SocketAddr;
use tokio::{
    net::{TcpListener, TcpStream},
    prelude::*,
};

pub enum NetCmd {
    Listen(SocketAddr),
    Connect(SocketAddr),
    Disconnect(SessionId),
    Broadcast(Payload)
}

impl Message for NetCmd {
    type Result = ();
}

struct Handlers<S: 'static> {
    connected: Option<Box<Fn(&mut S, SessionInfo) -> () + 'static>>,
    disconnected: Option<Box<Fn(&mut S, SessionInfo) -> () + 'static>>,
    message: Box<Fn(&mut S, SessionId, &Payload) -> bool + 'static>,
}

pub struct Network<S: 'static> {
    state: S,
    handlers: Handlers<S>,
    sessions: HashMap<SessionId, SessionInfo>,
}

impl<S: 'static> Network<S> {
    pub fn new<F>(state: S, msg_handler: F) -> Self
    where
        F: Fn(&mut S, SessionId, &Payload) -> bool + 'static,
    {
        let handlers = Handlers {
            connected: None,
            disconnected: None,
            message: Box::new(msg_handler),
        };
        Network {
            state,
            handlers,
            sessions: HashMap::with_capacity(32),
        }
    }

    pub fn on_connect<F>(mut self, f: F) -> Network<S>
    where
        F: Fn(&mut S, SessionInfo) -> () + 'static,
    {
        self.handlers.connected.replace(Box::new(f));
        self
    }

    pub fn on_disconnect<F>(mut self, f: F) -> Network<S>
    where
        F: Fn(&mut S, SessionInfo) -> () + 'static,
    {
        self.handlers.disconnected.replace(Box::new(f));
        self
    }

    fn broadcast(&self, msg: &Payload, skip_id: Option<SessionId>) {
        self.sessions
            .values()
            .filter(|ses| {
                skip_id.map_or(true, |skip_id| ses.id != skip_id)
            })
            .for_each(|ses| {
                ses.address.do_send(msg.clone());
            });
    }
}

impl<S: 'static> Actor for Network<S> {
    type Context = Context<Self>;
}

impl<S: 'static> Handler<NetCmd> for Network<S> {
    type Result = ();

    fn handle(&mut self, msg: NetCmd, ctx: &mut Self::Context) {
        match msg {
            NetCmd::Listen(bind_addr) => {
                let recipient = ctx.address().recipient();
                Server::create(move |ctx| {
                    let s = TcpListener::bind(&bind_addr).unwrap();
                    debug!("Accepting inbound connections on {}", bind_addr);
                    ctx.add_stream(s.incoming());
                    Server { recipient }
                });
            }
            NetCmd::Connect(addr) => {
                let rx = ctx.address().recipient();
                Arbiter::spawn(
                    TcpStream::connect(&addr)
                        .and_then(|s| {
                            Session::init(rx, ConnectionType::Outbound, s);
                            Ok(())
                        })
                        .map_err(move |e| {
                            warn!("[{}] Failed to connect to peer: {:?}", addr, e);
                        }),
                );
            }
            NetCmd::Disconnect(id) => {
                if let Some(ses) = self.sessions.get(&id) {
                    ses.address.do_send(session::Disconnect);
                }
            }
            NetCmd::Broadcast(payload) => {
                self.broadcast(&payload, None);
            }
        }
    }
}

impl<S: 'static> Handler<SessionMsg> for Network<S> {
    type Result = ();

    fn handle(&mut self, msg: SessionMsg, _: &mut Self::Context) {
        match msg {
            SessionMsg::Connected(ses) => {
                let id = ses.id;
                let prev = self.sessions.insert(id, ses.clone());
                assert!(prev.is_none());
                if let Some(f) = &self.handlers.connected {
                    f(&mut self.state, ses);
                }
            }
            SessionMsg::Disconnected(addr) => {
                let ses = self
                    .sessions
                    .remove(&addr)
                    .unwrap_or_else(|| panic!("Expected disconnected peer to exist: {}", addr));
                if let Some(f) = &self.handlers.disconnected {
                    f(&mut self.state, ses);
                }
            }
            SessionMsg::Message(ses_id, payload) => {
                if (self.handlers.message)(&mut self.state, ses_id, &payload) {
                    self.broadcast(&payload, Some(ses_id));
                }
            }
        }
    }
}
<commit_msg>Clarify assertion error on duplicate session IDs<commit_after>use super::server::Server;
use crate::*;
use std::collections::HashMap;
use std::net::SocketAddr;
use tokio::{
    net::{TcpListener, TcpStream},
    prelude::*,
};

pub enum NetCmd {
    Listen(SocketAddr),
    Connect(SocketAddr),
    Disconnect(SessionId),
    Broadcast(Payload)
}

impl Message for NetCmd {
    type Result = ();
}

struct Handlers<S: 'static> {
    connected: Option<Box<Fn(&mut S, SessionInfo) -> () + 'static>>,
    disconnected: Option<Box<Fn(&mut S, SessionInfo) -> () + 'static>>,
    message: Box<Fn(&mut S, SessionId, &Payload) -> bool + 'static>,
}

pub struct Network<S: 'static> {
    state: S,
    handlers: Handlers<S>,
    sessions: HashMap<SessionId, SessionInfo>,
}

impl<S: 'static> Network<S> {
    pub fn new<F>(state: S, msg_handler: F) -> Self
    where
        F: Fn(&mut S, SessionId, &Payload) -> bool + 'static,
    {
        let handlers = Handlers {
            connected: None,
            disconnected: None,
            message: Box::new(msg_handler),
        };
        Network {
            state,
            handlers,
            sessions: HashMap::with_capacity(32),
        }
    }

    pub fn on_connect<F>(mut self, f: F) -> Network<S>
    where
        F: Fn(&mut S, SessionInfo) -> () + 'static,
    {
        self.handlers.connected.replace(Box::new(f));
        self
    }

    pub fn on_disconnect<F>(mut self, f: F) -> Network<S>
    where
        F: Fn(&mut S, SessionInfo) -> () + 'static,
    {
        self.handlers.disconnected.replace(Box::new(f));
        self
    }

    fn broadcast(&self, msg: &Payload, skip_id: Option<SessionId>) {
        self.sessions
            .values()
            .filter(|ses| {
                skip_id.map_or(true, |skip_id| ses.id != skip_id)
            })
            .for_each(|ses| {
                ses.address.do_send(msg.clone());
            });
    }
}

impl<S: 'static> Actor for Network<S> {
    type Context = Context<Self>;
}

impl<S: 'static> Handler<NetCmd> for Network<S> {
    type Result = ();

    fn handle(&mut self, msg: NetCmd, ctx: &mut Self::Context) {
        match msg {
            NetCmd::Listen(bind_addr) => {
                let recipient = ctx.address().recipient();
                Server::create(move |ctx| {
                    let s = TcpListener::bind(&bind_addr).unwrap();
                    debug!("Accepting inbound connections on {}", bind_addr);
                    ctx.add_stream(s.incoming());
                    Server { recipient }
                });
            }
            NetCmd::Connect(addr) => {
                let rx = ctx.address().recipient();
                Arbiter::spawn(
                    TcpStream::connect(&addr)
                        .and_then(|s| {
                            Session::init(rx, ConnectionType::Outbound, s);
                            Ok(())
                        })
                        .map_err(move |e| {
                            warn!("[{}] Failed to connect to peer: {:?}", addr, e);
                        }),
                );
            }
            NetCmd::Disconnect(id) => {
                if let Some(ses) = self.sessions.get(&id) {
                    ses.address.do_send(session::Disconnect);
                }
            }
            NetCmd::Broadcast(payload) => {
                self.broadcast(&payload, None);
            }
        }
    }
}

impl<S: 'static> Handler<SessionMsg> for Network<S> {
    type Result = ();

    fn handle(&mut self, msg: SessionMsg, _: &mut Self::Context) {
        match msg {
            SessionMsg::Connected(ses) => {
                let id = ses.id;
                let prev = self.sessions.insert(id, ses.clone());
                assert!(prev.is_none(), "session id already exists in network");
                if let Some(f) = &self.handlers.connected {
                    f(&mut self.state, ses);
                }
            }
            SessionMsg::Disconnected(addr) => {
                let ses = self
                    .sessions
                    .remove(&addr)
                    .unwrap_or_else(|| panic!("Expected disconnected peer to exist: {}", addr));
                if let Some(f) = &self.handlers.disconnected {
                    f(&mut self.state, ses);
                }
            }
            SessionMsg::Message(ses_id, payload) => {
                if (self.handlers.message)(&mut self.state, ses_id, &payload) {
                    self.broadcast(&payload, Some(ses_id));
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright © 2017 Mozilla Foundation
//
// This program is made available under an ISC-style license.  See the
// accompanying file LICENSE for details

use {ContextOps, StreamOps};
use cubeb_core::{ffi, DeviceCollectionRef, DeviceRef, DeviceType, StreamParams, StreamParamsRef};
use std::ffi::CStr;
use std::mem;
use std::os::raw::{c_char, c_int, c_void};

// Helper macro for unwrapping `Result` values from rust-api calls
// while returning early with a c-api error code if the value of the
// expression is `Err`.
macro_rules! _try(
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => return e.raw_code()
    })
);

macro_rules! as_opt_ref {
    ($e:expr) => {
        if $e.is_null() {
            None
        } else {
            Some(StreamParamsRef::from_ptr($e))
        }
    }
}

#[macro_export]
macro_rules! capi_new(
    ($ctx:ident, $stm:ident) => (
        Ops {
            init: Some($crate::capi::capi_init::<$ctx>),
            get_backend_id: Some($crate::capi::capi_get_backend_id::<$ctx>),
            get_max_channel_count: Some($crate::capi::capi_get_max_channel_count::<$ctx>),
            get_min_latency: Some($crate::capi::capi_get_min_latency::<$ctx>),
            get_preferred_sample_rate: Some($crate::capi::capi_get_preferred_sample_rate::<$ctx>),
            enumerate_devices: Some($crate::capi::capi_enumerate_devices::<$ctx>),
            device_collection_destroy: Some($crate::capi::capi_device_collection_destroy::<$ctx>),
            destroy: Some($crate::capi::capi_destroy::<$ctx>),
            stream_init: Some($crate::capi::capi_stream_init::<$ctx>),
            stream_destroy: Some($crate::capi::capi_stream_destroy::<$stm>),
            stream_start: Some($crate::capi::capi_stream_start::<$stm>),
            stream_stop: Some($crate::capi::capi_stream_stop::<$stm>),
            stream_reset_default_device:
                Some($crate::capi::capi_stream_reset_default_device::<$stm>),
            stream_get_position: Some($crate::capi::capi_stream_get_position::<$stm>),
            stream_get_latency: Some($crate::capi::capi_stream_get_latency::<$stm>),
            stream_set_volume: Some($crate::capi::capi_stream_set_volume::<$stm>),
            stream_set_panning: Some($crate::capi::capi_stream_set_panning::<$stm>),
            stream_get_current_device: Some($crate::capi::capi_stream_get_current_device::<$stm>),
            stream_device_destroy: Some($crate::capi::capi_stream_device_destroy::<$stm>),
            stream_register_device_changed_callback: None,
            register_device_collection_changed:
                Some($crate::capi::capi_register_device_collection_changed::<$ctx>)
        }));

pub unsafe extern "C" fn capi_init<CTX: ContextOps>(
    c: *mut *mut ffi::cubeb,
    context_name: *const c_char,
) -> c_int {
    let anchor = &();
    let context_name = opt_cstr(anchor, context_name);
    let context = _try!(CTX::init(context_name));
    *c = context.as_ptr();
    // Leaking pointer across C FFI
    mem::forget(context);
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_backend_id<CTX: ContextOps>(c: *mut ffi::cubeb) -> *const c_char {
    let ctx = &mut *(c as *mut CTX);
    ctx.backend_id().as_ptr()
}

pub unsafe extern "C" fn capi_get_max_channel_count<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    max_channels: *mut u32,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);

    *max_channels = _try!(ctx.max_channel_count());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_min_latency<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    param: ffi::cubeb_stream_params,
    latency_frames: *mut u32,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let param = StreamParams::from(param);
    *latency_frames = _try!(ctx.min_latency(param));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_preferred_sample_rate<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    rate: *mut u32,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);

    *rate = _try!(ctx.preferred_sample_rate());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_enumerate_devices<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    devtype: ffi::cubeb_device_type,
    collection: *mut ffi::cubeb_device_collection,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let devtype = DeviceType::from_bits_truncate(devtype);
    let collection = DeviceCollectionRef::from_ptr(collection);
    _try!(ctx.enumerate_devices(devtype, collection));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_device_collection_destroy<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    collection: *mut ffi::cubeb_device_collection,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let collection = DeviceCollectionRef::from_ptr_mut(collection);
    let _ = ctx.device_collection_destroy(collection);
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_destroy<CTX>(c: *mut ffi::cubeb) {
    let _: Box<CTX> = Box::from_raw(c as *mut _);
}

pub unsafe extern "C" fn capi_stream_init<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    s: *mut *mut ffi::cubeb_stream,
    stream_name: *const c_char,
    input_device: ffi::cubeb_devid,
    input_stream_params: *mut ffi::cubeb_stream_params,
    output_device: ffi::cubeb_devid,
    output_stream_params: *mut ffi::cubeb_stream_params,
    latency_frames: u32,
    data_callback: ffi::cubeb_data_callback,
    state_callback: ffi::cubeb_state_callback,
    user_ptr: *mut c_void,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let anchor = &(); // for lifetime of stream_name as CStr

    let input_stream_params = as_opt_ref!(input_stream_params);
    let output_stream_params = as_opt_ref!(output_stream_params);

    let stream = _try!(ctx.stream_init(
        opt_cstr(anchor, stream_name),
        input_device,
        input_stream_params,
        output_device,
        output_stream_params,
        latency_frames,
        data_callback,
        state_callback,
        user_ptr
    ));
    *s = stream.as_ptr();
    // Leaking pointer across C FFI
    mem::forget(stream);
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_destroy<STM>(s: *mut ffi::cubeb_stream) {
    let _ = Box::from_raw(s as *mut STM);
}

pub unsafe extern "C" fn capi_stream_start<STM: StreamOps>(s: *mut ffi::cubeb_stream) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.start());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_stop<STM: StreamOps>(s: *mut ffi::cubeb_stream) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.stop());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_reset_default_device<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.reset_default_device());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_get_position<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    position: *mut u64,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    *position = _try!(stm.position());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_get_latency<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    latency: *mut u32,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    *latency = _try!(stm.latency());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_set_volume<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    volume: f32,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.set_volume(volume));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_set_panning<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    panning: f32,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.set_panning(panning));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_get_current_device<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    device: *mut *mut ffi::cubeb_device,
) -> i32 {
    let stm = &mut *(s as *mut STM);

    *device = _try!(stm.current_device()).as_ptr();
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_device_destroy<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    device: *mut ffi::cubeb_device,
) -> c_int {
    let stm = &mut *(s as *mut STM);
    let device = DeviceRef::from_ptr(device);
    let _ = stm.device_destroy(device);
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_register_device_collection_changed<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    devtype: ffi::cubeb_device_type,
    collection_changed_callback: ffi::cubeb_device_collection_changed_callback,
    user_ptr: *mut c_void,
) -> i32 {
    let ctx = &mut *(c as *mut CTX);
    let devtype = DeviceType::from_bits_truncate(devtype);
    _try!(ctx.register_device_collection_changed(devtype, collection_changed_callback, user_ptr));
    ffi::CUBEB_OK
}

fn opt_cstr<T>(_anchor: &T, ptr: *const c_char) -> Option<&CStr> {
    if ptr.is_null() {
        None
    } else {
        Some(unsafe { CStr::from_ptr(ptr) })
    }
}
<commit_msg>Implement stream_register_device_changed_callback<commit_after>// Copyright © 2017 Mozilla Foundation
//
// This program is made available under an ISC-style license.  See the
// accompanying file LICENSE for details

use {ContextOps, StreamOps};
use cubeb_core::{ffi, DeviceCollectionRef, DeviceRef, DeviceType, StreamParams, StreamParamsRef};
use std::ffi::CStr;
use std::mem;
use std::os::raw::{c_char, c_int, c_void};

// Helper macro for unwrapping `Result` values from rust-api calls
// while returning early with a c-api error code if the value of the
// expression is `Err`.
macro_rules! _try(
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => return e.raw_code()
    })
);

macro_rules! as_opt_ref {
    ($e:expr) => {
        if $e.is_null() {
            None
        } else {
            Some(StreamParamsRef::from_ptr($e))
        }
    }
}

#[macro_export]
macro_rules! capi_new(
    ($ctx:ident, $stm:ident) => (
        Ops {
            init: Some($crate::capi::capi_init::<$ctx>),
            get_backend_id: Some($crate::capi::capi_get_backend_id::<$ctx>),
            get_max_channel_count: Some($crate::capi::capi_get_max_channel_count::<$ctx>),
            get_min_latency: Some($crate::capi::capi_get_min_latency::<$ctx>),
            get_preferred_sample_rate: Some($crate::capi::capi_get_preferred_sample_rate::<$ctx>),
            enumerate_devices: Some($crate::capi::capi_enumerate_devices::<$ctx>),
            device_collection_destroy: Some($crate::capi::capi_device_collection_destroy::<$ctx>),
            destroy: Some($crate::capi::capi_destroy::<$ctx>),
            stream_init: Some($crate::capi::capi_stream_init::<$ctx>),
            stream_destroy: Some($crate::capi::capi_stream_destroy::<$stm>),
            stream_start: Some($crate::capi::capi_stream_start::<$stm>),
            stream_stop: Some($crate::capi::capi_stream_stop::<$stm>),
            stream_reset_default_device:
                Some($crate::capi::capi_stream_reset_default_device::<$stm>),
            stream_get_position: Some($crate::capi::capi_stream_get_position::<$stm>),
            stream_get_latency: Some($crate::capi::capi_stream_get_latency::<$stm>),
            stream_set_volume: Some($crate::capi::capi_stream_set_volume::<$stm>),
            stream_set_panning: Some($crate::capi::capi_stream_set_panning::<$stm>),
            stream_get_current_device: Some($crate::capi::capi_stream_get_current_device::<$stm>),
            stream_device_destroy: Some($crate::capi::capi_stream_device_destroy::<$stm>),
            stream_register_device_changed_callback:
                Some($crate::capi::capi_stream_register_device_changed_callback::<$stm>),
            register_device_collection_changed:
                Some($crate::capi::capi_register_device_collection_changed::<$ctx>)
        }));

pub unsafe extern "C" fn capi_init<CTX: ContextOps>(
    c: *mut *mut ffi::cubeb,
    context_name: *const c_char,
) -> c_int {
    let anchor = &();
    let context_name = opt_cstr(anchor, context_name);
    let context = _try!(CTX::init(context_name));
    *c = context.as_ptr();
    // Leaking pointer across C FFI
    mem::forget(context);
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_backend_id<CTX: ContextOps>(c: *mut ffi::cubeb) -> *const c_char {
    let ctx = &mut *(c as *mut CTX);
    ctx.backend_id().as_ptr()
}

pub unsafe extern "C" fn capi_get_max_channel_count<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    max_channels: *mut u32,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);

    *max_channels = _try!(ctx.max_channel_count());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_min_latency<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    param: ffi::cubeb_stream_params,
    latency_frames: *mut u32,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let param = StreamParams::from(param);
    *latency_frames = _try!(ctx.min_latency(param));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_preferred_sample_rate<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    rate: *mut u32,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);

    *rate = _try!(ctx.preferred_sample_rate());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_enumerate_devices<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    devtype: ffi::cubeb_device_type,
    collection: *mut ffi::cubeb_device_collection,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let devtype = DeviceType::from_bits_truncate(devtype);
    let collection = DeviceCollectionRef::from_ptr(collection);
    _try!(ctx.enumerate_devices(devtype, collection));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_device_collection_destroy<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    collection: *mut ffi::cubeb_device_collection,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let collection = DeviceCollectionRef::from_ptr_mut(collection);
    let _ = ctx.device_collection_destroy(collection);
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_destroy<CTX>(c: *mut ffi::cubeb) {
    let _: Box<CTX> = Box::from_raw(c as *mut _);
}

pub unsafe extern "C" fn capi_stream_init<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    s: *mut *mut ffi::cubeb_stream,
    stream_name: *const c_char,
    input_device: ffi::cubeb_devid,
    input_stream_params: *mut ffi::cubeb_stream_params,
    output_device: ffi::cubeb_devid,
    output_stream_params: *mut ffi::cubeb_stream_params,
    latency_frames: u32,
    data_callback: ffi::cubeb_data_callback,
    state_callback: ffi::cubeb_state_callback,
    user_ptr: *mut c_void,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let anchor = &(); // for lifetime of stream_name as CStr

    let input_stream_params = as_opt_ref!(input_stream_params);
    let output_stream_params = as_opt_ref!(output_stream_params);

    let stream = _try!(ctx.stream_init(
        opt_cstr(anchor, stream_name),
        input_device,
        input_stream_params,
        output_device,
        output_stream_params,
        latency_frames,
        data_callback,
        state_callback,
        user_ptr
    ));
    *s = stream.as_ptr();
    // Leaking pointer across C FFI
    mem::forget(stream);
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_destroy<STM>(s: *mut ffi::cubeb_stream) {
    let _ = Box::from_raw(s as *mut STM);
}

pub unsafe extern "C" fn capi_stream_start<STM: StreamOps>(s: *mut ffi::cubeb_stream) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.start());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_stop<STM: StreamOps>(s: *mut ffi::cubeb_stream) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.stop());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_reset_default_device<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.reset_default_device());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_get_position<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    position: *mut u64,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    *position = _try!(stm.position());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_get_latency<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    latency: *mut u32,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    *latency = _try!(stm.latency());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_set_volume<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    volume: f32,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.set_volume(volume));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_set_panning<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    panning: f32,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.set_panning(panning));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_get_current_device<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    device: *mut *mut ffi::cubeb_device,
) -> i32 {
    let stm = &mut *(s as *mut STM);

    *device = _try!(stm.current_device()).as_ptr();
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_device_destroy<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    device: *mut ffi::cubeb_device,
) -> c_int {
    let stm = &mut *(s as *mut STM);
    let device = DeviceRef::from_ptr(device);
    let _ = stm.device_destroy(device);
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_register_device_changed_callback<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    device_changed_callback: ffi::cubeb_device_changed_callback,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.register_device_changed_callback(device_changed_callback));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_register_device_collection_changed<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    devtype: ffi::cubeb_device_type,
    collection_changed_callback: ffi::cubeb_device_collection_changed_callback,
    user_ptr: *mut c_void,
) -> i32 {
    let ctx = &mut *(c as *mut CTX);
    let devtype = DeviceType::from_bits_truncate(devtype);
    _try!(ctx.register_device_collection_changed(devtype, collection_changed_callback, user_ptr));
    ffi::CUBEB_OK
}

fn opt_cstr<T>(_anchor: &T, ptr: *const c_char) -> Option<&CStr> {
    if ptr.is_null() {
        None
    } else {
        Some(unsafe { CStr::from_ptr(ptr) })
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use serde::{Deserialize, Serialize};

#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum JsModuleFormat {
    CommonJS,
    Haste,
}

impl Default for JsModuleFormat {
    fn default() -> Self {
        JsModuleFormat::Haste
    }
}
<commit_msg>change default module format to CommonJS<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use serde::{Deserialize, Serialize};

/// Formatting style for generated files.
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum JsModuleFormat {
    /// Common JS style, e.g. `require('../path/MyModule')`
    CommonJS,
    /// Facebook style, e.g. `require('MyModule')`
    Haste,
}

impl Default for JsModuleFormat {
    fn default() -> Self {
        JsModuleFormat::CommonJS
    }
}
<|endoftext|>


<commit_before>use super::{ParserError, ParserResult};
use super::primitives::{PrimitiveIterator, U1, U2, U4};

use std::ops::Deref;
use std::rc::Rc;

macro_rules! generate_constant_pool_retrieval_method {
    ($variant_name:ident, $struct_name:ident, $method_name:ident) => {
        pub fn $method_name(index: usize,
                            constant_pool: &Vec<ConstantPoolItem>)
            -> ParserResult<Rc<$struct_name>> {
                let actual_index = ConstantPoolItem::shift_index(index);

                if let Some(item) = constant_pool.get(actual_index) {
                    match item {
                        &ConstantPoolItem::$variant_name(ref val) => return Ok(val.clone()),
                        item @ _ => {
                            let name = item.to_friendly_name();
                            return Err(ParserError::UnexpectedConstantPoolItem(name))
                        }
                    }
                }

                Err(ParserError::ConstantPoolIndexOutOfBounds(actual_index))
            }

    }
}

#[derive(Debug)]
pub struct ClassInfo {
    pub tag: U1,
    pub name_index: U2,
}

#[derive(Debug)]
pub struct FieldOrMethodOrInterfaceMethodInfo {
    pub tag: U1,
    pub class_index: U2,
    pub name_and_type_index: U2,
}

#[derive(Debug)]
pub struct StringInfo {
    pub tag: U1,
    pub string_index: U2,
}

#[derive(Debug)]
pub struct NameAndTypeInfo {
    pub tag: U1,
    pub name_index: U2,
    pub descriptor_index: U2,
}

#[derive(Debug)]
pub struct Utf8Info {
    pub tag: U1,
    pub length: U2,
    pub value: String,
}

impl Deref for Utf8Info {
    type Target = str;

    fn deref(&self) -> &str {
        &self.value
    }
}

#[derive(Debug)]
pub enum ConstantPoolItem {
    Class(Rc<ClassInfo>),
    FieldOrMethodOrInterfaceMethod(Rc<FieldOrMethodOrInterfaceMethodInfo>),
    String(Rc<StringInfo>),
    IntegerOrFloat { tag: U1, bytes: U1 },
    LongOrDouble {
        tag: U1,
        high_bytes: U4,
        low_bytes: U4,
    },
    NameAndType(Rc<NameAndTypeInfo>),
    Utf8(Rc<Utf8Info>),
    MethodHandle {
        tag: U1,
        reference_kind: U1,
        reference_index: U2,
    },
    MethodType { tag: U1, descriptor_index: U2 },
    InvokeDynamic {
        tag: U1,
        bootstrap_method_attr_index: U2,
        name_and_type_index: U2,
    },
}

impl ConstantPoolItem {
    pub fn from<T: PrimitiveIterator>(iter: &mut T) -> ParserResult<ConstantPoolItem> {
        let tag = try!(iter.next_u1());

        match tag {
            1 => {
                let length = try!(iter.next_u2());

                let mut byte_vec = vec![];
                for _ in 0..length {
                    byte_vec.push(try!(iter.next_u1()));
                }

                let value = try!(String::from_utf8(byte_vec));

                Ok(ConstantPoolItem::Utf8(Rc::new(Utf8Info {
                    tag: tag,
                    length: length,
                    value: value,
                })))
            }
            7 => {
                Ok(ConstantPoolItem::Class(Rc::new(ClassInfo {
                    tag: tag,
                    name_index: try!(iter.next_u2()),
                })))
            }
            8 => {
                Ok(ConstantPoolItem::String(Rc::new(StringInfo {
                    tag: tag,
                    string_index: try!(iter.next_u2()),
                })))
            }
            9 | 10 | 11 => {
                Ok(ConstantPoolItem::FieldOrMethodOrInterfaceMethod(
                        Rc::new(FieldOrMethodOrInterfaceMethodInfo {
                    tag: tag,
                    class_index: try!(iter.next_u2()),
                    name_and_type_index: try!(iter.next_u2()),
                })))
            }
            12 => {
                Ok(ConstantPoolItem::NameAndType(Rc::new(NameAndTypeInfo {
                    tag: tag,
                    name_index: try!(iter.next_u2()),
                    descriptor_index: try!(iter.next_u2()),
                })))
            }
            _ => Err(ParserError::UnknownConstantPoolTag(tag)),
        }
    }

    #[cfg_attr(rustfmt, rustfmt_skip)]
    pub fn to_friendly_name(&self) -> &'static str {
        match self {
            &ConstantPoolItem::Utf8(..) => "Utf8",
            &ConstantPoolItem::Class(..) => "Class",
            &ConstantPoolItem::String(..) => "String",
            &ConstantPoolItem::FieldOrMethodOrInterfaceMethod(..) =>
                "Field|Method|InterfaceMethod",
                &ConstantPoolItem::NameAndType(..) => "NameAndType",
                _ => "Not yet implemented",
        }
    }

    pub fn retrieve_item(index: usize,
                         constant_pool: &Vec<ConstantPoolItem>)
                         -> ParserResult<&ConstantPoolItem> {
        let actual_index = Self::shift_index(index);
        return constant_pool.get(index)
            .ok_or(ParserError::ConstantPoolIndexOutOfBounds(actual_index));
    }

    generate_constant_pool_retrieval_method!(Class, ClassInfo, retrieve_class_info);
    generate_constant_pool_retrieval_method!(Utf8, Utf8Info, retrieve_utf8_info);

    fn shift_index(unshifted_index: usize) -> usize {
        unshifted_index - 1 // references to the constant pool start from one
    }
}

#[derive(Debug)]
pub struct CodeAttribute {
    pub attribute_name: Rc<Utf8Info>,
    pub max_stack: U2,
    pub max_locals: U2,
    pub code_length: U4,
    pub code: Vec<U1>,
    pub exception_table_length: U2,
    pub exception_table: Vec<ExceptionHandler>,
    pub attributes_count: U2,
    pub attributes: Vec<Attribute>,
}

impl CodeAttribute {
    pub fn from<T: PrimitiveIterator>(attribute_name: Rc<Utf8Info>,
                                      iter: &mut T,
                                      constant_pool: &Vec<ConstantPoolItem>)
                                      -> ParserResult<CodeAttribute> {
        let max_stack = try!(iter.next_u2());
        let max_locals = try!(iter.next_u2());

        let code_length = try!(iter.next_u4());
        let mut code = vec![];
        for _ in 0..code_length {
            code.push(try!(iter.next_u1()));
        }

        let exception_table_length = try!(iter.next_u2());
        let mut exception_table = vec![];
        for _ in 0..exception_table_length {
            exception_table.push(try!(ExceptionHandler::from(iter)));
        }

        let attributes_count = try!(iter.next_u2());
        let mut attributes = vec![];
        for _ in 0..attributes_count {
            attributes.push(try!(Attribute::from(iter, constant_pool)));
        }

        Ok(CodeAttribute {
            attribute_name: attribute_name,
            max_stack: max_stack,
            max_locals: max_locals,
            code_length: code_length,
            code: code,
            exception_table_length: exception_table_length,
            exception_table: exception_table,
            attributes_count: attributes_count,
            attributes: attributes,
        })
    }
}

#[derive(Debug)]
pub struct ExceptionHandler {
    pub start_pc: U2,
    pub end_pc: U2,
    pub handler_pc: U2,
    pub catch_type: U2,
}

impl ExceptionHandler {
    pub fn from<T: PrimitiveIterator>(iter: &mut T) -> ParserResult<ExceptionHandler> {
        let start_pc = try!(iter.next_u2());
        let end_pc = try!(iter.next_u2());
        let handler_pc = try!(iter.next_u2());
        let catch_type = try!(iter.next_u2());

        Ok(ExceptionHandler {
            start_pc: start_pc,
            end_pc: end_pc,
            handler_pc: handler_pc,
            catch_type: catch_type,
        })
    }
}

#[derive(Debug)]
pub enum Attribute {
    Code(Rc<CodeAttribute>),
    Unknown {
        attribute_name: Rc<Utf8Info>,
        info: Vec<U1>,
    },
}

impl Attribute {
    pub fn from<T: PrimitiveIterator>(iter: &mut T,
                                      constant_pool: &Vec<ConstantPoolItem>)
                                      -> ParserResult<Attribute> {
        let attribute_name_index = try!(iter.next_u2());
        let attribute_name =
            try!(ConstantPoolItem::retrieve_utf8_info(attribute_name_index as usize,
                                                      constant_pool));

        let attribute_length = try!(iter.next_u4());

        match &**attribute_name {
            "Code" => {
                Ok(Attribute::Code(Rc::new(try!(CodeAttribute::from(attribute_name,
                                                                    iter,
                                                                    constant_pool)))))
            }
            _ => {
                let mut info = vec![];
                for _ in 0..attribute_length {
                    info.push(try!(iter.next_u1()));
                }

                Ok(Attribute::Unknown {
                    attribute_name: attribute_name,
                    info: info,
                })
            }
        }
    }
}

macro_rules! generate_method_or_field_parser_impl {
    ($impl_name:ident) => {
        impl $impl_name {
            pub fn from<T: PrimitiveIterator>(iter: &mut T,
                                              constant_pool: &Vec<ConstantPoolItem>)
                -> ParserResult<$impl_name> {
                    let access_flags = try!(iter.next_u2());

                    let name_index = try!(iter.next_u2());
                    let name = try!(ConstantPoolItem::retrieve_utf8_info(name_index as usize,
                                                                         constant_pool));

                    let descriptor_index = try!(iter.next_u2());
                    let descriptor = try!(ConstantPoolItem::retrieve_utf8_info(
                            descriptor_index as usize,
                            constant_pool));

                    let attributes_count = try!(iter.next_u2());
                    let mut attributes = vec![];
                    for _ in 0..attributes_count {
                        attributes.push(Rc::new(try!(Attribute::from(iter, constant_pool))));
                    }

                    Ok($impl_name {
                        access_flags: access_flags,
                        name: name,
                        descriptor: descriptor,
                        attributes_count: attributes_count,
                        attributes: attributes,
                    })

                }
        }
    }
}

#[derive(Debug)]
pub struct Field {
    pub access_flags: U2,
    pub name: Rc<Utf8Info>,
    pub descriptor: Rc<Utf8Info>,
    pub attributes_count: U2,
    pub attributes: Vec<Rc<Attribute>>,
}

#[derive(Debug)]
pub struct Method {
    pub access_flags: U2,
    pub name: Rc<Utf8Info>,
    pub descriptor: Rc<Utf8Info>,
    pub attributes_count: U2,
    pub attributes: Vec<Rc<Attribute>>,
}

generate_method_or_field_parser_impl!(Field);
generate_method_or_field_parser_impl!(Method);

pub struct AccessFlags;

impl AccessFlags {
    pub fn is_public(access_flags: U2) -> bool {
        (access_flags & 0x0001) != 0
    }

    pub fn is_private(access_flags: U2) -> bool {
        (access_flags & 0x0002) != 0
    }

    pub fn is_protected(access_flags: U2) -> bool {
        (access_flags & 0x0004) != 0
    }

    pub fn is_static(access_flags: U2) -> bool {
        (access_flags & 0x0008) != 0
    }

    pub fn is_final(access_flags: U2) -> bool {
        (access_flags & 0x0010) != 0
    }

    pub fn is_super(access_flags: U2) -> bool {
        (access_flags & 0x0020) != 0
    }

    pub fn is_volatile(access_flags: U2) -> bool {
        (access_flags & 0x0040) != 0
    }

    pub fn is_bridge(access_flags: U2) -> bool {
        (access_flags & 0x0040) != 0
    }

    pub fn is_transient(access_flags: U2) -> bool {
        (access_flags & 0x0080) != 0
    }

    pub fn is_varargs(access_flags: U2) -> bool {
        (access_flags & 0x0080) != 0
    }

    pub fn is_native(access_flags: U2) -> bool {
        (access_flags & 0x0100) != 0
    }

    pub fn is_interface(access_flags: U2) -> bool {
        (access_flags & 0x0200) != 0
    }

    pub fn is_abstract(access_flags: U2) -> bool {
        (access_flags & 0x0400) != 0
    }

    pub fn is_strict(access_flags: U2) -> bool {
        (access_flags & 0x0800) != 0
    }

    pub fn is_synthetic(access_flags: U2) -> bool {
        (access_flags & 0x1000) != 0
    }

    pub fn is_annotation(access_flags: U2) -> bool {
        (access_flags & 0x2000) != 0
    }

    pub fn is_enum(access_flags: U2) -> bool {
        (access_flags & 0x4000) != 0
    }
}
<commit_msg>Add additional constant pool retrieval methods<commit_after>use super::{ParserError, ParserResult};
use super::primitives::{PrimitiveIterator, U1, U2, U4};

use std::ops::Deref;
use std::rc::Rc;

macro_rules! generate_constant_pool_retrieval_method {
    ($variant_name:ident, $struct_name:ident, $method_name:ident) => {
        pub fn $method_name(index: usize,
                            constant_pool: &Vec<ConstantPoolItem>)
            -> ParserResult<Rc<$struct_name>> {
                let actual_index = ConstantPoolItem::shift_index(index);

                if let Some(item) = constant_pool.get(actual_index) {
                    match item {
                        &ConstantPoolItem::$variant_name(ref val) => return Ok(val.clone()),
                        item @ _ => {
                            let name = item.to_friendly_name();
                            return Err(ParserError::UnexpectedConstantPoolItem(name))
                        }
                    }
                }

                Err(ParserError::ConstantPoolIndexOutOfBounds(actual_index))
            }

    }
}

#[derive(Debug)]
pub struct ClassInfo {
    pub tag: U1,
    pub name_index: U2,
}

#[derive(Debug)]
pub struct FieldOrMethodOrInterfaceMethodInfo {
    pub tag: U1,
    pub class_index: U2,
    pub name_and_type_index: U2,
}

#[derive(Debug)]
pub struct StringInfo {
    pub tag: U1,
    pub string_index: U2,
}

#[derive(Debug)]
pub struct NameAndTypeInfo {
    pub tag: U1,
    pub name_index: U2,
    pub descriptor_index: U2,
}

#[derive(Debug)]
pub struct Utf8Info {
    pub tag: U1,
    pub length: U2,
    pub value: String,
}

impl Deref for Utf8Info {
    type Target = str;

    fn deref(&self) -> &str {
        &self.value
    }
}

#[derive(Debug)]
pub enum ConstantPoolItem {
    Class(Rc<ClassInfo>),
    FieldOrMethodOrInterfaceMethod(Rc<FieldOrMethodOrInterfaceMethodInfo>),
    String(Rc<StringInfo>),
    IntegerOrFloat { tag: U1, bytes: U1 },
    LongOrDouble {
        tag: U1,
        high_bytes: U4,
        low_bytes: U4,
    },
    NameAndType(Rc<NameAndTypeInfo>),
    Utf8(Rc<Utf8Info>),
    MethodHandle {
        tag: U1,
        reference_kind: U1,
        reference_index: U2,
    },
    MethodType { tag: U1, descriptor_index: U2 },
    InvokeDynamic {
        tag: U1,
        bootstrap_method_attr_index: U2,
        name_and_type_index: U2,
    },
}

impl ConstantPoolItem {
    pub fn from<T: PrimitiveIterator>(iter: &mut T) -> ParserResult<ConstantPoolItem> {
        let tag = try!(iter.next_u1());

        match tag {
            1 => {
                let length = try!(iter.next_u2());

                let mut byte_vec = vec![];
                for _ in 0..length {
                    byte_vec.push(try!(iter.next_u1()));
                }

                let value = try!(String::from_utf8(byte_vec));

                Ok(ConstantPoolItem::Utf8(Rc::new(Utf8Info {
                    tag: tag,
                    length: length,
                    value: value,
                })))
            }
            7 => {
                Ok(ConstantPoolItem::Class(Rc::new(ClassInfo {
                    tag: tag,
                    name_index: try!(iter.next_u2()),
                })))
            }
            8 => {
                Ok(ConstantPoolItem::String(Rc::new(StringInfo {
                    tag: tag,
                    string_index: try!(iter.next_u2()),
                })))
            }
            9 | 10 | 11 => {
                Ok(ConstantPoolItem::FieldOrMethodOrInterfaceMethod(
                        Rc::new(FieldOrMethodOrInterfaceMethodInfo {
                    tag: tag,
                    class_index: try!(iter.next_u2()),
                    name_and_type_index: try!(iter.next_u2()),
                })))
            }
            12 => {
                Ok(ConstantPoolItem::NameAndType(Rc::new(NameAndTypeInfo {
                    tag: tag,
                    name_index: try!(iter.next_u2()),
                    descriptor_index: try!(iter.next_u2()),
                })))
            }
            _ => Err(ParserError::UnknownConstantPoolTag(tag)),
        }
    }

    #[cfg_attr(rustfmt, rustfmt_skip)]
    pub fn to_friendly_name(&self) -> &'static str {
        match self {
            &ConstantPoolItem::Utf8(..) => "Utf8",
            &ConstantPoolItem::Class(..) => "Class",
            &ConstantPoolItem::String(..) => "String",
            &ConstantPoolItem::FieldOrMethodOrInterfaceMethod(..) =>
                "Field|Method|InterfaceMethod",
                &ConstantPoolItem::NameAndType(..) => "NameAndType",
                _ => "Not yet implemented",
        }
    }

    pub fn retrieve_item(index: usize,
                         constant_pool: &Vec<ConstantPoolItem>)
                         -> ParserResult<&ConstantPoolItem> {
        let actual_index = Self::shift_index(index);
        return constant_pool.get(index)
            .ok_or(ParserError::ConstantPoolIndexOutOfBounds(actual_index));
    }

    generate_constant_pool_retrieval_method!(Class, ClassInfo, retrieve_class_info);
    generate_constant_pool_retrieval_method!(Utf8, Utf8Info, retrieve_utf8_info);

    // TODO: Split the enum/struct into seperate variants
    generate_constant_pool_retrieval_method!(FieldOrMethodOrInterfaceMethod,
                                             FieldOrMethodOrInterfaceMethodInfo,
                                             retrieve_field_info);
    generate_constant_pool_retrieval_method!(FieldOrMethodOrInterfaceMethod,
                                             FieldOrMethodOrInterfaceMethodInfo,
                                             retrieve_method_info);
    generate_constant_pool_retrieval_method!(FieldOrMethodOrInterfaceMethod,
                                             FieldOrMethodOrInterfaceMethodInfo,
                                             retrieve_interface_method_info);

    generate_constant_pool_retrieval_method!(String, StringInfo, retrieve_string_info);
    generate_constant_pool_retrieval_method!(NameAndType,
                                             NameAndTypeInfo,
                                             retrieve_name_and_type_info);

    fn shift_index(unshifted_index: usize) -> usize {
        unshifted_index - 1 // references to the constant pool start from one
    }
}

#[derive(Debug)]
pub struct CodeAttribute {
    pub attribute_name: Rc<Utf8Info>,
    pub max_stack: U2,
    pub max_locals: U2,
    pub code_length: U4,
    pub code: Vec<U1>,
    pub exception_table_length: U2,
    pub exception_table: Vec<ExceptionHandler>,
    pub attributes_count: U2,
    pub attributes: Vec<Attribute>,
}

impl CodeAttribute {
    pub fn from<T: PrimitiveIterator>(attribute_name: Rc<Utf8Info>,
                                      iter: &mut T,
                                      constant_pool: &Vec<ConstantPoolItem>)
                                      -> ParserResult<CodeAttribute> {
        let max_stack = try!(iter.next_u2());
        let max_locals = try!(iter.next_u2());

        let code_length = try!(iter.next_u4());
        let mut code = vec![];
        for _ in 0..code_length {
            code.push(try!(iter.next_u1()));
        }

        let exception_table_length = try!(iter.next_u2());
        let mut exception_table = vec![];
        for _ in 0..exception_table_length {
            exception_table.push(try!(ExceptionHandler::from(iter)));
        }

        let attributes_count = try!(iter.next_u2());
        let mut attributes = vec![];
        for _ in 0..attributes_count {
            attributes.push(try!(Attribute::from(iter, constant_pool)));
        }

        Ok(CodeAttribute {
            attribute_name: attribute_name,
            max_stack: max_stack,
            max_locals: max_locals,
            code_length: code_length,
            code: code,
            exception_table_length: exception_table_length,
            exception_table: exception_table,
            attributes_count: attributes_count,
            attributes: attributes,
        })
    }
}

#[derive(Debug)]
pub struct ExceptionHandler {
    pub start_pc: U2,
    pub end_pc: U2,
    pub handler_pc: U2,
    pub catch_type: U2,
}

impl ExceptionHandler {
    pub fn from<T: PrimitiveIterator>(iter: &mut T) -> ParserResult<ExceptionHandler> {
        let start_pc = try!(iter.next_u2());
        let end_pc = try!(iter.next_u2());
        let handler_pc = try!(iter.next_u2());
        let catch_type = try!(iter.next_u2());

        Ok(ExceptionHandler {
            start_pc: start_pc,
            end_pc: end_pc,
            handler_pc: handler_pc,
            catch_type: catch_type,
        })
    }
}

#[derive(Debug)]
pub enum Attribute {
    Code(Rc<CodeAttribute>),
    Unknown {
        attribute_name: Rc<Utf8Info>,
        info: Vec<U1>,
    },
}

impl Attribute {
    pub fn from<T: PrimitiveIterator>(iter: &mut T,
                                      constant_pool: &Vec<ConstantPoolItem>)
                                      -> ParserResult<Attribute> {
        let attribute_name_index = try!(iter.next_u2());
        let attribute_name =
            try!(ConstantPoolItem::retrieve_utf8_info(attribute_name_index as usize,
                                                      constant_pool));

        let attribute_length = try!(iter.next_u4());

        match &**attribute_name {
            "Code" => {
                Ok(Attribute::Code(Rc::new(try!(CodeAttribute::from(attribute_name,
                                                                    iter,
                                                                    constant_pool)))))
            }
            _ => {
                let mut info = vec![];
                for _ in 0..attribute_length {
                    info.push(try!(iter.next_u1()));
                }

                Ok(Attribute::Unknown {
                    attribute_name: attribute_name,
                    info: info,
                })
            }
        }
    }
}

macro_rules! generate_method_or_field_parser_impl {
    ($impl_name:ident) => {
        impl $impl_name {
            pub fn from<T: PrimitiveIterator>(iter: &mut T,
                                              constant_pool: &Vec<ConstantPoolItem>)
                -> ParserResult<$impl_name> {
                    let access_flags = try!(iter.next_u2());

                    let name_index = try!(iter.next_u2());
                    let name = try!(ConstantPoolItem::retrieve_utf8_info(name_index as usize,
                                                                         constant_pool));

                    let descriptor_index = try!(iter.next_u2());
                    let descriptor = try!(ConstantPoolItem::retrieve_utf8_info(
                            descriptor_index as usize,
                            constant_pool));

                    let attributes_count = try!(iter.next_u2());
                    let mut attributes = vec![];
                    for _ in 0..attributes_count {
                        attributes.push(Rc::new(try!(Attribute::from(iter, constant_pool))));
                    }

                    Ok($impl_name {
                        access_flags: access_flags,
                        name: name,
                        descriptor: descriptor,
                        attributes_count: attributes_count,
                        attributes: attributes,
                    })

                }
        }
    }
}

#[derive(Debug)]
pub struct Field {
    pub access_flags: U2,
    pub name: Rc<Utf8Info>,
    pub descriptor: Rc<Utf8Info>,
    pub attributes_count: U2,
    pub attributes: Vec<Rc<Attribute>>,
}

#[derive(Debug)]
pub struct Method {
    pub access_flags: U2,
    pub name: Rc<Utf8Info>,
    pub descriptor: Rc<Utf8Info>,
    pub attributes_count: U2,
    pub attributes: Vec<Rc<Attribute>>,
}

generate_method_or_field_parser_impl!(Field);
generate_method_or_field_parser_impl!(Method);

pub struct AccessFlags;

impl AccessFlags {
    pub fn is_public(access_flags: U2) -> bool {
        (access_flags & 0x0001) != 0
    }

    pub fn is_private(access_flags: U2) -> bool {
        (access_flags & 0x0002) != 0
    }

    pub fn is_protected(access_flags: U2) -> bool {
        (access_flags & 0x0004) != 0
    }

    pub fn is_static(access_flags: U2) -> bool {
        (access_flags & 0x0008) != 0
    }

    pub fn is_final(access_flags: U2) -> bool {
        (access_flags & 0x0010) != 0
    }

    pub fn is_super(access_flags: U2) -> bool {
        (access_flags & 0x0020) != 0
    }

    pub fn is_volatile(access_flags: U2) -> bool {
        (access_flags & 0x0040) != 0
    }

    pub fn is_bridge(access_flags: U2) -> bool {
        (access_flags & 0x0040) != 0
    }

    pub fn is_transient(access_flags: U2) -> bool {
        (access_flags & 0x0080) != 0
    }

    pub fn is_varargs(access_flags: U2) -> bool {
        (access_flags & 0x0080) != 0
    }

    pub fn is_native(access_flags: U2) -> bool {
        (access_flags & 0x0100) != 0
    }

    pub fn is_interface(access_flags: U2) -> bool {
        (access_flags & 0x0200) != 0
    }

    pub fn is_abstract(access_flags: U2) -> bool {
        (access_flags & 0x0400) != 0
    }

    pub fn is_strict(access_flags: U2) -> bool {
        (access_flags & 0x0800) != 0
    }

    pub fn is_synthetic(access_flags: U2) -> bool {
        (access_flags & 0x1000) != 0
    }

    pub fn is_annotation(access_flags: U2) -> bool {
        (access_flags & 0x2000) != 0
    }

    pub fn is_enum(access_flags: U2) -> bool {
        (access_flags & 0x4000) != 0
    }
}
<|endoftext|>


<commit_before>extern crate csv;
extern crate rustc_serialize;

#[macro_use]
extern crate text_io;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

struct IndexedDB(HashMap<String, HashMap<String, f32>>, HashMap<String, HashMap<String, f32>>);

fn load_db(path: &str) -> IndexedDB {
    let mut rdr = csv::Reader::from_file(path).unwrap().has_headers(false);
    let mut ratings: HashMap<String, HashMap<String, f32>> = HashMap::new();
    let mut features: HashMap<String, HashMap<String, f32>> = HashMap::new();

    for record in rdr.decode() {
        let (user_id, feat_id, rating): (String, String, f32) = record.unwrap();
        let (user_id2, feat_id2, rating2) = (user_id.clone(), feat_id.clone(), rating);

        match ratings.entry(user_id) {
            Vacant(entry) => {
                let mut user_ratings = HashMap::new();
                user_ratings.insert(feat_id, rating);
                entry.insert(user_ratings);
            }
            Occupied(entry) => {
                entry.into_mut().insert(feat_id, rating);
            }
        }

        match features.entry(feat_id2) {
            Vacant(entry) => {
                let mut movie_ratings = HashMap::new();
                movie_ratings.insert(user_id2, rating2);
                entry.insert(movie_ratings);
            }
            Occupied(entry) => {
                entry.into_mut().insert(user_id2, rating2);
            }
        }
    }

    IndexedDB(ratings, features)
}

fn deviation(db: &IndexedDB, feat_1: &str, feat_2: &str) -> (f32, usize) {
    let mut vec_a: Vec<f32> = Vec::new();
    let mut vec_b: Vec<f32> = Vec::new();

    if let Some(ref ratings_f1) = db.1.get(&String::from(feat_1)) {
        for (user_id, &rating_f1) in ratings_f1.iter() {
            if let Some(ratings_f2) = db.1.get(&String::from(feat_2)) {
                if let Some(&rating_f2) = ratings_f2.get(user_id) {
                    vec_a.push(rating_f1);
                    vec_b.push(rating_f2);
                }
            } else {
                panic!("1: feat_2 is not found!");
            }
        }
    } else {
        panic!("1: feat_1 is not found!");
    }

    let length = vec_a.len();
    let mut deviation = 0.0;
    for i in 0..length {
        deviation += (vec_a[i] - vec_b[i]) / length as f32;
    }

    (deviation, length)
}

// fn item_based_prediction_input(db: &mut IndexedDB,
//                                sim_fun: fn(&MovieDB, String, String) -> f32)
//                                -> f32 {
//     let user_id: String;
//     let movie_id: String;
//     println!("Enter user_id y movie_id:");
//     scan!("{} {}", user_id, movie_id);

//     match db.0.entry(user_id) {
//         Vacant(entry) => {
//             let mut ratings: HashMap<u32, f32> = HashMap::new();
//             let mut movie: u32;
//             let mut rating: f32;
//             for i in 0..10 {
//                 println!("Enter movie_id:");
//                 scan!("{}", movie);
//                 println!("Enter rating:");
//                 scan!("{}", rating);
//                 ratings.insert(movie, rating);
//                 match db.1.entry(user_id) {
//                     Vacant(usr_map) => {
//                         let mut user_rtngs: HashMap<u32, f32> = HashMap::new();
//                         user_rtngs.insert(user_id, rating);
//                         usr_map.insert(user_rtngs);
//                     }
//                     Occupied(usr_map) => {
//                         usr_map.into_mut().insert(user_id, rating);
//                     }
//                 }
//             }
//             entry.insert(ratings);
//         }
//         Occupied(_) => {}
//     }

//     sim_fun(&db, user_id, movie_id)
// }

fn main() {
    println!("Loading database, please wait...");
    let mut db = load_db("./data/db2.csv");
    // let mut db = load_db("../report01/data/BX-Dump/BX-Book-Ratings.csv");
    println!("Database ready!\n________________________________________________");

    println!("{}", deviation(&db, "Taylor Swift", "PSY"));
    println!("{}", deviation(&db, "PSY", "Whitney Houston"));
    println!("{}", deviation(&db, "Taylor Swift", "Whitney Houston"));

    // let mut ender: u32;
    // loop {
    //     println!("Press 1 to make a query with Slope One.\n\
    //               Press 2 to make a query with Adjusted Cosine.\n\
    //               Press 0 to exit: ");
    //     scan!("{}", ender);
    //     match ender {
    //         1 => {
    //             println!("Slope One");
    //         }
    //         2 => {
    //             println!("Item similarity");
    //         }
    //         0 => {
    //             break;
    //         }
    //         _ => {
    //             println!("Try again");
    //         }
    //     }
    //     println!("\n______________________________________________________");
    // }
    // println!("\nBye bytes...");
}
<commit_msg>Slope One is done :)<commit_after>extern crate csv;
extern crate rustc_serialize;

#[macro_use]
extern crate text_io;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

struct IndexedDB(HashMap<String, HashMap<String, f32>>, HashMap<String, HashMap<String, f32>>);

fn load_db(path: &str) -> IndexedDB {
    let mut rdr = csv::Reader::from_file(path).unwrap().has_headers(false);
    let mut ratings: HashMap<String, HashMap<String, f32>> = HashMap::new();
    let mut features: HashMap<String, HashMap<String, f32>> = HashMap::new();

    for record in rdr.decode() {
        let (user_id, feat_id, rating): (String, String, f32) = record.unwrap();
        let (user_id2, feat_id2, rating2) = (user_id.clone(), feat_id.clone(), rating);

        match ratings.entry(user_id) {
            Vacant(entry) => {
                let mut user_ratings = HashMap::new();
                user_ratings.insert(feat_id, rating);
                entry.insert(user_ratings);
            }
            Occupied(entry) => {
                entry.into_mut().insert(feat_id, rating);
            }
        }

        match features.entry(feat_id2) {
            Vacant(entry) => {
                let mut movie_ratings = HashMap::new();
                movie_ratings.insert(user_id2, rating2);
                entry.insert(movie_ratings);
            }
            Occupied(entry) => {
                entry.into_mut().insert(user_id2, rating2);
            }
        }
    }

    IndexedDB(ratings, features)
}

fn deviation(db: &IndexedDB, feat_1: &str, feat_2: &str) -> (f32, usize) {
    let mut vec_a: Vec<f32> = Vec::new();
    let mut vec_b: Vec<f32> = Vec::new();

    if let Some(ref ratings_f1) = db.1.get(&String::from(feat_1)) {
        for (user_id, &rating_f1) in ratings_f1.iter() {
            if let Some(ratings_f2) = db.1.get(&String::from(feat_2)) {
                if let Some(&rating_f2) = ratings_f2.get(user_id) {
                    vec_a.push(rating_f1);
                    vec_b.push(rating_f2);
                }
            } else {
                panic!("1: feat_2 is not found!");
            }
        }
    } else {
        panic!("1: feat_1 is not found!");
    }

    let length = vec_a.len();
    let mut deviation = 0.0;
    for i in 0..length {
        deviation += (vec_a[i] - vec_b[i]) / length as f32;
    }

    (deviation, length)
}

fn weighted_slope_one(db: &IndexedDB, user: &str, feat: &str) -> f32 {
    let mut num = 0.0;
    let mut den = 0.0;
    if let Some(ref ratings) = db.0.get(&String::from(user)) {
        for (feat_id, &rating) in ratings.iter() {
            let (dev, card) = deviation(&db, feat, feat_id);
            num += (dev + rating) * card as f32;
            den += card as f32;
        }
    } else {
        panic!("user is not found!");
    }

    num / den
}

// fn item_based_prediction_input(db: &mut IndexedDB,
//                                sim_fun: fn(&MovieDB, String, String) -> f32)
//                                -> f32 {
//     let user_id: String;
//     let movie_id: String;
//     println!("Enter user_id y movie_id:");
//     scan!("{} {}", user_id, movie_id);

//     match db.0.entry(user_id) {
//         Vacant(entry) => {
//             let mut ratings: HashMap<u32, f32> = HashMap::new();
//             let mut movie: u32;
//             let mut rating: f32;
//             for i in 0..10 {
//                 println!("Enter movie_id:");
//                 scan!("{}", movie);
//                 println!("Enter rating:");
//                 scan!("{}", rating);
//                 ratings.insert(movie, rating);
//                 match db.1.entry(user_id) {
//                     Vacant(usr_map) => {
//                         let mut user_rtngs: HashMap<u32, f32> = HashMap::new();
//                         user_rtngs.insert(user_id, rating);
//                         usr_map.insert(user_rtngs);
//                     }
//                     Occupied(usr_map) => {
//                         usr_map.into_mut().insert(user_id, rating);
//                     }
//                 }
//             }
//             entry.insert(ratings);
//         }
//         Occupied(_) => {}
//     }

//     sim_fun(&db, user_id, movie_id)
// }

fn main() {
    println!("Loading database, please wait...");
    let mut db = load_db("./data/db2.csv");
    // let mut db = load_db("../report01/data/BX-Dump/BX-Book-Ratings.csv");
    println!("Database ready!\n---------------------------------------------");

    // println!("{}", deviation(&db, "Taylor Swift", "PSY"));
    // println!("{}", deviation(&db, "PSY", "Whitney Houston"));
    // println!("{}", deviation(&db, "Taylor Swift", "Whitney Houston"));
    println!("{}", weighted_slope_one(&db, "Ben", "Whitney Houston"));

    // let mut ender: u32;
    // loop {
    //     println!("Press 1 to make a query with Slope One.\n\
    //               Press 2 to make a query with Adjusted Cosine.\n\
    //               Press 0 to exit: ");
    //     scan!("{}", ender);
    //     match ender {
    //         1 => {
    //             println!("Slope One");
    //         }
    //         2 => {
    //             println!("Item similarity");
    //         }
    //         0 => {
    //             break;
    //         }
    //         _ => {
    //             println!("Try again");
    //         }
    //     }
    //     println!("\n______________________________________________________");
    // }
    // println!("\nBye bytes...");
}
<|endoftext|>


<commit_before>//! Crate name parsing.
use crate::errors::*;
use crate::Dependency;
use crate::{get_manifest_from_path, get_manifest_from_url};

/// A crate specifier. This can be a plain name (e.g. `docopt`), a name and a versionreq (e.g.
/// `docopt@^0.8`), a URL, or a path.
#[derive(Debug)]
pub struct CrateName<'a>(&'a str);

impl<'a> CrateName<'a> {
    /// Create a new `CrateName`
    pub fn new(name: &'a str) -> Self {
        CrateName(name)
    }

    /// Get crate name
    pub fn name(&self) -> &str {
        self.0
    }

    /// Does this specify a versionreq?
    pub fn has_version(&self) -> bool {
        self.0.contains('@')
    }

    /// If this crate specifier includes a version (e.g. `docopt@0.8`), extract the name and
    /// version.
    pub fn parse_as_version(&self) -> Result<Option<Dependency>> {
        if self.has_version() {
            let xs: Vec<_> = self.0.splitn(2, '@').collect();
            let (name, version) = (xs[0], xs[1]);
            semver::VersionReq::parse(version).chain_err(|| "Invalid crate version requirement")?;

            Ok(Some(Dependency::new(name).set_version(version)))
        } else {
            Ok(None)
        }
    }

    /// Will parse this crate name on the assumption that it is a URI.
    pub fn parse_crate_name_from_uri(&self) -> Result<Option<Dependency>> {
        if let Some(manifest) = get_manifest_from_url(self.0)? {
            let crate_name = manifest.package_name()?;
            let available_features = manifest.features()?;
            Ok(Some(
                Dependency::new(crate_name)
                    .set_git(self.0, None, None, None)
                    .set_available_features(available_features),
            ))
        } else if self.is_path() {
            let path = std::path::Path::new(self.0);
            let manifest = get_manifest_from_path(path)?;
            let crate_name = manifest.package_name()?;
            let path = dunce::canonicalize(path)?;
            let available_features = manifest.features()?;
            Ok(Some(
                Dependency::new(crate_name)
                    .set_path(path)
                    .set_available_features(available_features),
            ))
        } else {
            Ok(None)
        }
    }

    fn is_path(&self) -> bool {
        // FIXME: how else can we check if the name is a (possibly invalid) path?
        self.0.contains('.') || self.0.contains('/') || self.0.contains('\\')
    }
}
<commit_msg>fix(add)!: Remove implicit git support<commit_after>//! Crate name parsing.
use crate::errors::*;
use crate::get_manifest_from_path;
use crate::Dependency;

/// A crate specifier. This can be a plain name (e.g. `docopt`), a name and a versionreq (e.g.
/// `docopt@^0.8`), a URL, or a path.
#[derive(Debug)]
pub struct CrateName<'a>(&'a str);

impl<'a> CrateName<'a> {
    /// Create a new `CrateName`
    pub fn new(name: &'a str) -> Self {
        CrateName(name)
    }

    /// Get crate name
    pub fn name(&self) -> &str {
        self.0
    }

    /// Does this specify a versionreq?
    pub fn has_version(&self) -> bool {
        self.0.contains('@')
    }

    /// If this crate specifier includes a version (e.g. `docopt@0.8`), extract the name and
    /// version.
    pub fn parse_as_version(&self) -> Result<Option<Dependency>> {
        if self.has_version() {
            let xs: Vec<_> = self.0.splitn(2, '@').collect();
            let (name, version) = (xs[0], xs[1]);
            semver::VersionReq::parse(version).chain_err(|| "Invalid crate version requirement")?;

            Ok(Some(Dependency::new(name).set_version(version)))
        } else {
            Ok(None)
        }
    }

    /// Will parse this crate name on the assumption that it is a URI.
    pub fn parse_crate_name_from_uri(&self) -> Result<Option<Dependency>> {
        if self.is_path() {
            let path = std::path::Path::new(self.0);
            let manifest = get_manifest_from_path(path)?;
            let crate_name = manifest.package_name()?;
            let path = dunce::canonicalize(path)?;
            let available_features = manifest.features()?;
            Ok(Some(
                Dependency::new(crate_name)
                    .set_path(path)
                    .set_available_features(available_features),
            ))
        } else {
            Ok(None)
        }
    }

    fn is_path(&self) -> bool {
        // FIXME: how else can we check if the name is a (possibly invalid) path?
        self.0.contains('.') || self.0.contains('/') || self.0.contains('\\')
    }
}
<|endoftext|>


<commit_before>static START_ADDR: u16 = 0x200;
static MEM_SIZE: uint = 4096;
pub static DISPLAY_WIDTH: uint = 64;
pub static DISPLAY_HEIGHT: uint = 32;

static fontset: [[u8, .. 5], .. 0x10] = [
    [0xF0, 0x90, 0x90, 0x90, 0xF0], // 0
    [0x20, 0x60, 0x20, 0x20, 0x70], // 1
    [0xF0, 0x10, 0xF0, 0x80, 0xF0], // 2
    [0xF0, 0x10, 0xF0, 0x10, 0xF0], // 3
    [0x90, 0x90, 0xF0, 0x10, 0x10], // 4
    [0xF0, 0x80, 0xF0, 0x10, 0xF0], // 5
    [0xF0, 0x80, 0xF0, 0x90, 0xF0], // 6
    [0xF0, 0x10, 0x20, 0x40, 0x40], // 7
    [0xF0, 0x90, 0xF0, 0x90, 0xF0], // 8
    [0xF0, 0x90, 0xF0, 0x10, 0xF0], // 9
    [0xF0, 0x90, 0xF0, 0x90, 0x90], // A
    [0xE0, 0x90, 0xE0, 0x90, 0xE0], // B
    [0xF0, 0x80, 0x80, 0x80, 0xF0], // C
    [0xE0, 0x90, 0x90, 0x90, 0xE0], // D
    [0xF0, 0x80, 0xF0, 0x80, 0xF0], // E
    [0xF0, 0x80, 0xF0, 0x80, 0x80], // F
];

pub struct Chip8 {
    ram: [u8, .. MEM_SIZE],
    v: [u8, .. 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16, .. 16],
    display: [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT]
}

impl Chip8 {
    pub fn new() -> Chip8 {
        Chip8 {
            ram: [0u8, .. MEM_SIZE],
            v: [0u8, .. 16],
            i: 0u16,
            delay_timer: 0u8,
            sound_timer: 0u8,
            pc: START_ADDR,
            sp: 0,
            stack: [0u16, .. 16],
            display: [0u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT]
        }
    }

    pub fn load_rom(&mut self, rom: &[u8]) {
        use std::slice::bytes::copy_memory;
        let len = self.ram.len();
        copy_memory(self.ram.mut_slice(START_ADDR as uint, len), rom);
    }

    pub fn get_display(&self) -> [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT] {
        self.display
    }

    pub fn do_cycle(&mut self) {
        let ins = self.get_ins();
        self.pc += 2;

        match ins & 0xF000 {
            0x1000 => self.jump_addr(ins & 0x0FFF),
            0x3000 => self.skip_next_vx_eq(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0x6000 => self.set_vx_byte(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0x7000 => self.add_vx_byte(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0xA000 => self.set_i(ins & 0x0FFF),
            0xC000 => self.set_vx_rand_and(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0xD000 => self.display_sprite(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint, ((ins & 0x000F)) as uint),
            _ => fail!("Unkown instruction: {:x}", ins)
        }
    }

    fn get_ins(&self) -> u16 {
        let b1 = self.ram[self.pc as uint];
        let b2 = self.ram[(self.pc + 1) as uint];
        b1 as u16 << 8 | b2 as u16
    }

    fn set_i(&mut self, to: u16) {
        self.i = to;
    }

    fn set_vx_rand_and(&mut self, x: uint, to: u8) {
        use std::rand::{task_rng, Rng};
        let mut rgen = task_rng();
        self.v[x] = rgen.gen::<u8>() & to;
    }

    fn skip_next_vx_eq(&mut self, x: uint, to: u8) {
        if self.v[x] == to {
            self.pc += 2;
        }
    }

    fn display_sprite(&mut self, vx: uint, vy: uint, n: uint) {
        let x_off = self.v[vx] as uint;
        let y_off = self.v[vy] as uint * DISPLAY_WIDTH;
        let offset = x_off + y_off;

        for mut y in range(0u, n) {
            if y >= DISPLAY_HEIGHT {
                y = y - DISPLAY_HEIGHT;
            }
            let b = self.ram[self.i as uint + y];
            for mut x in range(0u, 8) {
                if x >= DISPLAY_WIDTH {
                    x = x - DISPLAY_WIDTH;
                }
                let idx = offset + (y * DISPLAY_WIDTH) + x;
                if idx < DISPLAY_WIDTH * DISPLAY_HEIGHT {
                    self.display[idx] ^= b & (0b10000000 >> x);
                } else {
                    println!("Warning: Out of bounds VRAM write: {}", idx);
                }
            }
        }
    }

    fn add_vx_byte(&mut self, x: uint, byte: u8) {
        self.v[x] += byte;
    }

    fn set_vx_byte(&mut self, x: uint, byte: u8) {
        self.v[x] = byte;
    }

    fn jump_addr(&mut self, addr: u16) {
        self.pc = addr;
    }
}
<commit_msg>Implement opcodes for stars example<commit_after>use std::slice::bytes::copy_memory;

static START_ADDR: u16 = 0x200;
static MEM_SIZE: uint = 4096;
pub static DISPLAY_WIDTH: uint = 64;
pub static DISPLAY_HEIGHT: uint = 32;

static fontset: [[u8, .. 5], .. 0x10] = [
    [0xF0, 0x90, 0x90, 0x90, 0xF0], // 0
    [0x20, 0x60, 0x20, 0x20, 0x70], // 1
    [0xF0, 0x10, 0xF0, 0x80, 0xF0], // 2
    [0xF0, 0x10, 0xF0, 0x10, 0xF0], // 3
    [0x90, 0x90, 0xF0, 0x10, 0x10], // 4
    [0xF0, 0x80, 0xF0, 0x10, 0xF0], // 5
    [0xF0, 0x80, 0xF0, 0x90, 0xF0], // 6
    [0xF0, 0x10, 0x20, 0x40, 0x40], // 7
    [0xF0, 0x90, 0xF0, 0x90, 0xF0], // 8
    [0xF0, 0x90, 0xF0, 0x10, 0xF0], // 9
    [0xF0, 0x90, 0xF0, 0x90, 0x90], // A
    [0xE0, 0x90, 0xE0, 0x90, 0xE0], // B
    [0xF0, 0x80, 0x80, 0x80, 0xF0], // C
    [0xE0, 0x90, 0x90, 0x90, 0xE0], // D
    [0xF0, 0x80, 0xF0, 0x80, 0xF0], // E
    [0xF0, 0x80, 0xF0, 0x80, 0x80], // F
];

pub struct Chip8 {
    ram: [u8, .. MEM_SIZE],
    v: [u8, .. 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16, .. 16],
    display: [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT]
}

impl Chip8 {

    pub fn new() -> Chip8 {
        Chip8 {
            ram: [0u8, .. MEM_SIZE],
            v: [0u8, .. 16],
            i: 0u16,
            delay_timer: 0u8,
            sound_timer: 0u8,
            pc: START_ADDR,
            sp: 0,
            stack: [0u16, .. 16],
            display: [0u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT]
        }
    }

    pub fn load_rom(&mut self, rom: &[u8]) {
        let len = self.ram.len();
        copy_memory(self.ram.mut_slice(START_ADDR as uint, len), rom);
    }

    pub fn get_display(&self) -> [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT] {
        self.display
    }

    pub fn do_cycle(&mut self) {
        let ins = self.get_ins();
        self.pc += 2;

        match ins & 0xF000 {
            0x1000 => self.jump_addr(ins & 0x0FFF),
            0x3000 => self.skip_next_vx_eq(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0x5000 => match ins & 0x000F {
                0x0000 => self.skip_next_vx_eq_vy(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint),
                _ => fail!("Unknown 0x5XXX instruction: {:x}", ins)
            },
            0x6000 => self.set_vx_byte(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0x7000 => self.add_vx_byte(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0x8000 => match ins & 0x000F {
                0x0000 => self.set_vx_to_vy(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint),
                0x0004 => self.add_vx_vy(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint),
                0x0005 => self.sub_vx_vy(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint),
                _ => fail!("Unknown 0x8XXX instruction: {:x}", ins)
            },
            0x9000 => match ins & 0x000F {
                0x0000 => self.skip_next_vx_ne_vy(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint),
                _ => fail!("Unknown 0x9XXX instruction: {:x}", ins)
            },
            0xA000 => self.set_i(ins & 0x0FFF),
            0xC000 => self.set_vx_rand_and(((ins & 0x0F00) >> 8) as uint, (ins & 0x00FF) as u8),
            0xD000 => self.display_sprite(((ins & 0x0F00) >> 8) as uint, ((ins & 0x00F0) >> 4) as uint, ((ins & 0x000F)) as uint),
            0xF000 => match ins & 0x00FF {
                0x0055 => self.copy_v0_through_vx_to_mem(((ins & 0x0F00) >> 8) as uint),
                0x0065 => self.read_v0_through_vx_from_mem(((ins & 0x0F00) >> 8) as uint),
                0x001E => self.add_vx_to_i(((ins & 0x0F00) >> 8) as uint),
                _ => fail!("Unknown 0xFXXX instruction: {:x}", ins)
            },
            _ => fail!("Unknown instruction: {:x}", ins)
        }
    }

    fn get_ins(&self) -> u16 {
        let b1 = self.ram[self.pc as uint];
        let b2 = self.ram[(self.pc + 1) as uint];
        b1 as u16 << 8 | b2 as u16
    }

    fn set_i(&mut self, to: u16) {
        self.i = to;
    }

    fn set_vx_rand_and(&mut self, x: uint, to: u8) {
        use std::rand::{task_rng, Rng};
        let mut rgen = task_rng();
        self.v[x] = rgen.gen::<u8>() & to;
    }

    fn skip_next_vx_eq(&mut self, x: uint, to: u8) {
        if self.v[x] == to {
            self.pc += 2;
        }
    }

    fn display_sprite(&mut self, vx: uint, vy: uint, n: uint) {
        let x_off = self.v[vx] as uint;
        let y_off = self.v[vy] as uint * DISPLAY_WIDTH;
        let offset = x_off + y_off;

        for mut y in range(0u, n) {
            if y >= DISPLAY_HEIGHT {
                y = y - DISPLAY_HEIGHT;
            }
            let b = self.ram[self.i as uint + y];
            for mut x in range(0u, 8) {
                if x >= DISPLAY_WIDTH {
                    x = x - DISPLAY_WIDTH;
                }
                let idx = offset + (y * DISPLAY_WIDTH) + x;
                if idx < DISPLAY_WIDTH * DISPLAY_HEIGHT {
                    self.display[idx] ^= b & (0b10000000 >> x);
                } else {
                    println!("Warning: Out of bounds VRAM write: {}", idx);
                }
            }
        }
    }

    fn add_vx_byte(&mut self, x: uint, byte: u8) {
        self.v[x] += byte;
    }

    fn set_vx_byte(&mut self, x: uint, byte: u8) {
        self.v[x] = byte;
    }

    fn jump_addr(&mut self, addr: u16) {
        self.pc = addr;
    }

    fn set_vx_to_vy(&mut self, x: uint, y: uint) {
        self.v[x] = self.v[y];
    }

    fn add_vx_vy(&mut self, x: uint, y: uint) {
        let result = (self.v[x] + self.v[y]) as u16;
        self.v[0xF] = (result > 255) as u8;
        self.v[x] = result as u8;
    }

    fn sub_vx_vy(&mut self, x: uint, y: uint) {
        self.v[0xF] = (self.v[x] > self.v[y]) as u8;
        self.v[x] -= self.v[y];
    }

    fn add_vx_to_i(&mut self, x: uint) {
        self.i += x as u16;
    }

    fn copy_v0_through_vx_to_mem(&mut self, x: uint) {
        if x == 0 {
            return;
        }
        copy_memory(self.ram.mut_slice(self.i as uint, x), self.v.slice(0, x));
    }

    fn read_v0_through_vx_from_mem(&mut self, x: uint) {
        if x == 0 {
            return;
        }
        copy_memory(self.v.mut_slice(0, x), self.ram.slice(self.i as uint, x));
    }

    fn skip_next_vx_eq_vy(&mut self, x: uint, y: uint) {
        if self.v[x] == self.v[y] {
            self.pc += 2;
        }
    }

    fn skip_next_vx_ne_vy(&mut self, x: uint, y: uint) {
        if self.v[x] != self.v[y] {
            self.pc += 2;
        }
    }
}
<|endoftext|>


<commit_before>use sync::{Arc, Mutex};
use super::super::error::{MyDriverError, InvalidPoolConstraints};
use conn::{MyConn, MyOpts, MyResult, Stmt, QueryResult};

struct MyInnerPool {
    opts: MyOpts,
    pool: Vec<MyConn>,
    min: uint,
    max: uint,
    count: uint
}

impl MyInnerPool {
    fn new(min: uint, max: uint, opts: MyOpts) -> MyResult<MyInnerPool> {
        if min > max || max == 0 {
            return Err(MyDriverError(InvalidPoolConstraints));
        }
        let mut pool = MyInnerPool {
            opts: opts,
            pool: Vec::with_capacity(max),
            max: max,
            min: min,
            count: 0
        };
        for _ in range(0, min) {
            try!(pool.new_conn());
        }
        Ok(pool)
    }
    fn new_conn(&mut self) -> MyResult<()> {
        match MyConn::new(self.opts.clone()) {
            Ok(conn) => {
                self.pool.push(conn);
                Ok(())
            },
            Err(err) => Err(err)
        }
    }
}

#[deriving(Clone)]
pub struct MyPool {
    pool: Arc<Mutex<MyInnerPool>>
}

impl MyPool {
    pub fn new(opts: MyOpts) -> MyResult<MyPool> {
        MyPool::new_manual(10, 100, opts)
    }

    pub fn new_manual(min: uint, max: uint, opts: MyOpts) -> MyResult<MyPool> {
        let pool = try!(MyInnerPool::new(min, max, opts));
        Ok(MyPool{ pool: Arc::new(Mutex::new(pool)) })
    }

    pub fn get_conn(&self) -> MyResult<MyPooledConn> {
        let mut pool = self.pool.lock();

        while pool.pool.is_empty() {
            if pool.count < pool.max {
                match pool.new_conn() {
                    Ok(()) => {
                        pool.count += 1;
                        break;
                    },
                    Err(err) => return Err(err)
                }
            } else {
                pool.cond.wait();
            }
        }

        let mut conn = pool.pool.pop().unwrap();

        if !conn.ping() {
            try!(conn.reset());
        }

        Ok(MyPooledConn {pool: self.clone(), conn: Some(conn)})
    }
    pub fn query(&self, query: &str) -> MyResult<QueryResult> {
        let conn = try!(self.get_conn());
        conn.pooled_query(query)
    }
    pub fn prepare(&self, query: &str) -> MyResult<Stmt> {
        let conn = try!(self.get_conn());
        conn.pooled_prepare(query)
    }
}

pub struct MyPooledConn {
    pool: MyPool,
    conn: Option<MyConn>
}

impl Drop for MyPooledConn {
    fn drop(&mut self) {
        let mut pool = self.pool.pool.lock();
        if pool.count > pool.min {
            pool.count -= 1;
        } else {
            pool.pool.push(self.conn.take_unwrap());
        }
        pool.cond.signal();
    }
}

impl MyPooledConn {
    pub fn query<'a>(&'a mut self, query: &str) -> MyResult<QueryResult<'a>> {
        self.conn.get_mut_ref().query(query)
    }
    pub fn prepare<'a>(&'a mut self, query: &str) -> MyResult<Stmt<'a>> {
        self.conn.get_mut_ref().prepare(query)
    }
    pub fn get_mut_ref<'a>(&'a mut self) -> &'a mut MyConn {
        self.conn.get_mut_ref()
    }
    pub fn get_ref<'a>(&'a self) -> &'a MyConn {
        self.conn.get_ref()
    }
    fn pooled_query(mut self, query: &str) -> MyResult<QueryResult> {
        match self.get_mut_ref()._query(query) {
            Ok((columns, ok_packet)) => Ok(QueryResult::new_pooled(self, columns, ok_packet, false)),
            Err(err) => Err(err)
        }
    }
    fn pooled_prepare(mut self, query: &str) -> MyResult<Stmt> {
        match self.get_mut_ref()._prepare(query) {
            Ok(stmt) => Ok(Stmt::new_pooled(stmt, self)),
            Err(err) => Err(err)
        }
    }
}

#[cfg(test)]
mod test {
    use conn::{MyOpts};
    use std::default::{Default};
    use super::{MyPool};
    use super::super::super::value::{Bytes, Int};

    #[test]
    fn test_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let conn = pool.get_conn();
                assert!(conn.is_ok());
                let mut conn = conn.unwrap();
                assert!(conn.query("SELECT 1").is_ok());
            });
        }
    }

    #[test]
    fn test_pooled_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let result = pool.query("SELECT 1");
                assert!(result.is_ok());
                let mut result = result.unwrap();
                assert_eq!(result.next(), Some(Ok(vec![Bytes(vec![0x31u8])])));
            });
        }
    }

    #[test]
    fn test_prepared_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let conn = pool.get_conn();
                assert!(conn.is_ok());
                let mut conn = conn.unwrap();
                let stmt = conn.prepare("SELECT 1");
                assert!(stmt.is_ok());
                let mut stmt = stmt.unwrap();
                assert!(stmt.execute([]).is_ok());
            });
        }
    }

    #[test]
    fn test_pooled_prepared_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let stmt = pool.prepare("SELECT 1");
                assert!(stmt.is_ok());
                let mut stmt = stmt.unwrap();
                for _ in range(0u, 5u) {
                    let result = stmt.execute([]);
                    assert!(result.is_ok());
                    let mut result = result.unwrap();
                    assert_eq!(result.next(), Some(Ok(vec![Int(1)])));
                    assert_eq!(result.next(), None);
                }
            });
        }
    }
}
<commit_msg>Add `MyPooledConn::unwrap`<commit_after>use sync::{Arc, Mutex};
use super::super::error::{MyDriverError, InvalidPoolConstraints};
use conn::{MyConn, MyOpts, MyResult, Stmt, QueryResult};

struct MyInnerPool {
    opts: MyOpts,
    pool: Vec<MyConn>,
    min: uint,
    max: uint,
    count: uint
}

impl MyInnerPool {
    fn new(min: uint, max: uint, opts: MyOpts) -> MyResult<MyInnerPool> {
        if min > max || max == 0 {
            return Err(MyDriverError(InvalidPoolConstraints));
        }
        let mut pool = MyInnerPool {
            opts: opts,
            pool: Vec::with_capacity(max),
            max: max,
            min: min,
            count: 0
        };
        for _ in range(0, min) {
            try!(pool.new_conn());
        }
        Ok(pool)
    }
    fn new_conn(&mut self) -> MyResult<()> {
        match MyConn::new(self.opts.clone()) {
            Ok(conn) => {
                self.pool.push(conn);
                Ok(())
            },
            Err(err) => Err(err)
        }
    }
}

#[deriving(Clone)]
pub struct MyPool {
    pool: Arc<Mutex<MyInnerPool>>
}

impl MyPool {
    pub fn new(opts: MyOpts) -> MyResult<MyPool> {
        MyPool::new_manual(10, 100, opts)
    }

    pub fn new_manual(min: uint, max: uint, opts: MyOpts) -> MyResult<MyPool> {
        let pool = try!(MyInnerPool::new(min, max, opts));
        Ok(MyPool{ pool: Arc::new(Mutex::new(pool)) })
    }

    pub fn get_conn(&self) -> MyResult<MyPooledConn> {
        let mut pool = self.pool.lock();

        while pool.pool.is_empty() {
            if pool.count < pool.max {
                match pool.new_conn() {
                    Ok(()) => {
                        pool.count += 1;
                        break;
                    },
                    Err(err) => return Err(err)
                }
            } else {
                pool.cond.wait();
            }
        }

        let mut conn = pool.pool.pop().unwrap();

        if !conn.ping() {
            try!(conn.reset());
        }

        Ok(MyPooledConn {pool: self.clone(), conn: Some(conn)})
    }
    pub fn query(&self, query: &str) -> MyResult<QueryResult> {
        let conn = try!(self.get_conn());
        conn.pooled_query(query)
    }
    pub fn prepare(&self, query: &str) -> MyResult<Stmt> {
        let conn = try!(self.get_conn());
        conn.pooled_prepare(query)
    }
}

pub struct MyPooledConn {
    pool: MyPool,
    conn: Option<MyConn>
}

impl Drop for MyPooledConn {
    fn drop(&mut self) {
        let mut pool = self.pool.pool.lock();
        if pool.count > pool.min || self.conn.is_none() {
            pool.count -= 1;
        } else {
            pool.pool.push(self.conn.take_unwrap());
        }
        pool.cond.signal();
    }
}

impl MyPooledConn {
    pub fn query<'a>(&'a mut self, query: &str) -> MyResult<QueryResult<'a>> {
        self.conn.get_mut_ref().query(query)
    }
    pub fn prepare<'a>(&'a mut self, query: &str) -> MyResult<Stmt<'a>> {
        self.conn.get_mut_ref().prepare(query)
    }
    pub fn get_mut_ref<'a>(&'a mut self) -> &'a mut MyConn {
        self.conn.get_mut_ref()
    }
    pub fn get_ref<'a>(&'a self) -> &'a MyConn {
        self.conn.get_ref()
    }
    pub fn unwrap(mut self) -> MyConn {
        self.conn.take_unwrap()
    }
    fn pooled_query(mut self, query: &str) -> MyResult<QueryResult> {
        match self.get_mut_ref()._query(query) {
            Ok((columns, ok_packet)) => Ok(QueryResult::new_pooled(self, columns, ok_packet, false)),
            Err(err) => Err(err)
        }
    }
    fn pooled_prepare(mut self, query: &str) -> MyResult<Stmt> {
        match self.get_mut_ref()._prepare(query) {
            Ok(stmt) => Ok(Stmt::new_pooled(stmt, self)),
            Err(err) => Err(err)
        }
    }
}

#[cfg(test)]
mod test {
    use conn::{MyOpts};
    use std::default::{Default};
    use super::{MyPool};
    use super::super::super::value::{Bytes, Int};

    #[test]
    fn test_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let conn = pool.get_conn();
                assert!(conn.is_ok());
                let mut conn = conn.unwrap();
                assert!(conn.query("SELECT 1").is_ok());
            });
        }
    }

    #[test]
    fn test_pooled_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let result = pool.query("SELECT 1");
                assert!(result.is_ok());
                let mut result = result.unwrap();
                assert_eq!(result.next(), Some(Ok(vec![Bytes(vec![0x31u8])])));
            });
        }
    }

    #[test]
    fn test_prepared_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let conn = pool.get_conn();
                assert!(conn.is_ok());
                let mut conn = conn.unwrap();
                let stmt = conn.prepare("SELECT 1");
                assert!(stmt.is_ok());
                let mut stmt = stmt.unwrap();
                assert!(stmt.execute([]).is_ok());
            });
        }
    }

    #[test]
    fn test_pooled_prepared_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let stmt = pool.prepare("SELECT 1");
                assert!(stmt.is_ok());
                let mut stmt = stmt.unwrap();
                for _ in range(0u, 5u) {
                    let result = stmt.execute([]);
                    assert!(result.is_ok());
                    let mut result = result.unwrap();
                    assert_eq!(result.next(), Some(Ok(vec![Int(1)])));
                    assert_eq!(result.next(), None);
                }
            });
        }
    }
}
<|endoftext|>