<commit_before>//! # Environment life cycle APIs
//!
//! These APIs map to the life cycle of a specific "Agent" or self-contained
//! environment. If a Neon module is loaded multiple times (Web Workers, worker
//! threads), these API will be handle data associated with a specific instance.
//!
//! See the [N-API Lifecycle][npai-docs] documentation for more details.
//!
//! [napi-docs]: https://nodejs.org/api/n-api.html#n_api_environment_life_cycle_apis

use std::{
    any::Any,
    marker::PhantomData,
    sync::{
        atomic::{AtomicU64, Ordering},
        Arc,
    },
};

use crate::{
    context::Context,
    event::Channel,
    handle::root::NapiRef,
    result::NeonResult,
    sys::{lifecycle, raw::Env, tsfn::ThreadsafeFunction},
    types::promise::NodeApiDeferred,
};

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(transparent)]
/// Uniquely identifies an instance of the module
///
/// _Note_: Since `InstanceData` is created lazily, the order of `id` may not
/// reflect the order that instances were created.
pub(crate) struct InstanceId(u64);

impl InstanceId {
    fn next() -> Self {
        static NEXT_ID: AtomicU64 = AtomicU64::new(0);

        Self(NEXT_ID.fetch_add(1, Ordering::SeqCst))
    }
}

/// `InstanceData` holds Neon data associated with a particular instance of a
/// native module. If a module is loaded multiple times (e.g., worker threads), this
/// data will be unique per instance.
pub(crate) struct InstanceData {
    id: InstanceId,

    /// Used to free `Root` in the same JavaScript environment that created it
    ///
    /// _Design Note_: An `Arc` ensures the `ThreadsafeFunction` outlives the unloading
    /// of a module. Since it is unlikely that modules will be re-loaded frequently, this
    /// could be replaced with a leaked `&'static ThreadsafeFunction<NapiRef>`. However,
    /// given the cost of FFI, this optimization is omitted until the cost of an
    /// `Arc` is demonstrated as significant.
    drop_queue: Arc<ThreadsafeFunction<DropData>>,

    /// Shared `Channel` that is cloned to be returned by the `cx.channel()` method
    shared_channel: Channel,

    /// Table of user-defined global cells.
    globals: GlobalTable,
}

#[derive(Default)]
pub(crate) struct GlobalTable {
    cells: Vec<GlobalCell>,
}

pub(crate) enum GlobalCell {
    /// Uninitialized state.
    Uninit,
    /// Intermediate "dirty" state representing the middle of a `get_or_try_init` transaction.
    Trying,
    /// Fully initialized state.
    Init(Box<dyn Any + Send + 'static>),
}

pub(crate) type GlobalCellValue = Box<dyn Any + Send + 'static>;

impl GlobalCell {
    /// Establish the initial state at the beginning of the initialization protocol.
    /// This method ensures that re-entrant initialization always panics (i.e. when
    /// an existing `get_or_try_init` is in progress).
    fn pre_init<F>(&mut self, f: F)
    where
        F: FnOnce() -> GlobalCell,
    {
        match self {
            GlobalCell::Uninit => {
                *self = f();
            }
            GlobalCell::Trying => panic!("attempt to reinitialize Global during initialization"),
            GlobalCell::Init(_) => {}
        }
    }

    pub(crate) fn get<'cx, 'a, C>(cx: &'a mut C, id: usize) -> Option<&mut GlobalCellValue>
    where
        C: Context<'cx>,
    {
        let cell = InstanceData::globals(cx).get(id);
        match cell {
            GlobalCell::Init(ref mut b) => Some(b),
            _ => None,
        }
    }

    pub(crate) fn get_or_init<'cx, 'a, C>(
        cx: &'a mut C,
        id: usize,
        value: GlobalCellValue,
    ) -> &mut GlobalCellValue
    where
        C: Context<'cx>,
    {
        InstanceData::globals(cx)
            .get(id)
            .pre_init(|| GlobalCell::Init(value));

        GlobalCell::get(cx, id).unwrap()
    }

    pub(crate) fn get_or_init_with<'cx, 'a, C, F>(
        cx: &'a mut C,
        id: usize,
        f: F,
    ) -> &mut GlobalCellValue
    where
        C: Context<'cx>,
        F: FnOnce() -> GlobalCellValue,
    {
        InstanceData::globals(cx)
            .get(id)
            .pre_init(|| GlobalCell::Init(f()));

        GlobalCell::get(cx, id).unwrap()
    }

    pub(crate) fn get_or_try_init<'cx, 'a, C, F>(
        cx: &'a mut C,
        id: usize,
        f: F,
    ) -> NeonResult<&mut GlobalCellValue>
    where
        C: Context<'cx>,
        F: FnOnce(&mut C) -> NeonResult<GlobalCellValue>,
    {
        // Kick off a new transaction and drop it before getting the result.
        {
            let mut tx = TryInitTransaction::new(cx, id);
            tx.run(|cx| Ok(f(cx)?))?;
        }

        // If we're here, the transaction has succeeded, so get the result.
        Ok(GlobalCell::get(cx, id).unwrap())
    }
}

impl Default for GlobalCell {
    fn default() -> Self {
        GlobalCell::Uninit
    }
}

impl GlobalTable {
    pub(crate) fn get(&mut self, index: usize) -> &mut GlobalCell {
        if index >= self.cells.len() {
            self.cells.resize_with(index + 1, Default::default);
        }
        &mut self.cells[index]
    }
}

/// An RAII implementation of `GlobalCell::get_or_try_init`, which ensures that
/// the state of a cell is properly managed through all possible control paths.
/// As soon as the transaction begins, the cell is labelled as being in a dirty
/// state (`GlobalCell::Trying`), so that any additional re-entrant attempts to
/// initialize the cell will fail fast. The `Drop` implementation ensures that
/// after the transaction, the cell goes back to a clean state of either
/// `GlobalCell::Uninit` if it fails or `GlobalCell::Init` if it succeeds.
struct TryInitTransaction<'cx, 'a, C: Context<'cx>> {
    cx: &'a mut C,
    id: usize,
    _lifetime: PhantomData<&'cx ()>,
}

impl<'cx, 'a, C: Context<'cx>> TryInitTransaction<'cx, 'a, C> {
    fn new(cx: &'a mut C, id: usize) -> Self {
        let mut tx = Self {
            cx,
            id,
            _lifetime: PhantomData,
        };
        tx.cell().pre_init(|| GlobalCell::Trying);
        tx
    }

    /// _Post-condition:_ If this method returns an `Ok` result, the cell is in the
    /// `GlobalCell::Init` state.
    fn run<F>(&mut self, f: F) -> NeonResult<()>
    where
        F: FnOnce(&mut C) -> NeonResult<GlobalCellValue>,
    {
        if self.is_trying() {
            let value = f(self.cx)?;
            *self.cell() = GlobalCell::Init(value);
        }
        Ok(())
    }

    fn cell(&mut self) -> &mut GlobalCell {
        InstanceData::globals(self.cx).get(self.id)
    }

    fn is_trying(&mut self) -> bool {
        if let GlobalCell::Trying = *self.cell() {
            true
        } else {
            false
        }
    }
}

impl<'cx, 'a, C: Context<'cx>> Drop for TryInitTransaction<'cx, 'a, C> {
    fn drop(&mut self) {
        if self.is_trying() {
            *self.cell() = GlobalCell::Uninit;
        }
    }
}

/// Wrapper for raw Node-API values to be dropped on the main thread
pub(crate) enum DropData {
    Deferred(NodeApiDeferred),
    Ref(NapiRef),
}

impl DropData {
    /// Drop a value on the main thread
    fn drop(env: Option<Env>, data: Self) {
        if let Some(env) = env {
            unsafe {
                match data {
                    DropData::Deferred(data) => data.leaked(env),
                    DropData::Ref(data) => data.unref(env),
                }
            }
        }
    }
}

impl InstanceData {
    /// Return the data associated with this module instance, lazily initializing if
    /// necessary.
    ///
    /// # Safety
    /// No additional locking (e.g., `Mutex`) is necessary because holding a
    /// `Context` reference ensures serialized access.
    pub(crate) fn get<'cx, C: Context<'cx>>(cx: &mut C) -> &mut InstanceData {
        let env = cx.env().to_raw();
        let data = unsafe { lifecycle::get_instance_data::<InstanceData>(env).as_mut() };

        if let Some(data) = data {
            return data;
        }

        let drop_queue = unsafe {
            let queue = ThreadsafeFunction::new(env, DropData::drop);
            queue.unref(env);
            queue
        };

        let shared_channel = {
            let mut channel = Channel::new(cx);
            channel.unref(cx);
            channel
        };

        let data = InstanceData {
            id: InstanceId::next(),
            drop_queue: Arc::new(drop_queue),
            shared_channel,
            globals: GlobalTable::default(),
        };

        unsafe { &mut *lifecycle::set_instance_data(env, data) }
    }

    /// Helper to return a reference to the `drop_queue` field of `InstanceData`
    pub(crate) fn drop_queue<'cx, C: Context<'cx>>(
        cx: &mut C,
    ) -> Arc<ThreadsafeFunction<DropData>> {
        Arc::clone(&InstanceData::get(cx).drop_queue)
    }

    /// Clones the shared channel and references it since new channels should start
    /// referenced, but the shared channel is unreferenced.
    pub(crate) fn channel<'cx, C: Context<'cx>>(cx: &mut C) -> Channel {
        let mut channel = InstanceData::get(cx).shared_channel.clone();
        channel.reference(cx);
        channel
    }

    /// Unique identifier for this instance of the module
    pub(crate) fn id<'cx, C: Context<'cx>>(cx: &mut C) -> InstanceId {
        InstanceData::get(cx).id
    }

    /// Helper to return a reference to the `globals` field of `InstanceData`.
    pub(crate) fn globals<'cx, C: Context<'cx>>(cx: &mut C) -> &mut GlobalTable {
        &mut InstanceData::get(cx).globals
    }
}
<commit_msg>Use `GlobalCellValue` shorthand in type definition of `GlobalCell`.<commit_after>//! # Environment life cycle APIs
//!
//! These APIs map to the life cycle of a specific "Agent" or self-contained
//! environment. If a Neon module is loaded multiple times (Web Workers, worker
//! threads), these API will be handle data associated with a specific instance.
//!
//! See the [N-API Lifecycle][npai-docs] documentation for more details.
//!
//! [napi-docs]: https://nodejs.org/api/n-api.html#n_api_environment_life_cycle_apis

use std::{
    any::Any,
    marker::PhantomData,
    sync::{
        atomic::{AtomicU64, Ordering},
        Arc,
    },
};

use crate::{
    context::Context,
    event::Channel,
    handle::root::NapiRef,
    result::NeonResult,
    sys::{lifecycle, raw::Env, tsfn::ThreadsafeFunction},
    types::promise::NodeApiDeferred,
};

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(transparent)]
/// Uniquely identifies an instance of the module
///
/// _Note_: Since `InstanceData` is created lazily, the order of `id` may not
/// reflect the order that instances were created.
pub(crate) struct InstanceId(u64);

impl InstanceId {
    fn next() -> Self {
        static NEXT_ID: AtomicU64 = AtomicU64::new(0);

        Self(NEXT_ID.fetch_add(1, Ordering::SeqCst))
    }
}

/// `InstanceData` holds Neon data associated with a particular instance of a
/// native module. If a module is loaded multiple times (e.g., worker threads), this
/// data will be unique per instance.
pub(crate) struct InstanceData {
    id: InstanceId,

    /// Used to free `Root` in the same JavaScript environment that created it
    ///
    /// _Design Note_: An `Arc` ensures the `ThreadsafeFunction` outlives the unloading
    /// of a module. Since it is unlikely that modules will be re-loaded frequently, this
    /// could be replaced with a leaked `&'static ThreadsafeFunction<NapiRef>`. However,
    /// given the cost of FFI, this optimization is omitted until the cost of an
    /// `Arc` is demonstrated as significant.
    drop_queue: Arc<ThreadsafeFunction<DropData>>,

    /// Shared `Channel` that is cloned to be returned by the `cx.channel()` method
    shared_channel: Channel,

    /// Table of user-defined global cells.
    globals: GlobalTable,
}

#[derive(Default)]
pub(crate) struct GlobalTable {
    cells: Vec<GlobalCell>,
}

pub(crate) type GlobalCellValue = Box<dyn Any + Send + 'static>;

pub(crate) enum GlobalCell {
    /// Uninitialized state.
    Uninit,
    /// Intermediate "dirty" state representing the middle of a `get_or_try_init` transaction.
    Trying,
    /// Fully initialized state.
    Init(GlobalCellValue),
}

impl GlobalCell {
    /// Establish the initial state at the beginning of the initialization protocol.
    /// This method ensures that re-entrant initialization always panics (i.e. when
    /// an existing `get_or_try_init` is in progress).
    fn pre_init<F>(&mut self, f: F)
    where
        F: FnOnce() -> GlobalCell,
    {
        match self {
            GlobalCell::Uninit => {
                *self = f();
            }
            GlobalCell::Trying => panic!("attempt to reinitialize Global during initialization"),
            GlobalCell::Init(_) => {}
        }
    }

    pub(crate) fn get<'cx, 'a, C>(cx: &'a mut C, id: usize) -> Option<&mut GlobalCellValue>
    where
        C: Context<'cx>,
    {
        let cell = InstanceData::globals(cx).get(id);
        match cell {
            GlobalCell::Init(ref mut b) => Some(b),
            _ => None,
        }
    }

    pub(crate) fn get_or_init<'cx, 'a, C>(
        cx: &'a mut C,
        id: usize,
        value: GlobalCellValue,
    ) -> &mut GlobalCellValue
    where
        C: Context<'cx>,
    {
        InstanceData::globals(cx)
            .get(id)
            .pre_init(|| GlobalCell::Init(value));

        GlobalCell::get(cx, id).unwrap()
    }

    pub(crate) fn get_or_init_with<'cx, 'a, C, F>(
        cx: &'a mut C,
        id: usize,
        f: F,
    ) -> &mut GlobalCellValue
    where
        C: Context<'cx>,
        F: FnOnce() -> GlobalCellValue,
    {
        InstanceData::globals(cx)
            .get(id)
            .pre_init(|| GlobalCell::Init(f()));

        GlobalCell::get(cx, id).unwrap()
    }

    pub(crate) fn get_or_try_init<'cx, 'a, C, F>(
        cx: &'a mut C,
        id: usize,
        f: F,
    ) -> NeonResult<&mut GlobalCellValue>
    where
        C: Context<'cx>,
        F: FnOnce(&mut C) -> NeonResult<GlobalCellValue>,
    {
        // Kick off a new transaction and drop it before getting the result.
        {
            let mut tx = TryInitTransaction::new(cx, id);
            tx.run(|cx| Ok(f(cx)?))?;
        }

        // If we're here, the transaction has succeeded, so get the result.
        Ok(GlobalCell::get(cx, id).unwrap())
    }
}

impl Default for GlobalCell {
    fn default() -> Self {
        GlobalCell::Uninit
    }
}

impl GlobalTable {
    pub(crate) fn get(&mut self, index: usize) -> &mut GlobalCell {
        if index >= self.cells.len() {
            self.cells.resize_with(index + 1, Default::default);
        }
        &mut self.cells[index]
    }
}

/// An RAII implementation of `GlobalCell::get_or_try_init`, which ensures that
/// the state of a cell is properly managed through all possible control paths.
/// As soon as the transaction begins, the cell is labelled as being in a dirty
/// state (`GlobalCell::Trying`), so that any additional re-entrant attempts to
/// initialize the cell will fail fast. The `Drop` implementation ensures that
/// after the transaction, the cell goes back to a clean state of either
/// `GlobalCell::Uninit` if it fails or `GlobalCell::Init` if it succeeds.
struct TryInitTransaction<'cx, 'a, C: Context<'cx>> {
    cx: &'a mut C,
    id: usize,
    _lifetime: PhantomData<&'cx ()>,
}

impl<'cx, 'a, C: Context<'cx>> TryInitTransaction<'cx, 'a, C> {
    fn new(cx: &'a mut C, id: usize) -> Self {
        let mut tx = Self {
            cx,
            id,
            _lifetime: PhantomData,
        };
        tx.cell().pre_init(|| GlobalCell::Trying);
        tx
    }

    /// _Post-condition:_ If this method returns an `Ok` result, the cell is in the
    /// `GlobalCell::Init` state.
    fn run<F>(&mut self, f: F) -> NeonResult<()>
    where
        F: FnOnce(&mut C) -> NeonResult<GlobalCellValue>,
    {
        if self.is_trying() {
            let value = f(self.cx)?;
            *self.cell() = GlobalCell::Init(value);
        }
        Ok(())
    }

    fn cell(&mut self) -> &mut GlobalCell {
        InstanceData::globals(self.cx).get(self.id)
    }

    fn is_trying(&mut self) -> bool {
        if let GlobalCell::Trying = *self.cell() {
            true
        } else {
            false
        }
    }
}

impl<'cx, 'a, C: Context<'cx>> Drop for TryInitTransaction<'cx, 'a, C> {
    fn drop(&mut self) {
        if self.is_trying() {
            *self.cell() = GlobalCell::Uninit;
        }
    }
}

/// Wrapper for raw Node-API values to be dropped on the main thread
pub(crate) enum DropData {
    Deferred(NodeApiDeferred),
    Ref(NapiRef),
}

impl DropData {
    /// Drop a value on the main thread
    fn drop(env: Option<Env>, data: Self) {
        if let Some(env) = env {
            unsafe {
                match data {
                    DropData::Deferred(data) => data.leaked(env),
                    DropData::Ref(data) => data.unref(env),
                }
            }
        }
    }
}

impl InstanceData {
    /// Return the data associated with this module instance, lazily initializing if
    /// necessary.
    ///
    /// # Safety
    /// No additional locking (e.g., `Mutex`) is necessary because holding a
    /// `Context` reference ensures serialized access.
    pub(crate) fn get<'cx, C: Context<'cx>>(cx: &mut C) -> &mut InstanceData {
        let env = cx.env().to_raw();
        let data = unsafe { lifecycle::get_instance_data::<InstanceData>(env).as_mut() };

        if let Some(data) = data {
            return data;
        }

        let drop_queue = unsafe {
            let queue = ThreadsafeFunction::new(env, DropData::drop);
            queue.unref(env);
            queue
        };

        let shared_channel = {
            let mut channel = Channel::new(cx);
            channel.unref(cx);
            channel
        };

        let data = InstanceData {
            id: InstanceId::next(),
            drop_queue: Arc::new(drop_queue),
            shared_channel,
            globals: GlobalTable::default(),
        };

        unsafe { &mut *lifecycle::set_instance_data(env, data) }
    }

    /// Helper to return a reference to the `drop_queue` field of `InstanceData`
    pub(crate) fn drop_queue<'cx, C: Context<'cx>>(
        cx: &mut C,
    ) -> Arc<ThreadsafeFunction<DropData>> {
        Arc::clone(&InstanceData::get(cx).drop_queue)
    }

    /// Clones the shared channel and references it since new channels should start
    /// referenced, but the shared channel is unreferenced.
    pub(crate) fn channel<'cx, C: Context<'cx>>(cx: &mut C) -> Channel {
        let mut channel = InstanceData::get(cx).shared_channel.clone();
        channel.reference(cx);
        channel
    }

    /// Unique identifier for this instance of the module
    pub(crate) fn id<'cx, C: Context<'cx>>(cx: &mut C) -> InstanceId {
        InstanceData::get(cx).id
    }

    /// Helper to return a reference to the `globals` field of `InstanceData`.
    pub(crate) fn globals<'cx, C: Context<'cx>>(cx: &mut C) -> &mut GlobalTable {
        &mut InstanceData::get(cx).globals
    }
}
<|endoftext|>


<commit_before>#![deny(rust_2018_idioms)]
#![deny(proc_macro_derive_resolution_fallback)]

mod channel;
mod guild;

use std::sync::{mpsc, Arc};
use std::thread;

use rendezvous_common::{
    anyhow,
    data::*,
    ipc,
    parking_lot::RwLock,
    tracing::{self, debug, info, info_span, warn},
};
use serenity::{
    http::Http,
    model::{
        self,
        channel::{ChannelType, GuildChannel, Message, MessageType},
        guild::{Guild, Member},
        id::GuildId,
    },
    prelude::*,
};

use crate::{
    channel::{Channel, ChannelList},
    guild::{author_name, GuildData, GuildMap, UserData},
};

fn main() -> anyhow::Result<()> {
    tracing::init()?;

    let token = std::env::var("RENDEZVOUS_DISCORD_BOT_TOKEN")?;

    let (msg_tx, msg_rx) = mpsc::channel();
    let (event_tx, event_rx) = mpsc::sync_channel(8);

    let handler = Handler::new(event_tx);
    let channels = Arc::clone(&handler.channels);
    let mut client = Client::new(&token, handler)?;
    ipc::spawn_socket(msg_tx, event_rx)?;

    let http = Arc::clone(&client.cache_and_http.http);
    thread::spawn(move || {
        for m in msg_rx {
            handle_ipc_event(&http, &channels, m).unwrap();
        }
    });

    client.start_autosharded()?;

    Ok(())
}

fn handle_ipc_event(http: &Http, channels: &RwLock<ChannelList>, e: Event) -> anyhow::Result<()> {
    match e {
        Event::MessageCreated {
            nickname,
            channel,
            content,
            ..
        } => {
            if !channel.starts_with("#") {
                return Ok(());
            }
            let channels = channels.read();
            debug!(
                "channels: {:?}",
                channels.iter().map(|ch| ch.name()).collect::<Vec<_>>()
            );
            if let Some(ch) = channels.get_by_name(&channel[1..]) {
                debug!("{:?}", ch);
                ch.id()
                    .send_message(http, |m| m.content(format!("<{}> {}", nickname, content)))?;
            } else {
                warn!("unknown channel: {:?}", channel);
            }
        }
        _ => {}
    }
    Ok(())
}

struct Handler {
    guilds: RwLock<GuildMap>,
    channels: Arc<RwLock<ChannelList>>,
    current_user: RwLock<Option<model::user::CurrentUser>>,
    event_tx: mpsc::SyncSender<Event>,
}

impl Handler {
    fn new(event_tx: mpsc::SyncSender<Event>) -> Self {
        Handler {
            guilds: Default::default(),
            channels: Default::default(),
            current_user: Default::default(),
            event_tx,
        }
    }

    fn insert_guild(&self, guild: Guild) -> Option<GuildData> {
        let mut lock = self.guilds.write();
        lock.insert(guild.id, guild.into())
    }

    fn register_guild_channel<'a>(&'a self, channel: &GuildChannel) -> bool {
        if channel.kind != ChannelType::Text {
            return false;
        }
        self.channels
            .write()
            .get_or_insert_with(channel.id, || Channel::Guild(channel.clone()));
        true
    }
}

impl EventHandler for Handler {
    fn ready(
        &self,
        _ctx: Context,
        model::gateway::Ready {
            user,
            guilds,
            private_channels,
            ..
        }: model::gateway::Ready,
    ) {
        use model::guild::GuildStatus::*;
        *self.current_user.write() = Some(user);
        self.guilds
            .write()
            .extend(guilds.into_iter().filter_map(|g| match g {
                OnlineGuild(g) => Some((g.id, g.into())),
                _ => None,
            }));
        self.channels.write().extend(
            private_channels
                .into_iter()
                .filter_map(|(_, ch)| Channel::from_discord(ch)),
        );
    }

    fn guild_create(&self, _ctx: Context, guild: Guild) {
        let mut new_channels = vec![];
        for channel in guild.channels.values() {
            let chan = channel.read();
            if self.register_guild_channel(&chan) {
                new_channels.push(chan.name.clone());
            }
        }
        self.insert_guild(guild);
    }

    fn guild_member_addition(&self, _ctx: Context, guild_id: GuildId, new_member: Member) {
        if let Some(g) = self.guilds.write().get_mut(&guild_id) {
            let id = new_member.user.read().id;
            g.members.insert(id, new_member.into());
        }
    }

    fn guild_member_removal(&self, _ctx: Context, guild_id: GuildId, user: model::user::User) {
        if let Some(g) = self.guilds.write().get_mut(&guild_id) {
            g.members.remove(&user.id);
        }
    }

    fn guild_member_update(&self, _ctx: Context, new: model::event::GuildMemberUpdateEvent) {
        let guild_id = new.guild_id;
        let new = UserData::from(new);
        if let Some(m) = self
            .guilds
            .write()
            .get_mut(&guild_id)
            .and_then(|g| g.members.get_mut(&new.id))
        {
            if m.name != new.name {
                let _ = self.event_tx.send(Event::UserRenamed {
                    old: m.name.clone(),
                    new: new.name.clone(),
                });
            }
            *m = new;
        }
    }

    fn message(&self, _ctx: Context, new_message: Message) {
        let span = info_span!("message");
        let _enter = span.enter();
        info!("entered");
        if new_message.kind != MessageType::Regular
            || self
                .current_user
                .read()
                .as_ref()
                .map(|u| u.id == new_message.author.id)
                .unwrap_or(false)
        {
            return;
        }

        if let Some(ch) = self.channels.read().get_by_id(new_message.channel_id) {
            self.event_tx
                .send(Event::MessageCreated {
                    nickname: author_name(&self.guilds.read(), &new_message).to_owned(),
                    channel: format!("#{}", ch.name()),
                    content: new_message.content,
                    origin: None,
                })
                .unwrap();
        } else {
            info!("channel not found: {}", new_message.channel_id);
        }
    }
}
<commit_msg>feat: port Discord bouncer to gRPC<commit_after>#![deny(rust_2018_idioms)]
#![deny(proc_macro_derive_resolution_fallback)]

mod channel;
mod guild;

use std::sync::Arc;

use rendezvous_common::proto::UserRenamed;
use rendezvous_common::{
    anyhow,
    futures::prelude::*,
    parking_lot::RwLock,
    proto::{
        bouncer_service_client::BouncerServiceClient, event, ClientType, Event, Header,
        MessageCreated,
    },
    tokio::{self, sync::mpsc},
    tracing::{self, debug, info, info_span, warn},
};
use serenity::{
    http::Http,
    model::{
        self,
        channel::{ChannelType, GuildChannel, Message, MessageType},
        guild::{Guild, Member},
        id::GuildId,
    },
    prelude::*,
};

use crate::{
    channel::{Channel, ChannelList},
    guild::{author_name, GuildData, GuildMap, UserData},
};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    tracing::init()?;

    let mut rpc_client = BouncerServiceClient::connect("http://[::1]:49252").await?;

    let token = std::env::var("RENDEZVOUS_DISCORD_BOT_TOKEN")?;

    let (event_tx, mut event_rx) = mpsc::channel::<Event>(8);

    let handler = Handler::new(event_tx);
    let channels = Arc::clone(&handler.channels);
    let mut discord_client = Client::new(&token, handler)?;

    let http = Arc::clone(&discord_client.cache_and_http.http);

    let mut resp = rpc_client
        .subscribe(Header {
            client_type: ClientType::Discord.into(),
        })
        .await?;

    let handle_rpc_stream = tokio::task::spawn(async move {
        let stream = resp.get_mut();
        while let Some(m) = stream.try_next().await? {
            handle_ipc_event(&http, &channels, m)?;
        }
        Ok::<_, anyhow::Error>(())
    });

    let delegate_post_requests = tokio::spawn(async move {
        while let Some(e) = event_rx.recv().await {
            rpc_client.post(e).await?;
        }
        Ok::<(), anyhow::Error>(())
    });

    let handle_discord_events = tokio::task::spawn_blocking(move || {
        discord_client.start_autosharded()?;
        Ok::<_, anyhow::Error>(())
    });

    tokio::try_join!(
        handle_rpc_stream,
        delegate_post_requests,
        handle_discord_events,
    )?;

    Ok(())
}

fn handle_ipc_event(http: &Http, channels: &RwLock<ChannelList>, e: Event) -> anyhow::Result<()> {
    match e.body {
        Some(event::Body::MessageCreated(MessageCreated {
            nickname,
            channel,
            content,
            ..
        })) => {
            if !channel.starts_with("#") {
                return Ok(());
            }
            let channels = channels.read();
            debug!(
                "channels: {:?}",
                channels.iter().map(|ch| ch.name()).collect::<Vec<_>>()
            );
            if let Some(ch) = channels.get_by_name(&channel[1..]) {
                debug!("{:?}", ch);
                ch.id()
                    .send_message(http, |m| m.content(format!("<{}> {}", nickname, content)))?;
            } else {
                warn!("unknown channel: {:?}", channel);
            }
        }
        _ => {}
    }
    Ok(())
}

struct Handler {
    guilds: RwLock<GuildMap>,
    channels: Arc<RwLock<ChannelList>>,
    current_user: RwLock<Option<model::user::CurrentUser>>,
    event_tx: mpsc::Sender<Event>,
}

impl Handler {
    fn new(event_tx: mpsc::Sender<Event>) -> Self {
        Handler {
            guilds: Default::default(),
            channels: Default::default(),
            current_user: Default::default(),
            event_tx,
        }
    }

    fn insert_guild(&self, guild: Guild) -> Option<GuildData> {
        let mut lock = self.guilds.write();
        lock.insert(guild.id, guild.into())
    }

    fn register_guild_channel<'a>(&'a self, channel: &GuildChannel) -> bool {
        if channel.kind != ChannelType::Text {
            return false;
        }
        self.channels
            .write()
            .get_or_insert_with(channel.id, || Channel::Guild(channel.clone()));
        true
    }
}

impl EventHandler for Handler {
    fn ready(
        &self,
        _ctx: Context,
        model::gateway::Ready {
            user,
            guilds,
            private_channels,
            ..
        }: model::gateway::Ready,
    ) {
        use model::guild::GuildStatus::*;
        *self.current_user.write() = Some(user);
        self.guilds
            .write()
            .extend(guilds.into_iter().filter_map(|g| match g {
                OnlineGuild(g) => Some((g.id, g.into())),
                _ => None,
            }));
        self.channels.write().extend(
            private_channels
                .into_iter()
                .filter_map(|(_, ch)| Channel::from_discord(ch)),
        );
    }

    fn guild_create(&self, _ctx: Context, guild: Guild) {
        let mut new_channels = vec![];
        for channel in guild.channels.values() {
            let chan = channel.read();
            if self.register_guild_channel(&chan) {
                new_channels.push(chan.name.clone());
            }
        }
        self.insert_guild(guild);
    }

    fn guild_member_addition(&self, _ctx: Context, guild_id: GuildId, new_member: Member) {
        if let Some(g) = self.guilds.write().get_mut(&guild_id) {
            let id = new_member.user.read().id;
            g.members.insert(id, new_member.into());
        }
    }

    fn guild_member_removal(&self, _ctx: Context, guild_id: GuildId, user: model::user::User) {
        if let Some(g) = self.guilds.write().get_mut(&guild_id) {
            g.members.remove(&user.id);
        }
    }

    fn guild_member_update(&self, _ctx: Context, new: model::event::GuildMemberUpdateEvent) {
        let guild_id = new.guild_id;
        let new = UserData::from(new);
        if let Some(m) = self
            .guilds
            .write()
            .get_mut(&guild_id)
            .and_then(|g| g.members.get_mut(&new.id))
        {
            if m.name != new.name {
                let _ = self.event_tx.send(Event {
                    header: Some(Header {
                        client_type: ClientType::Discord.into(),
                    }),
                    body: Some(event::Body::UserRenamed(UserRenamed {
                        old: m.name.clone(),
                        new: new.name.clone(),
                    })),
                });
            }
            *m = new;
        }
    }

    fn message(&self, _ctx: Context, new_message: Message) {
        let span = info_span!("message");
        let _enter = span.enter();
        info!("entered");
        if new_message.kind != MessageType::Regular
            || self
                .current_user
                .read()
                .as_ref()
                .map(|u| u.id == new_message.author.id)
                .unwrap_or(false)
        {
            return;
        }

        if let Some(ch) = self.channels.read().get_by_id(new_message.channel_id) {
            self.event_tx
                .blocking_send(Event {
                    header: Some(Header {
                        client_type: ClientType::Discord.into(),
                    }),
                    body: Some(event::Body::MessageCreated(MessageCreated {
                        nickname: author_name(&self.guilds.read(), &new_message).to_owned(),
                        channel: format!("#{}", ch.name()),
                        content: new_message.content,
                        origin: "".to_owned(),
                    })),
                })
                .unwrap();
        } else {
            info!("channel not found: {}", new_message.channel_id);
        }
    }
}
<|endoftext|>


<commit_before>use crate::{LexedStr, PrefixEntryPoint, Step};

#[test]
fn vis() {
    check_prefix(PrefixEntryPoint::Vis, "pub(crate) fn foo() {}", "pub(crate)");
    check_prefix(PrefixEntryPoint::Vis, "fn foo() {}", "");
    check_prefix(PrefixEntryPoint::Vis, "pub(fn foo() {}", "pub");
    check_prefix(PrefixEntryPoint::Vis, "pub(crate fn foo() {}", "pub(crate");
    check_prefix(PrefixEntryPoint::Vis, "crate fn foo() {}", "crate");
}

#[test]
fn block() {
    check_prefix(PrefixEntryPoint::Block, "{}, 92", "{}");
    check_prefix(PrefixEntryPoint::Block, "{, 92)", "{, 92)");
    check_prefix(PrefixEntryPoint::Block, "()", "");
}

#[test]
fn stmt() {
    check_prefix(PrefixEntryPoint::Stmt, "92; fn", "92");
    check_prefix(PrefixEntryPoint::Stmt, "let _ = 92; 1", "let _ = 92");
    check_prefix(PrefixEntryPoint::Stmt, "pub fn f() {} = 92", "pub fn f() {}");
    check_prefix(PrefixEntryPoint::Stmt, "struct S;;", "struct S;");
    check_prefix(PrefixEntryPoint::Stmt, "fn f() {};", "fn f() {}");
    check_prefix(PrefixEntryPoint::Stmt, ";;;", ";");
    check_prefix(PrefixEntryPoint::Stmt, "+", "+");
    check_prefix(PrefixEntryPoint::Stmt, "@", "@");
    check_prefix(PrefixEntryPoint::Stmt, "loop {} - 1", "loop {}");
}

#[test]
fn pat() {
    check_prefix(PrefixEntryPoint::Pat, "x y", "x");
    check_prefix(PrefixEntryPoint::Pat, "fn f() {}", "fn");
    // FIXME: This one is wrong, we should consume only one pattern.
    check_prefix(PrefixEntryPoint::Pat, ".. ..", ".. ..");
}

#[test]
fn ty() {
    check_prefix(PrefixEntryPoint::Ty, "fn() foo", "fn()");
    check_prefix(PrefixEntryPoint::Ty, "Clone + Copy + fn", "Clone + Copy +");
    check_prefix(PrefixEntryPoint::Ty, "struct f", "struct");
}

#[test]
fn expr() {
    check_prefix(PrefixEntryPoint::Expr, "92 92", "92");
    check_prefix(PrefixEntryPoint::Expr, "+1", "+");
    check_prefix(PrefixEntryPoint::Expr, "-1", "-1");
    check_prefix(PrefixEntryPoint::Expr, "fn foo() {}", "fn");
    check_prefix(PrefixEntryPoint::Expr, "#[attr] ()", "#[attr] ()");
}

#[test]
fn path() {
    check_prefix(PrefixEntryPoint::Path, "foo::bar baz", "foo::bar");
    check_prefix(PrefixEntryPoint::Path, "foo::<> baz", "foo::<>");
    check_prefix(PrefixEntryPoint::Path, "foo<> baz", "foo<>");
    check_prefix(PrefixEntryPoint::Path, "Fn() -> i32?", "Fn() -> i32");
    // FIXME: this shouldn't be accepted as path actually.
    check_prefix(PrefixEntryPoint::Path, "<_>::foo", "<_>::foo");
}

fn check_prefix(entry: PrefixEntryPoint, input: &str, prefix: &str) {
    let lexed = LexedStr::new(input);
    let input = lexed.to_input();

    let mut n_tokens = 0;
    for step in entry.parse(&input).iter() {
        match step {
            Step::Token { n_input_tokens, .. } => n_tokens += n_input_tokens as usize,
            Step::Enter { .. } | Step::Exit | Step::Error { .. } => (),
        }
    }

    let mut i = 0;
    loop {
        if n_tokens == 0 {
            break;
        }
        if !lexed.kind(i).is_trivia() {
            n_tokens -= 1;
        }
        i += 1;
    }
    let buf = &lexed.as_str()[..lexed.text_start(i)];
    assert_eq!(buf, prefix);
}
<commit_msg>internal: add more prefix entry point tests<commit_after>use crate::{LexedStr, PrefixEntryPoint, Step};

#[test]
fn vis() {
    check_prefix(PrefixEntryPoint::Vis, "pub(crate) fn foo() {}", "pub(crate)");
    check_prefix(PrefixEntryPoint::Vis, "fn foo() {}", "");
    check_prefix(PrefixEntryPoint::Vis, "pub(fn foo() {}", "pub");
    check_prefix(PrefixEntryPoint::Vis, "pub(crate fn foo() {}", "pub(crate");
    check_prefix(PrefixEntryPoint::Vis, "crate fn foo() {}", "crate");
}

#[test]
fn block() {
    check_prefix(PrefixEntryPoint::Block, "{}, 92", "{}");
    check_prefix(PrefixEntryPoint::Block, "{, 92)", "{, 92)");
    check_prefix(PrefixEntryPoint::Block, "()", "");
}

#[test]
fn stmt() {
    check_prefix(PrefixEntryPoint::Stmt, "92; fn", "92");
    check_prefix(PrefixEntryPoint::Stmt, "let _ = 92; 1", "let _ = 92");
    check_prefix(PrefixEntryPoint::Stmt, "pub fn f() {} = 92", "pub fn f() {}");
    check_prefix(PrefixEntryPoint::Stmt, "struct S;;", "struct S;");
    check_prefix(PrefixEntryPoint::Stmt, "fn f() {};", "fn f() {}");
    check_prefix(PrefixEntryPoint::Stmt, ";;;", ";");
    check_prefix(PrefixEntryPoint::Stmt, "+", "+");
    check_prefix(PrefixEntryPoint::Stmt, "@", "@");
    check_prefix(PrefixEntryPoint::Stmt, "loop {} - 1", "loop {}");
}

#[test]
fn pat() {
    check_prefix(PrefixEntryPoint::Pat, "x y", "x");
    check_prefix(PrefixEntryPoint::Pat, "fn f() {}", "fn");
    // FIXME: This one is wrong, we should consume only one pattern.
    check_prefix(PrefixEntryPoint::Pat, ".. ..", ".. ..");
}

#[test]
fn ty() {
    check_prefix(PrefixEntryPoint::Ty, "fn() foo", "fn()");
    check_prefix(PrefixEntryPoint::Ty, "Clone + Copy + fn", "Clone + Copy +");
    check_prefix(PrefixEntryPoint::Ty, "struct f", "struct");
}

#[test]
fn expr() {
    check_prefix(PrefixEntryPoint::Expr, "92 92", "92");
    check_prefix(PrefixEntryPoint::Expr, "+1", "+");
    check_prefix(PrefixEntryPoint::Expr, "-1", "-1");
    check_prefix(PrefixEntryPoint::Expr, "fn foo() {}", "fn");
    check_prefix(PrefixEntryPoint::Expr, "#[attr] ()", "#[attr] ()");
}

#[test]
fn path() {
    check_prefix(PrefixEntryPoint::Path, "foo::bar baz", "foo::bar");
    check_prefix(PrefixEntryPoint::Path, "foo::<> baz", "foo::<>");
    check_prefix(PrefixEntryPoint::Path, "foo<> baz", "foo<>");
    check_prefix(PrefixEntryPoint::Path, "Fn() -> i32?", "Fn() -> i32");
    // FIXME: This shouldn't be accepted as path actually.
    check_prefix(PrefixEntryPoint::Path, "<_>::foo", "<_>::foo");
}

#[test]
fn item() {
    // FIXME: This shouldn't consume the semicolon.
    check_prefix(PrefixEntryPoint::Item, "fn foo() {};", "fn foo() {};");
    check_prefix(PrefixEntryPoint::Item, "#[attr] pub struct S {} 92", "#[attr] pub struct S {}");
    check_prefix(PrefixEntryPoint::Item, "item!{}?", "item!{}");
    check_prefix(PrefixEntryPoint::Item, "????", "?");
}

#[test]
fn meta_item() {
    check_prefix(PrefixEntryPoint::MetaItem, "attr, ", "attr");
    check_prefix(
        PrefixEntryPoint::MetaItem,
        "attr(some token {stream});",
        "attr(some token {stream})",
    );
    check_prefix(PrefixEntryPoint::MetaItem, "path::attr = 2 * 2!", "path::attr = 2 * 2");
}

fn check_prefix(entry: PrefixEntryPoint, input: &str, prefix: &str) {
    let lexed = LexedStr::new(input);
    let input = lexed.to_input();

    let mut n_tokens = 0;
    for step in entry.parse(&input).iter() {
        match step {
            Step::Token { n_input_tokens, .. } => n_tokens += n_input_tokens as usize,
            Step::Enter { .. } | Step::Exit | Step::Error { .. } => (),
        }
    }

    let mut i = 0;
    loop {
        if n_tokens == 0 {
            break;
        }
        if !lexed.kind(i).is_trivia() {
            n_tokens -= 1;
        }
        i += 1;
    }
    let buf = &lexed.as_str()[..lexed.text_start(i)];
    assert_eq!(buf, prefix);
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::cell::RefCell;

// TODO : Using an Observer requires a &mut reference, and should have the "No races!" property:
// TODO : If you hold a &mut ref, no one else can call open/push/shut. Don't let go of that &mut!
// TODO : Probably a good place to insist on RAII... (see ObserverSession)

// observer trait
pub trait Observer {
    type Time;
    type Data;
    fn open(&mut self, time: &Self::Time);   // new punctuation, essentially ...
    fn show(&mut self, data: &Self::Data);   // shows data to the observer.
    fn give(&mut self, data:  Self::Data);   // gives data to the observer.
    fn shut(&mut self, time: &Self::Time);   // indicates that we are done for now.
}

// extension trait for creating an RAII observer session from any observer
pub trait ObserverSessionExt : Observer {
    fn session<'a>(&'a mut self, time: &'a Self::Time) -> ObserverSession<'a, Self>;
    fn show_at<'a, I: Iterator<Item=&'a Self::Data>>(&mut self, time: &Self::Time, iter: I) where Self::Data: 'a;
    fn give_at<I: Iterator<Item=Self::Data>>(&mut self, time: &Self::Time, iter: I);
}

impl<O: Observer> ObserverSessionExt for O {
    #[inline(always)] fn session<'a>(&'a mut self, time: &'a O::Time) -> ObserverSession<'a, O> {
        self.open(time);
        ObserverSession { observer: self, time: time }
    }
    fn show_at<'a, I: Iterator<Item=&'a O::Data>>(&mut self, time: &O::Time, iter: I) where O::Data: 'a {
        self.open(time);
        for item in iter { self.show(item); }
        self.shut(time);
    }
    fn give_at<I: Iterator<Item=O::Data>>(&mut self, time: &O::Time, iter: I) {
        self.open(time);
        for item in iter { self.give(item); }
        self.shut(time);
    }}

// Attempt at RAII for observers. Intended to prevent mis-sequencing of open/push/shut.
pub struct ObserverSession<'a, O:Observer+'a> where O::Time: 'a {
    observer:   &'a mut O,
    time:       &'a O::Time,
}

impl<'a, O:Observer> Drop for ObserverSession<'a, O> where O::Time: 'a {
    #[inline(always)] fn drop(&mut self) { self.observer.shut(self.time); }
}

impl<'a, O:Observer> ObserverSession<'a, O> where O::Time: 'a {
    #[inline(always)] pub fn show(&mut self, data: &O::Data) { self.observer.show(data); }
    #[inline(always)] pub fn give(&mut self, data:  O::Data) { self.observer.give(data); }
}

// blanket implementation for Rc'd observers
impl<O: Observer> Observer for Rc<RefCell<O>> {
    type Time = O::Time;
    type Data = O::Data;
    #[inline(always)] fn open(&mut self, time: &O::Time) { self.borrow_mut().open(time); }
    #[inline(always)] fn show(&mut self, data: &O::Data) { self.borrow_mut().show(data); }
    #[inline(always)] fn give(&mut self, data:  O::Data) { self.borrow_mut().give(data); }
    #[inline(always)] fn shut(&mut self, time: &O::Time) { self.borrow_mut().shut(time); }
}

// blanket implementation for Box'd observers
impl<O: ?Sized + Observer> Observer for Box<O> {
    type Time = O::Time;
    type Data = O::Data;
    #[inline(always)] fn open(&mut self, time: &O::Time) { (**self).open(time); }
    #[inline(always)] fn show(&mut self, data: &O::Data) { (**self).show(data); }
    #[inline(always)] fn give(&mut self, data:  O::Data) { (**self).give(data); }
    #[inline(always)] fn shut(&mut self, time: &O::Time) { (**self).shut(time); }
}
// an observer broadcasting to many observers
pub struct BroadcastObserver<O: Observer> {
    observers:  Vec<O>,
}

impl<O: Observer> BroadcastObserver<O> {
    pub fn new() -> BroadcastObserver<O> { BroadcastObserver { observers: Vec::new() }}
    pub fn add(&mut self, observer: O) { self.observers.push(observer); }
}

impl<O: Observer> Observer for BroadcastObserver<O> {
    type Time = O::Time;
    type Data = O::Data;
    #[inline(always)] fn open(&mut self, time: &O::Time) { for observer in self.observers.iter_mut() { observer.open(time); } }
    #[inline(always)] fn show(&mut self, data: &O::Data) { for observer in self.observers.iter_mut() { observer.show(data); } }
    #[inline(always)] fn give(&mut self, data:  O::Data) {
        // Hand ownership to the last observer
        for index in (0..self.observers.len() - 1) { self.observers[index].show(&data); }
        if self.observers.len() > 0 {
            let last = self.observers.len() - 1;
            self.observers[last].give(data);
        }
    }
    #[inline(always)] fn shut(&mut self, time: &O::Time) { for observer in self.observers.iter_mut() { observer.shut(time); } }
}

// an observer routing between many observers
pub struct ExchangeObserver<O: Observer, H: Fn(&O::Data) -> u64> {
    pub observers:  Vec<O>,
    pub hash_func:  H,
}

impl<O: Observer, H: Fn(&O::Data) -> u64+'static> Observer for ExchangeObserver<O, H> where O::Data : Clone {
    type Time = O::Time;
    type Data = O::Data;
    #[inline(always)] fn open(&mut self, time: &O::Time) -> () { for observer in self.observers.iter_mut() { observer.open(time); } }
    #[inline(always)] fn show(&mut self, data: &O::Data) -> () {
        let dst = (self.hash_func)(data) % self.observers.len() as u64;
        self.observers[dst as usize].show(data);
    }
    #[inline(always)] fn give(&mut self, data:  O::Data) -> () {
        let dst = (self.hash_func)(&data) % self.observers.len() as u64;
        self.observers[dst as usize].give(data);
    }
    #[inline(always)] fn shut(&mut self, time: &O::Time) -> () { for observer in self.observers.iter_mut() { observer.shut(time); } }
}

// an observer buffering records before sending
pub struct BufferedObserver<D, O: Observer> {
    limit:      u64,
    buffer:     Vec<D>,
    observer:   O,
}

impl<D, O: Observer<Data = Vec<D>>> BufferedObserver<D, O> {
    pub fn inner(&self) -> &O { &self.observer }
    pub fn inner_mut(&mut self) -> &mut O { &mut self.observer }
    pub fn new(limit: u64, observer: O) -> BufferedObserver<D, O> {
        BufferedObserver {
            limit: limit,
            buffer: Vec::with_capacity(limit as usize),
            observer: observer,
        }
    }
}

impl<D: Clone+'static, O: Observer<Data = Vec<D>>> Observer for BufferedObserver<D, O> {
    type Time = O::Time;
    type Data = D;
    #[inline(always)] fn open(&mut self, time: &O::Time) { self.observer.open(time); }
    #[inline(always)] fn show(&mut self, data: &D) { self.give(data.clone()); }
    #[inline(always)] fn give(&mut self, data:  D) {
        self.buffer.push(data);
        if self.buffer.len() as u64 > self.limit {
            self.observer.show(&mut self.buffer);
            self.buffer.clear();
        }
    }
    #[inline(always)] fn shut(&mut self, time: &O::Time) {
        if self.buffer.len() > 0 {
            self.observer.show(&self.buffer);
            self.buffer.clear();
        }
        self.observer.shut(time);
    }
}

// dual to BufferedObserver, flattens out buffers
pub struct FlattenedObserver<O: Observer> {
    observer:   O,
}

impl<O: Observer> FlattenedObserver<O> {
    pub fn new(observer: O) -> FlattenedObserver<O> { FlattenedObserver { observer: observer }}
}

impl<O: Observer> Observer for FlattenedObserver<O> {
    type Time = O::Time;
    type Data = Vec<O::Data>;
    #[inline(always)] fn open(&mut self, time: &O::Time) -> () { self.observer.open(time); }
    #[inline(always)] fn show(&mut self, data: &Vec<O::Data>) -> () { for datum in data { self.observer.show(datum); } }
    #[inline(always)] fn give(&mut self, data:  Vec<O::Data>) -> () { for datum in data { self.observer.give(datum); } }
    #[inline(always)] fn shut(&mut self, time: &O::Time) -> () { self.observer.shut(time); }
}

// // discriminated union of two observers
// pub enum ObserverPair<O1: Observer, O2: Observer> {
//     Type1(O1),
//     Type2(O2),
// }
//
// impl<T, D, O1: Observer<Time=T, Data=D>, O2: Observer<Time=T, Data=D>> Observer for ObserverPair<O1, O2> {
//     type Time = T;
//     type Data = D;
//     #[inline(always)]
//     fn open(&mut self, time: &T) {
//         match *self {
//             ObserverPair::Type1(ref mut observer) => observer.open(time),
//             ObserverPair::Type2(ref mut observer) => observer.open(time),
//         }
//     }
//     #[inline(always)]
//     fn push(&mut self, data: &D) {
//         match *self {
//             ObserverPair::Type1(ref mut observer) => observer.push(data),
//             ObserverPair::Type2(ref mut observer) => observer.push(data),
//         }
//     }
//     #[inline(always)]
//     fn shut(&mut self, time: &T) {
//         match *self {
//             ObserverPair::Type1(ref mut observer) => observer.shut(time),
//             ObserverPair::Type2(ref mut observer) => observer.shut(time),
//         }
//     }
// }
<commit_msg>corrected potential underflow in BroadcastObserver<commit_after>use std::rc::Rc;
use std::cell::RefCell;

// TODO : Using an Observer requires a &mut reference, and should have the "No races!" property:
// TODO : If you hold a &mut ref, no one else can call open/push/shut. Don't let go of that &mut!
// TODO : Probably a good place to insist on RAII... (see ObserverSession)

// observer trait
pub trait Observer {
    type Time;
    type Data;
    fn open(&mut self, time: &Self::Time);   // new punctuation, essentially ...
    fn show(&mut self, data: &Self::Data);   // shows data to the observer.
    fn give(&mut self, data:  Self::Data);   // gives data to the observer.
    fn shut(&mut self, time: &Self::Time);   // indicates that we are done for now.
}

// extension trait for creating an RAII observer session from any observer
pub trait ObserverSessionExt : Observer {
    fn session<'a>(&'a mut self, time: &'a Self::Time) -> ObserverSession<'a, Self>;
    fn show_at<'a, I: Iterator<Item=&'a Self::Data>>(&mut self, time: &Self::Time, iter: I) where Self::Data: 'a;
    fn give_at<I: Iterator<Item=Self::Data>>(&mut self, time: &Self::Time, iter: I);
}

impl<O: Observer> ObserverSessionExt for O {
    #[inline(always)] fn session<'a>(&'a mut self, time: &'a O::Time) -> ObserverSession<'a, O> {
        self.open(time);
        ObserverSession { observer: self, time: time }
    }
    fn show_at<'a, I: Iterator<Item=&'a O::Data>>(&mut self, time: &O::Time, iter: I) where O::Data: 'a {
        self.open(time);
        for item in iter { self.show(item); }
        self.shut(time);
    }
    fn give_at<I: Iterator<Item=O::Data>>(&mut self, time: &O::Time, iter: I) {
        self.open(time);
        for item in iter { self.give(item); }
        self.shut(time);
    }}

// Attempt at RAII for observers. Intended to prevent mis-sequencing of open/push/shut.
pub struct ObserverSession<'a, O:Observer+'a> where O::Time: 'a {
    observer:   &'a mut O,
    time:       &'a O::Time,
}

impl<'a, O:Observer> Drop for ObserverSession<'a, O> where O::Time: 'a {
    #[inline(always)] fn drop(&mut self) { self.observer.shut(self.time); }
}

impl<'a, O:Observer> ObserverSession<'a, O> where O::Time: 'a {
    #[inline(always)] pub fn show(&mut self, data: &O::Data) { self.observer.show(data); }
    #[inline(always)] pub fn give(&mut self, data:  O::Data) { self.observer.give(data); }
}

// blanket implementation for Rc'd observers
impl<O: Observer> Observer for Rc<RefCell<O>> {
    type Time = O::Time;
    type Data = O::Data;
    #[inline(always)] fn open(&mut self, time: &O::Time) { self.borrow_mut().open(time); }
    #[inline(always)] fn show(&mut self, data: &O::Data) { self.borrow_mut().show(data); }
    #[inline(always)] fn give(&mut self, data:  O::Data) { self.borrow_mut().give(data); }
    #[inline(always)] fn shut(&mut self, time: &O::Time) { self.borrow_mut().shut(time); }
}

// blanket implementation for Box'd observers
impl<O: ?Sized + Observer> Observer for Box<O> {
    type Time = O::Time;
    type Data = O::Data;
    #[inline(always)] fn open(&mut self, time: &O::Time) { (**self).open(time); }
    #[inline(always)] fn show(&mut self, data: &O::Data) { (**self).show(data); }
    #[inline(always)] fn give(&mut self, data:  O::Data) { (**self).give(data); }
    #[inline(always)] fn shut(&mut self, time: &O::Time) { (**self).shut(time); }
}
// an observer broadcasting to many observers
pub struct BroadcastObserver<O: Observer> {
    observers:  Vec<O>,
}

impl<O: Observer> BroadcastObserver<O> {
    pub fn new() -> BroadcastObserver<O> { BroadcastObserver { observers: Vec::new() }}
    pub fn add(&mut self, observer: O) { self.observers.push(observer); }
}

impl<O: Observer> Observer for BroadcastObserver<O> {
    type Time = O::Time;
    type Data = O::Data;
    #[inline(always)] fn open(&mut self, time: &O::Time) { for observer in self.observers.iter_mut() { observer.open(time); } }
    #[inline(always)] fn show(&mut self, data: &O::Data) { for observer in self.observers.iter_mut() { observer.show(data); } }
    #[inline(always)] fn give(&mut self, data:  O::Data) {
        // Hand ownership to the last observer
        for index in (1..self.observers.len()) { self.observers[index - 1].show(&data); }
        if self.observers.len() > 0 {
            let last = self.observers.len() - 1;
            self.observers[last].give(data);
        }
    }
    #[inline(always)] fn shut(&mut self, time: &O::Time) { for observer in self.observers.iter_mut() { observer.shut(time); } }
}

// an observer routing between many observers
pub struct ExchangeObserver<O: Observer, H: Fn(&O::Data) -> u64> {
    pub observers:  Vec<O>,
    pub hash_func:  H,
}

impl<O: Observer, H: Fn(&O::Data) -> u64+'static> Observer for ExchangeObserver<O, H> where O::Data : Clone {
    type Time = O::Time;
    type Data = O::Data;
    #[inline(always)] fn open(&mut self, time: &O::Time) -> () { for observer in self.observers.iter_mut() { observer.open(time); } }
    #[inline(always)] fn show(&mut self, data: &O::Data) -> () {
        let dst = (self.hash_func)(data) % self.observers.len() as u64;
        self.observers[dst as usize].show(data);
    }
    #[inline(always)] fn give(&mut self, data:  O::Data) -> () {
        let dst = (self.hash_func)(&data) % self.observers.len() as u64;
        self.observers[dst as usize].give(data);
    }
    #[inline(always)] fn shut(&mut self, time: &O::Time) -> () { for observer in self.observers.iter_mut() { observer.shut(time); } }
}

// an observer buffering records before sending
pub struct BufferedObserver<D, O: Observer> {
    limit:      usize,
    buffer:     Vec<D>,
    observer:   O,
}

impl<D, O: Observer<Data = Vec<D>>> BufferedObserver<D, O> {
    pub fn inner(&self) -> &O { &self.observer }
    pub fn inner_mut(&mut self) -> &mut O { &mut self.observer }
    pub fn new(limit: usize, observer: O) -> BufferedObserver<D, O> {
        BufferedObserver {
            limit: limit,
            buffer: Vec::with_capacity(limit as usize),
            observer: observer,
        }
    }
}

impl<D: Clone+'static, O: Observer<Data = Vec<D>>> Observer for BufferedObserver<D, O> {
    type Time = O::Time;
    type Data = D;
    #[inline(always)] fn open(&mut self, time: &O::Time) { self.observer.open(time); }
    #[inline(always)] fn show(&mut self, data: &D) { self.give(data.clone()); }
    #[inline(always)] fn give(&mut self, data:  D) {
        self.buffer.push(data);
        if self.buffer.len() > self.limit {
            self.observer.show(&mut self.buffer);
            self.buffer.clear();
        }
    }
    #[inline(always)] fn shut(&mut self, time: &O::Time) {
        if self.buffer.len() > 0 {
            self.observer.show(&self.buffer);
            self.buffer.clear();
        }
        self.observer.shut(time);
    }
}

// dual to BufferedObserver, flattens out buffers
pub struct FlattenedObserver<O: Observer> {
    observer:   O,
}

impl<O: Observer> FlattenedObserver<O> {
    pub fn new(observer: O) -> FlattenedObserver<O> { FlattenedObserver { observer: observer }}
}

impl<O: Observer> Observer for FlattenedObserver<O> {
    type Time = O::Time;
    type Data = Vec<O::Data>;
    #[inline(always)] fn open(&mut self, time: &O::Time) -> () { self.observer.open(time); }
    #[inline(always)] fn show(&mut self, data: &Vec<O::Data>) -> () { for datum in data { self.observer.show(datum); } }
    #[inline(always)] fn give(&mut self, data:  Vec<O::Data>) -> () { for datum in data { self.observer.give(datum); } }
    #[inline(always)] fn shut(&mut self, time: &O::Time) -> () { self.observer.shut(time); }
}

// // discriminated union of two observers
// pub enum ObserverPair<O1: Observer, O2: Observer> {
//     Type1(O1),
//     Type2(O2),
// }
//
// impl<T, D, O1: Observer<Time=T, Data=D>, O2: Observer<Time=T, Data=D>> Observer for ObserverPair<O1, O2> {
//     type Time = T;
//     type Data = D;
//     #[inline(always)]
//     fn open(&mut self, time: &T) {
//         match *self {
//             ObserverPair::Type1(ref mut observer) => observer.open(time),
//             ObserverPair::Type2(ref mut observer) => observer.open(time),
//         }
//     }
//     #[inline(always)]
//     fn push(&mut self, data: &D) {
//         match *self {
//             ObserverPair::Type1(ref mut observer) => observer.push(data),
//             ObserverPair::Type2(ref mut observer) => observer.push(data),
//         }
//     }
//     #[inline(always)]
//     fn shut(&mut self, time: &T) {
//         match *self {
//             ObserverPair::Type1(ref mut observer) => observer.shut(time),
//             ObserverPair::Type2(ref mut observer) => observer.shut(time),
//         }
//     }
// }
<|endoftext|>


<commit_before>use gb_proc::video_controller::{VideoController, ScreenBuffer};
use gb_proc::sound_controller::SoundController;
use gb_proc::cpu::{Handler, HandlerHolder, Interrupt};
use bitfield::Bitfield;

pub struct GBHandlerHolder {
    memory_holder: MemoryHolder,
    cartridge: Box<Handler + 'static>,
    pub video_controller: VideoController,
    joypad_register: JoypadRegister,
    serial_transfer_controller: SerialTransferController,
    sound_controller: SoundController,
}

impl GBHandlerHolder {
    pub fn new(cartridge: Box<Handler>) -> GBHandlerHolder {
        GBHandlerHolder {
            memory_holder: MemoryHolder::new(),
            cartridge: cartridge,
            video_controller: VideoController::new(),
            joypad_register: JoypadRegister::new(),
            serial_transfer_controller: SerialTransferController::new(),
            sound_controller: SoundController::new(),
        }
    }
}

// TODO: move this where the memory is actually used
// e.g. video_ram should be in the VideoController
struct MemoryHolder {
    stack: [u8; 256],
    internal_ram: [u8; 8196],
}

impl MemoryHolder {
    pub fn new() -> MemoryHolder {
        MemoryHolder {
            stack: [0; 256],
            internal_ram: [0; 8196],
        }
    }
}

impl Handler for MemoryHolder {
    fn read(&self, address: u16) -> u8 {
        match address {
            0xFF4D | 0xFF56 | 0xFF70 | 0xFF6C | 0xFF72 ... 0xFF77 => {
                // These IO registers are legal in the GBC so we should not crash
                // if the cpu tryies to access them, even though they are not
                // implemented in the DMG.
                0xFF
            },
            0xC000 ... 0xDFFF => self.internal_ram[(address - 0xC000) as usize],
            0xFF80 ... 0xFFFE => self.stack[(address - 0xFF80) as usize],
            _ => panic!(format!("Address not supported {:04X}", address)),
        }
    }

    fn write(&mut self, address: u16, v: u8) {
        match address {
            0xFF4D | 0xFF56 | 0xFF70 | 0xFF6C | 0xFF72 ... 0xFF77 => {
                // These IO registers are legal in the GBC so we should not crash
                // if the cpu tryies to access them, even though they are not
                // implemented in the DMG.
            },
            0xC000 ... 0xDFFF => self.internal_ram[(address - 0xC000) as usize] = v,
            0xFF80 ... 0xFFFE => self.stack[(address - 0xFF80) as usize] = v,
            _ => panic!(format!("Address not supported {:04X}", address)),
        }
    }
}

impl HandlerHolder for GBHandlerHolder {
    fn get_screen_buffer(&self) -> &ScreenBuffer {
        self.video_controller.get_screen()
    }

    fn should_refresh(&mut self) -> bool {
        self.video_controller.should_refresh()
    }

    fn key_up(&mut self, key: Key) {
        self.joypad_register.key_up(key);
    }

    fn key_down(&mut self, key: Key) {
        self.joypad_register.key_down(key);
    }

    fn get_handler_read(&self, address: u16) -> &Handler {
        match address {
            0x0000 ... 0x7FFF => self.cartridge.as_ref(),
            0x8000 ... 0x9FFF => &self.video_controller,
            0xA000 ... 0xBFFF => self.cartridge.as_ref(),
            0xC000 ... 0xDFFF => &self.memory_holder,
            // Accessing this in the real GB will return the internal_ram echoed
            // but it's probably a bug in the emulator, so let's panic
            0xE000 ... 0xFDFF => panic!("Tried to access echo of internal ram"),
            0xFE00 ... 0xFE9F => &self.video_controller,
            0xFEA0 ... 0xFEFF => &self.memory_holder,
            0xFF00            => &self.joypad_register,
            0xFF01 ... 0xFF02 => &self.serial_transfer_controller,
            0xFF09 ... 0xFF3F => &self.sound_controller,
            0xFF40 ... 0xFF4B => &self.video_controller,
            0xFF4C ... 0xFFFE => &self.memory_holder,
            _ => unreachable!(),
        }
    }

    fn get_handler_write(&mut self, address: u16) -> &mut Handler {
        match address {
            0x0000 ... 0x7FFF => &mut *self.cartridge,
            0x8000 ... 0x9FFF => &mut self.video_controller,
            0xA000 ... 0xBFFF => &mut *self.cartridge,
            0xC000 ... 0xDFFF => &mut self.memory_holder,
            0xE000 ... 0xFDFF => &mut self.memory_holder,
            0xFE00 ... 0xFE9F => &mut self.video_controller,
            0xFEA0 ... 0xFEFF => &mut self.memory_holder,
            0xFF00            => &mut self.joypad_register,
            0xFF01 ... 0xFF02 => &mut self.serial_transfer_controller,
            0xFF09 ... 0xFF3F => &mut self.sound_controller,
            0xFF40 ... 0xFF4B => &mut self.video_controller,
            0xFF4C ... 0xFFFE => &mut self.memory_holder,
            _ => unimplemented!(),
        }
    }

    fn add_cycles(&mut self, cycles: usize) {
        self.video_controller.add_cycles(cycles);
        self.sound_controller.add_cycles(cycles);
    }

    fn check_interrupts(&mut self) -> Vec<Interrupt> {
        self.video_controller.check_interrupts()
    }
}

memory_mapper!{
    name: SerialTransferController,
    fields: [
        0xFF01, transfer_data, 0;
    ],
    bitfields: {
        getters: [
            0xFF02, flags, 0, [
                get_0, shift_clock, u8;
                get_1, fast_clock, u8;
                get_7, start_transfer, u8
            ]
        ],
        getter_setters: [
        ],
    },
}

#[derive(Debug)]
pub enum Key {
    Up,
    Down,
    Left,
    Right,
    A,
    B,
    Select,
    Start,
}

struct JoypadRegister {
    P14: bool,
    P15: bool,

    // Button status
    up: bool,
    down: bool,
    left: bool,
    right: bool,
    a: bool,
    b: bool,
    select: bool,
    start: bool,
}

impl JoypadRegister {
    pub fn new() -> JoypadRegister {
        JoypadRegister {
            P14: false,
            P15: false,
            up: false,
            down: false,
            left: false,
            right: false,
            a: false,
            b: false,
            select: false,
            start: false,
        }
    }

    pub fn key_up(&mut self, key: Key) {
        match key {
            Key::Up => { self.up = false },
            Key::Down => { self.down = false },
            Key::Left => { self.left = false },
            Key::Right => { self.right = false },
            Key::A => { self.a = false },
            Key::B => { self.b = false },
            Key::Select => { self.select = false },
            Key::Start => { self.start = false },
        }
    }

    pub fn key_down(&mut self, key: Key) {
        match key {
            Key::Up => { self.up = true },
            Key::Down => { self.down = true },
            Key::Left => { self.left = true },
            Key::Right => { self.right = true },
            Key::A => { self.a = true },
            Key::B => { self.b = true },
            Key::Select => { self.select = true },
            Key::Start => { self.start = true },
        }
    }
}

impl Handler for JoypadRegister {
    fn read(&self, address: u16) -> u8 {
        if address != 0xFF00 {
            unimplemented!();
        }

        // 0 means that the button is pressed
        let mut r = 0b00001111;
        if self.P14 {
            if self.right { r &= 0b00001110 };
            if self.left  { r &= 0b00001101 };
            if self.up    { r &= 0b00001011 };
            if self.down  { r &= 0b00000111 };
        } else if self.P15 {
            if self.a      { r &= 0b00001110 };
            if self.b      { r &= 0b00001101 };
            if self.select { r &= 0b00001011 };
            if self.start  { r &= 0b00000111 };
        } else {
            // Can this ever happen?
            unimplemented!();
        }

        r
    }

    fn write(&mut self, address: u16, v: u8) {
        if address != 0xFF00 {
            unimplemented!();
        }

        // I'm not totally sure about this, but it seems to work
        self.P15 = (0b00010000 & v) > 0;
        self.P14 = (0b00100000 & v) > 0;
    }
}
<commit_msg>Allow games to access forbidden IO area.<commit_after>use gb_proc::video_controller::{VideoController, ScreenBuffer};
use gb_proc::sound_controller::SoundController;
use gb_proc::cpu::{Handler, HandlerHolder, Interrupt};
use bitfield::Bitfield;

pub struct GBHandlerHolder {
    memory_holder: MemoryHolder,
    cartridge: Box<Handler + 'static>,
    pub video_controller: VideoController,
    joypad_register: JoypadRegister,
    serial_transfer_controller: SerialTransferController,
    sound_controller: SoundController,
}

impl GBHandlerHolder {
    pub fn new(cartridge: Box<Handler>) -> GBHandlerHolder {
        GBHandlerHolder {
            memory_holder: MemoryHolder::new(),
            cartridge: cartridge,
            video_controller: VideoController::new(),
            joypad_register: JoypadRegister::new(),
            serial_transfer_controller: SerialTransferController::new(),
            sound_controller: SoundController::new(),
        }
    }
}

// TODO: move this where the memory is actually used
// e.g. video_ram should be in the VideoController
struct MemoryHolder {
    stack: [u8; 256],
    internal_ram: [u8; 8196],
}

impl MemoryHolder {
    pub fn new() -> MemoryHolder {
        MemoryHolder {
            stack: [0; 256],
            internal_ram: [0; 8196],
        }
    }
}

impl Handler for MemoryHolder {
    fn read(&self, address: u16) -> u8 {
        match address {
            0xFEA0 ... 0xFEFF | 0xFF4C ... 0xFF7F => {
                // This area of the memory is not theoretically accessible but
                // some games do try to read from here because of bugs in them.
                // We will just return the default bus value.
                0xFF
            },
            0xC000 ... 0xDFFF => self.internal_ram[(address - 0xC000) as usize],
            0xFF80 ... 0xFFFE => self.stack[(address - 0xFF80) as usize],
            _ => panic!(format!("Address not supported {:04X}", address)),
        }
    }

    fn write(&mut self, address: u16, v: u8) {
        match address {
            0xFEA0 ... 0xFEFF | 0xFF4C ... 0xFF7F => {
                // This area is not mapped to anything in the game boy hardware,
                // so writes have no effect.
            }
            0xC000 ... 0xDFFF => self.internal_ram[(address - 0xC000) as usize] = v,
            0xFF80 ... 0xFFFE => self.stack[(address - 0xFF80) as usize] = v,
            _ => panic!(format!("Address not supported {:04X}", address)),
        }
    }
}

impl HandlerHolder for GBHandlerHolder {
    fn get_screen_buffer(&self) -> &ScreenBuffer {
        self.video_controller.get_screen()
    }

    fn should_refresh(&mut self) -> bool {
        self.video_controller.should_refresh()
    }

    fn key_up(&mut self, key: Key) {
        self.joypad_register.key_up(key);
    }

    fn key_down(&mut self, key: Key) {
        self.joypad_register.key_down(key);
    }

    fn get_handler_read(&self, address: u16) -> &Handler {
        match address {
            0x0000 ... 0x7FFF => self.cartridge.as_ref(),
            0x8000 ... 0x9FFF => &self.video_controller,
            0xA000 ... 0xBFFF => self.cartridge.as_ref(),
            0xC000 ... 0xDFFF => &self.memory_holder,
            // Accessing this in the real GB will return the internal_ram echoed
            // but it's probably a bug in the emulator, so let's panic
            0xE000 ... 0xFDFF => panic!("Tried to access echo of internal ram"),
            0xFE00 ... 0xFE9F => &self.video_controller,
            0xFEA0 ... 0xFEFF => &self.memory_holder,
            0xFF00            => &self.joypad_register,
            0xFF01 ... 0xFF02 => &self.serial_transfer_controller,
            0xFF09 ... 0xFF3F => &self.sound_controller,
            0xFF40 ... 0xFF4B => &self.video_controller,
            0xFF4C ... 0xFFFE => &self.memory_holder,
            _ => unreachable!(),
        }
    }

    fn get_handler_write(&mut self, address: u16) -> &mut Handler {
        match address {
            0x0000 ... 0x7FFF => &mut *self.cartridge,
            0x8000 ... 0x9FFF => &mut self.video_controller,
            0xA000 ... 0xBFFF => &mut *self.cartridge,
            0xC000 ... 0xDFFF => &mut self.memory_holder,
            0xE000 ... 0xFDFF => &mut self.memory_holder,
            0xFE00 ... 0xFE9F => &mut self.video_controller,
            0xFEA0 ... 0xFEFF => &mut self.memory_holder,
            0xFF00            => &mut self.joypad_register,
            0xFF01 ... 0xFF02 => &mut self.serial_transfer_controller,
            0xFF09 ... 0xFF3F => &mut self.sound_controller,
            0xFF40 ... 0xFF4B => &mut self.video_controller,
            0xFF4C ... 0xFFFE => &mut self.memory_holder,
            _ => unimplemented!(),
        }
    }

    fn add_cycles(&mut self, cycles: usize) {
        self.video_controller.add_cycles(cycles);
        self.sound_controller.add_cycles(cycles);
    }

    fn check_interrupts(&mut self) -> Vec<Interrupt> {
        self.video_controller.check_interrupts()
    }
}

memory_mapper!{
    name: SerialTransferController,
    fields: [
        0xFF01, transfer_data, 0;
    ],
    bitfields: {
        getters: [
            0xFF02, flags, 0, [
                get_0, shift_clock, u8;
                get_1, fast_clock, u8;
                get_7, start_transfer, u8
            ]
        ],
        getter_setters: [
        ],
    },
}

#[derive(Debug)]
pub enum Key {
    Up,
    Down,
    Left,
    Right,
    A,
    B,
    Select,
    Start,
}

struct JoypadRegister {
    P14: bool,
    P15: bool,

    // Button status
    up: bool,
    down: bool,
    left: bool,
    right: bool,
    a: bool,
    b: bool,
    select: bool,
    start: bool,
}

impl JoypadRegister {
    pub fn new() -> JoypadRegister {
        JoypadRegister {
            P14: false,
            P15: false,
            up: false,
            down: false,
            left: false,
            right: false,
            a: false,
            b: false,
            select: false,
            start: false,
        }
    }

    pub fn key_up(&mut self, key: Key) {
        match key {
            Key::Up => { self.up = false },
            Key::Down => { self.down = false },
            Key::Left => { self.left = false },
            Key::Right => { self.right = false },
            Key::A => { self.a = false },
            Key::B => { self.b = false },
            Key::Select => { self.select = false },
            Key::Start => { self.start = false },
        }
    }

    pub fn key_down(&mut self, key: Key) {
        match key {
            Key::Up => { self.up = true },
            Key::Down => { self.down = true },
            Key::Left => { self.left = true },
            Key::Right => { self.right = true },
            Key::A => { self.a = true },
            Key::B => { self.b = true },
            Key::Select => { self.select = true },
            Key::Start => { self.start = true },
        }
    }
}

impl Handler for JoypadRegister {
    fn read(&self, address: u16) -> u8 {
        if address != 0xFF00 {
            unimplemented!();
        }

        // 0 means that the button is pressed
        let mut r = 0b00001111;
        if self.P14 {
            if self.right { r &= 0b00001110 };
            if self.left  { r &= 0b00001101 };
            if self.up    { r &= 0b00001011 };
            if self.down  { r &= 0b00000111 };
        } else if self.P15 {
            if self.a      { r &= 0b00001110 };
            if self.b      { r &= 0b00001101 };
            if self.select { r &= 0b00001011 };
            if self.start  { r &= 0b00000111 };
        } else {
            // Can this ever happen?
            unimplemented!();
        }

        r
    }

    fn write(&mut self, address: u16, v: u8) {
        if address != 0xFF00 {
            unimplemented!();
        }

        // I'm not totally sure about this, but it seems to work
        self.P15 = (0b00010000 & v) > 0;
        self.P14 = (0b00100000 & v) > 0;
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate security_framework;
extern crate security_framework_sys;
extern crate tempdir;

use self::security_framework::base;
use self::security_framework::certificate::SecCertificate;
use self::security_framework::identity::SecIdentity;
use self::security_framework::import_export::Pkcs12ImportOptions;
use self::security_framework::secure_transport::{self, SslContext, ProtocolSide, ConnectionType,
                                                 SslProtocol, ClientBuilder};
use self::security_framework::os::macos::keychain::{self, KeychainSettings};
use self::security_framework_sys::base::errSecIO;
use self::tempdir::TempDir;
use std::fmt;
use std::io;
use std::error;
use std::sync::Mutex;
use std::sync::atomic::{AtomicBool, Ordering};

use Protocol;

lazy_static! {
    static ref AT_EXIT_SET: AtomicBool = AtomicBool::new(false);
    static ref TEMP_DIRS: Mutex<Vec<TempDir>> = Mutex::new(vec![]);
}

fn convert_protocol(protocol: Protocol) -> SslProtocol {
    match protocol {
        Protocol::Sslv3 => SslProtocol::Ssl3,
        Protocol::Tlsv10 => SslProtocol::Tls1,
        Protocol::Tlsv11 => SslProtocol::Tls11,
        Protocol::Tlsv12 => SslProtocol::Tls12,
        Protocol::__NonExhaustive => unreachable!(),
    }
}

fn protocol_min_max(protocols: &[Protocol]) -> (SslProtocol, SslProtocol) {
    let mut min = Protocol::Tlsv12;
    let mut max = Protocol::Sslv3;
    for protocol in protocols {
        if (*protocol as usize) < (min as usize) {
            min = *protocol;
        }
        if (*protocol as usize) > (max as usize) {
            max = *protocol;
        }
    }
    (convert_protocol(min), convert_protocol(max))
}

pub struct Error(base::Error);

impl error::Error for Error {
    fn description(&self) -> &str {
        error::Error::description(&self.0)
    }

    fn cause(&self) -> Option<&error::Error> {
        error::Error::cause(&self.0)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, fmt)
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl From<base::Error> for Error {
    fn from(error: base::Error) -> Error {
        Error(error)
    }
}

#[derive(Clone)]
pub struct Pkcs12 {
    identity: SecIdentity,
    chain: Vec<SecCertificate>,
}

impl Pkcs12 {
    pub fn from_der(buf: &[u8], pass: &str) -> Result<Pkcs12, Error> {
        let dir = match TempDir::new("native-tls") {
            Ok(dir) => dir,
            Err(_) => return Err(Error(base::Error::from(errSecIO))),
        };

        let mut keychain = try!(keychain::CreateOptions::new().password(pass).create(
            dir.path().join("tmp.keychain"),
        ));

        // disable lock on sleep and timeouts
        try!(keychain.set_settings(&KeychainSettings::new()));

        let mut imports = try!(
            Pkcs12ImportOptions::new()
                .passphrase(pass)
                .keychain(keychain)
                .import(buf)
        );
        let import = imports.pop().unwrap();

        // FIXME: Compare the certificates for equality using CFEqual
        let identity_cert = try!(import.identity.certificate()).to_der();

        if !AT_EXIT_SET.swap(true, Ordering::Relaxed) {
            extern "C" fn atexit() {
                TEMP_DIRS.lock().unwrap().clear();
            }

            unsafe { libc::atexit(atexit); }
        }

        TEMP_DIRS.lock().unwrap().push(dir);

        Ok(Pkcs12 {
            identity: import.identity,
            chain: import
                .cert_chain
                .into_iter()
                .filter(|c| c.to_der() != identity_cert)
                .collect(),
        })
    }
}

pub struct Certificate(SecCertificate);

impl Certificate {
    pub fn from_der(buf: &[u8]) -> Result<Certificate, Error> {
        let cert = try!(SecCertificate::from_der(buf));
        Ok(Certificate(cert))
    }
}

pub enum HandshakeError<S> {
    Interrupted(MidHandshakeTlsStream<S>),
    Failure(Error),
}

impl<S> From<secure_transport::HandshakeError<S>> for HandshakeError<S> {
    fn from(e: secure_transport::HandshakeError<S>) -> HandshakeError<S> {
        match e {
            secure_transport::HandshakeError::Failure(e) => HandshakeError::Failure(e.into()),
            secure_transport::HandshakeError::Interrupted(s) => {
                HandshakeError::Interrupted(MidHandshakeTlsStream::Server(s))
            }
        }
    }
}

impl<S> From<secure_transport::ClientHandshakeError<S>> for HandshakeError<S> {
    fn from(e: secure_transport::ClientHandshakeError<S>) -> HandshakeError<S> {
        match e {
            secure_transport::ClientHandshakeError::Failure(e) => HandshakeError::Failure(e.into()),
            secure_transport::ClientHandshakeError::Interrupted(s) => {
                HandshakeError::Interrupted(MidHandshakeTlsStream::Client(s))
            }
        }
    }
}

impl<S> From<base::Error> for HandshakeError<S> {
    fn from(e: base::Error) -> HandshakeError<S> {
        HandshakeError::Failure(e.into())
    }
}

pub enum MidHandshakeTlsStream<S> {
    Server(secure_transport::MidHandshakeSslStream<S>),
    Client(secure_transport::MidHandshakeClientBuilder<S>),
}

impl<S> fmt::Debug for MidHandshakeTlsStream<S>
where
    S: fmt::Debug,
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MidHandshakeTlsStream::Server(ref s) => s.fmt(fmt),
            MidHandshakeTlsStream::Client(ref s) => s.fmt(fmt),
        }
    }
}

impl<S> MidHandshakeTlsStream<S>
where
    S: io::Read + io::Write,
{
    pub fn get_ref(&self) -> &S {
        match *self {
            MidHandshakeTlsStream::Server(ref s) => s.get_ref(),
            MidHandshakeTlsStream::Client(ref s) => s.get_ref(),
        }
    }

    pub fn get_mut(&mut self) -> &mut S {
        match *self {
            MidHandshakeTlsStream::Server(ref mut s) => s.get_mut(),
            MidHandshakeTlsStream::Client(ref mut s) => s.get_mut(),
        }
    }

    pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
        match self {
            MidHandshakeTlsStream::Server(s) => {
                match s.handshake() {
                    Ok(s) => Ok(TlsStream(s)),
                    Err(e) => Err(e.into()),
                }
            }
            MidHandshakeTlsStream::Client(s) => {
                match s.handshake() {
                    Ok(s) => Ok(TlsStream(s)),
                    Err(e) => Err(e.into()),
                }
            }
        }
    }
}

pub struct TlsConnectorBuilder(TlsConnector);

impl TlsConnectorBuilder {
    pub fn identity(&mut self, pkcs12: Pkcs12) -> Result<(), Error> {
        self.0.pkcs12 = Some(pkcs12);
        Ok(())
    }

    pub fn add_root_certificate(&mut self, cert: Certificate) -> Result<(), Error> {
        self.0.roots.push(cert.0);
        Ok(())
    }

    pub fn supported_protocols(&mut self, protocols: &[Protocol]) -> Result<(), Error> {
        self.0.protocols = protocols.to_vec();
        Ok(())
    }

    pub fn build(self) -> Result<TlsConnector, Error> {
        Ok(self.0)
    }
}

#[derive(Clone)]
pub struct TlsConnector {
    pkcs12: Option<Pkcs12>,
    protocols: Vec<Protocol>,
    roots: Vec<SecCertificate>,
}

impl TlsConnector {
    pub fn builder() -> Result<TlsConnectorBuilder, Error> {
        Ok(TlsConnectorBuilder(TlsConnector {
            pkcs12: None,
            protocols: vec![Protocol::Tlsv10, Protocol::Tlsv11, Protocol::Tlsv12],
            roots: vec![],
        }))
    }

    pub fn connect<S>(&self, domain: &str, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        self.connect_inner(Some(domain), stream)
    }

    pub fn connect_no_domain<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        self.connect_inner(None, stream)
    }

    fn connect_inner<S>(
        &self,
        domain: Option<&str>,
        stream: S,
    ) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        let mut builder = ClientBuilder::new();
        let (min, max) = protocol_min_max(&self.protocols);
        builder.protocol_min(min);
        builder.protocol_max(max);
        if let Some(pkcs12) = self.pkcs12.as_ref() {
            builder.identity(&pkcs12.identity, &pkcs12.chain);
        }
        builder.anchor_certificates(&self.roots);

        let r = match domain {
            Some(domain) => builder.handshake2(domain, stream),
            None => builder.danger_handshake_without_providing_domain_for_certificate_validation_and_server_name_indication(stream),
        };
        match r {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub struct TlsAcceptorBuilder(TlsAcceptor);

impl TlsAcceptorBuilder {
    pub fn supported_protocols(&mut self, protocols: &[Protocol]) -> Result<(), Error> {
        self.0.protocols = protocols.to_vec();
        Ok(())
    }

    pub fn build(self) -> Result<TlsAcceptor, Error> {
        Ok(self.0)
    }
}

#[derive(Clone)]
pub struct TlsAcceptor {
    pkcs12: Pkcs12,
    protocols: Vec<Protocol>,
}

impl TlsAcceptor {
    pub fn builder(pkcs12: Pkcs12) -> Result<TlsAcceptorBuilder, Error> {
        Ok(TlsAcceptorBuilder(TlsAcceptor {
            pkcs12: pkcs12,
            protocols: vec![Protocol::Tlsv10, Protocol::Tlsv11, Protocol::Tlsv12],
        }))
    }

    pub fn accept<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        let mut ctx = try!(SslContext::new(
            ProtocolSide::Server,
            ConnectionType::Stream,
        ));

        let (min, max) = protocol_min_max(&self.protocols);
        try!(ctx.set_protocol_version_min(min));
        try!(ctx.set_protocol_version_max(max));
        try!(ctx.set_certificate(
            &self.pkcs12.identity,
            &self.pkcs12.chain,
        ));
        match ctx.handshake(stream) {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub struct TlsStream<S>(secure_transport::SslStream<S>);

impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S: io::Read + io::Write> TlsStream<S> {
    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }

    pub fn buffered_read_size(&self) -> Result<usize, Error> {
        Ok(try!(self.0.context().buffered_read_size()))
    }

    pub fn shutdown(&mut self) -> io::Result<()> {
        try!(self.0.close());
        Ok(())
    }
}

impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// Security Framework-specific extensions to `TlsStream`.
pub trait TlsStreamExt<S> {
    /// Returns a shared reference to the Security Framework `SslStream`.
    fn raw_stream(&self) -> &secure_transport::SslStream<S>;

    /// Returns a mutable reference to the Security Framework `SslStream`.
    fn raw_stream_mut(&mut self) -> &mut secure_transport::SslStream<S>;
}

impl<S> TlsStreamExt<S> for ::TlsStream<S> {
    fn raw_stream(&self) -> &secure_transport::SslStream<S> {
        &(self.0).0
    }

    fn raw_stream_mut(&mut self) -> &mut secure_transport::SslStream<S> {
        &mut (self.0).0
    }
}

/// Security Framework-specific extensions to `TlsConnectorBuilder`.
pub trait TlsConnectorBuilderExt {
    /// Deprecated
    #[deprecated(since = "0.1.2", note = "use add_root_certificate")]
    fn anchor_certificates(&mut self, certs: &[SecCertificate]) -> &mut Self;
}

impl TlsConnectorBuilderExt for ::TlsConnectorBuilder {
    fn anchor_certificates(&mut self, certs: &[SecCertificate]) -> &mut Self {
        (self.0).0.roots = certs.to_owned();
        self
    }
}

/// Security Framework-specific extensions to `Error`
pub trait ErrorExt {
    /// Extract the underlying Security Framework error for inspection.
    fn security_framework_error(&self) -> &base::Error;
}

impl ErrorExt for ::Error {
    fn security_framework_error(&self) -> &base::Error {
        &(self.0).0
    }
}
<commit_msg>Use std::sync::Once for libc::atexit initialization<commit_after>extern crate libc;
extern crate security_framework;
extern crate security_framework_sys;
extern crate tempdir;

use self::security_framework::base;
use self::security_framework::certificate::SecCertificate;
use self::security_framework::identity::SecIdentity;
use self::security_framework::import_export::Pkcs12ImportOptions;
use self::security_framework::secure_transport::{self, SslContext, ProtocolSide, ConnectionType,
                                                 SslProtocol, ClientBuilder};
use self::security_framework::os::macos::keychain::{self, KeychainSettings};
use self::security_framework_sys::base::errSecIO;
use self::tempdir::TempDir;
use std::fmt;
use std::io;
use std::error;
use std::sync::Mutex;
use std::sync::{Once, ONCE_INIT};

use Protocol;

static SET_AT_EXIT: Once = ONCE_INIT;

lazy_static! {
    static ref TEMP_DIRS: Mutex<Vec<TempDir>> = Mutex::new(vec![]);
}

fn convert_protocol(protocol: Protocol) -> SslProtocol {
    match protocol {
        Protocol::Sslv3 => SslProtocol::Ssl3,
        Protocol::Tlsv10 => SslProtocol::Tls1,
        Protocol::Tlsv11 => SslProtocol::Tls11,
        Protocol::Tlsv12 => SslProtocol::Tls12,
        Protocol::__NonExhaustive => unreachable!(),
    }
}

fn protocol_min_max(protocols: &[Protocol]) -> (SslProtocol, SslProtocol) {
    let mut min = Protocol::Tlsv12;
    let mut max = Protocol::Sslv3;
    for protocol in protocols {
        if (*protocol as usize) < (min as usize) {
            min = *protocol;
        }
        if (*protocol as usize) > (max as usize) {
            max = *protocol;
        }
    }
    (convert_protocol(min), convert_protocol(max))
}

pub struct Error(base::Error);

impl error::Error for Error {
    fn description(&self) -> &str {
        error::Error::description(&self.0)
    }

    fn cause(&self) -> Option<&error::Error> {
        error::Error::cause(&self.0)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, fmt)
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl From<base::Error> for Error {
    fn from(error: base::Error) -> Error {
        Error(error)
    }
}

#[derive(Clone)]
pub struct Pkcs12 {
    identity: SecIdentity,
    chain: Vec<SecCertificate>,
}

impl Pkcs12 {
    pub fn from_der(buf: &[u8], pass: &str) -> Result<Pkcs12, Error> {
        let dir = match TempDir::new("native-tls") {
            Ok(dir) => dir,
            Err(_) => return Err(Error(base::Error::from(errSecIO))),
        };

        let mut keychain = try!(keychain::CreateOptions::new().password(pass).create(
            dir.path().join("tmp.keychain"),
        ));

        // disable lock on sleep and timeouts
        try!(keychain.set_settings(&KeychainSettings::new()));

        let mut imports = try!(
            Pkcs12ImportOptions::new()
                .passphrase(pass)
                .keychain(keychain)
                .import(buf)
        );
        let import = imports.pop().unwrap();

        // FIXME: Compare the certificates for equality using CFEqual
        let identity_cert = try!(import.identity.certificate()).to_der();

        SET_AT_EXIT.call_once(|| {
            extern "C" fn atexit() {
                TEMP_DIRS.lock().unwrap().clear();
            }

            unsafe { libc::atexit(atexit); }
        });

        TEMP_DIRS.lock().unwrap().push(dir);

        Ok(Pkcs12 {
            identity: import.identity,
            chain: import
                .cert_chain
                .into_iter()
                .filter(|c| c.to_der() != identity_cert)
                .collect(),
        })
    }
}

pub struct Certificate(SecCertificate);

impl Certificate {
    pub fn from_der(buf: &[u8]) -> Result<Certificate, Error> {
        let cert = try!(SecCertificate::from_der(buf));
        Ok(Certificate(cert))
    }
}

pub enum HandshakeError<S> {
    Interrupted(MidHandshakeTlsStream<S>),
    Failure(Error),
}

impl<S> From<secure_transport::HandshakeError<S>> for HandshakeError<S> {
    fn from(e: secure_transport::HandshakeError<S>) -> HandshakeError<S> {
        match e {
            secure_transport::HandshakeError::Failure(e) => HandshakeError::Failure(e.into()),
            secure_transport::HandshakeError::Interrupted(s) => {
                HandshakeError::Interrupted(MidHandshakeTlsStream::Server(s))
            }
        }
    }
}

impl<S> From<secure_transport::ClientHandshakeError<S>> for HandshakeError<S> {
    fn from(e: secure_transport::ClientHandshakeError<S>) -> HandshakeError<S> {
        match e {
            secure_transport::ClientHandshakeError::Failure(e) => HandshakeError::Failure(e.into()),
            secure_transport::ClientHandshakeError::Interrupted(s) => {
                HandshakeError::Interrupted(MidHandshakeTlsStream::Client(s))
            }
        }
    }
}

impl<S> From<base::Error> for HandshakeError<S> {
    fn from(e: base::Error) -> HandshakeError<S> {
        HandshakeError::Failure(e.into())
    }
}

pub enum MidHandshakeTlsStream<S> {
    Server(secure_transport::MidHandshakeSslStream<S>),
    Client(secure_transport::MidHandshakeClientBuilder<S>),
}

impl<S> fmt::Debug for MidHandshakeTlsStream<S>
where
    S: fmt::Debug,
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MidHandshakeTlsStream::Server(ref s) => s.fmt(fmt),
            MidHandshakeTlsStream::Client(ref s) => s.fmt(fmt),
        }
    }
}

impl<S> MidHandshakeTlsStream<S>
where
    S: io::Read + io::Write,
{
    pub fn get_ref(&self) -> &S {
        match *self {
            MidHandshakeTlsStream::Server(ref s) => s.get_ref(),
            MidHandshakeTlsStream::Client(ref s) => s.get_ref(),
        }
    }

    pub fn get_mut(&mut self) -> &mut S {
        match *self {
            MidHandshakeTlsStream::Server(ref mut s) => s.get_mut(),
            MidHandshakeTlsStream::Client(ref mut s) => s.get_mut(),
        }
    }

    pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
        match self {
            MidHandshakeTlsStream::Server(s) => {
                match s.handshake() {
                    Ok(s) => Ok(TlsStream(s)),
                    Err(e) => Err(e.into()),
                }
            }
            MidHandshakeTlsStream::Client(s) => {
                match s.handshake() {
                    Ok(s) => Ok(TlsStream(s)),
                    Err(e) => Err(e.into()),
                }
            }
        }
    }
}

pub struct TlsConnectorBuilder(TlsConnector);

impl TlsConnectorBuilder {
    pub fn identity(&mut self, pkcs12: Pkcs12) -> Result<(), Error> {
        self.0.pkcs12 = Some(pkcs12);
        Ok(())
    }

    pub fn add_root_certificate(&mut self, cert: Certificate) -> Result<(), Error> {
        self.0.roots.push(cert.0);
        Ok(())
    }

    pub fn supported_protocols(&mut self, protocols: &[Protocol]) -> Result<(), Error> {
        self.0.protocols = protocols.to_vec();
        Ok(())
    }

    pub fn build(self) -> Result<TlsConnector, Error> {
        Ok(self.0)
    }
}

#[derive(Clone)]
pub struct TlsConnector {
    pkcs12: Option<Pkcs12>,
    protocols: Vec<Protocol>,
    roots: Vec<SecCertificate>,
}

impl TlsConnector {
    pub fn builder() -> Result<TlsConnectorBuilder, Error> {
        Ok(TlsConnectorBuilder(TlsConnector {
            pkcs12: None,
            protocols: vec![Protocol::Tlsv10, Protocol::Tlsv11, Protocol::Tlsv12],
            roots: vec![],
        }))
    }

    pub fn connect<S>(&self, domain: &str, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        self.connect_inner(Some(domain), stream)
    }

    pub fn connect_no_domain<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        self.connect_inner(None, stream)
    }

    fn connect_inner<S>(
        &self,
        domain: Option<&str>,
        stream: S,
    ) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        let mut builder = ClientBuilder::new();
        let (min, max) = protocol_min_max(&self.protocols);
        builder.protocol_min(min);
        builder.protocol_max(max);
        if let Some(pkcs12) = self.pkcs12.as_ref() {
            builder.identity(&pkcs12.identity, &pkcs12.chain);
        }
        builder.anchor_certificates(&self.roots);

        let r = match domain {
            Some(domain) => builder.handshake2(domain, stream),
            None => builder.danger_handshake_without_providing_domain_for_certificate_validation_and_server_name_indication(stream),
        };
        match r {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub struct TlsAcceptorBuilder(TlsAcceptor);

impl TlsAcceptorBuilder {
    pub fn supported_protocols(&mut self, protocols: &[Protocol]) -> Result<(), Error> {
        self.0.protocols = protocols.to_vec();
        Ok(())
    }

    pub fn build(self) -> Result<TlsAcceptor, Error> {
        Ok(self.0)
    }
}

#[derive(Clone)]
pub struct TlsAcceptor {
    pkcs12: Pkcs12,
    protocols: Vec<Protocol>,
}

impl TlsAcceptor {
    pub fn builder(pkcs12: Pkcs12) -> Result<TlsAcceptorBuilder, Error> {
        Ok(TlsAcceptorBuilder(TlsAcceptor {
            pkcs12: pkcs12,
            protocols: vec![Protocol::Tlsv10, Protocol::Tlsv11, Protocol::Tlsv12],
        }))
    }

    pub fn accept<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        let mut ctx = try!(SslContext::new(
            ProtocolSide::Server,
            ConnectionType::Stream,
        ));

        let (min, max) = protocol_min_max(&self.protocols);
        try!(ctx.set_protocol_version_min(min));
        try!(ctx.set_protocol_version_max(max));
        try!(ctx.set_certificate(
            &self.pkcs12.identity,
            &self.pkcs12.chain,
        ));
        match ctx.handshake(stream) {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub struct TlsStream<S>(secure_transport::SslStream<S>);

impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S: io::Read + io::Write> TlsStream<S> {
    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }

    pub fn buffered_read_size(&self) -> Result<usize, Error> {
        Ok(try!(self.0.context().buffered_read_size()))
    }

    pub fn shutdown(&mut self) -> io::Result<()> {
        try!(self.0.close());
        Ok(())
    }
}

impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// Security Framework-specific extensions to `TlsStream`.
pub trait TlsStreamExt<S> {
    /// Returns a shared reference to the Security Framework `SslStream`.
    fn raw_stream(&self) -> &secure_transport::SslStream<S>;

    /// Returns a mutable reference to the Security Framework `SslStream`.
    fn raw_stream_mut(&mut self) -> &mut secure_transport::SslStream<S>;
}

impl<S> TlsStreamExt<S> for ::TlsStream<S> {
    fn raw_stream(&self) -> &secure_transport::SslStream<S> {
        &(self.0).0
    }

    fn raw_stream_mut(&mut self) -> &mut secure_transport::SslStream<S> {
        &mut (self.0).0
    }
}

/// Security Framework-specific extensions to `TlsConnectorBuilder`.
pub trait TlsConnectorBuilderExt {
    /// Deprecated
    #[deprecated(since = "0.1.2", note = "use add_root_certificate")]
    fn anchor_certificates(&mut self, certs: &[SecCertificate]) -> &mut Self;
}

impl TlsConnectorBuilderExt for ::TlsConnectorBuilder {
    fn anchor_certificates(&mut self, certs: &[SecCertificate]) -> &mut Self {
        (self.0).0.roots = certs.to_owned();
        self
    }
}

/// Security Framework-specific extensions to `Error`
pub trait ErrorExt {
    /// Extract the underlying Security Framework error for inspection.
    fn security_framework_error(&self) -> &base::Error;
}

impl ErrorExt for ::Error {
    fn security_framework_error(&self) -> &base::Error {
        &(self.0).0
    }
}
<|endoftext|>


<commit_before>fn main() {
  println!("cargo:rustc-link-lib={}", "gurobi65")
}
<commit_msg>fix build script<commit_after>use std::env;
use std::path::{Path, PathBuf};

#[cfg(all(target_os="windows", target_env="msvc"))]
fn setup_from_env() {
  let gurobi_home = env::var("GUROBI_HOME").unwrap();
  assert!(Path::new(gurobi_home.as_str()).exists());

  let mut libpath: PathBuf = PathBuf::from(gurobi_home);
  libpath.push("lib");

  println!("cargo:rustc-link-search=native={}",
           libpath.to_str().unwrap());
}

#[cfg(not(all(target_os="windows", target_env="msvc")))]
fn setup_from_env() {}

fn main() {
  setup_from_env();
  println!("cargo:rustc-link-lib={}", "gurobi65")
}
<|endoftext|>