//! Provides the plugin infrastructure. use event::{Event, AbstractEvent}; use std::any::Any; use std::sync::mpsc::Sender; use std::mem; use minidom::Element; #[derive(Clone)] pub struct PluginProxyBinding { sender: Sender, dispatcher: Sender, } impl PluginProxyBinding { pub fn new(sender: Sender, dispatcher: Sender) -> PluginProxyBinding { PluginProxyBinding { sender: sender, dispatcher: dispatcher, } } } pub enum PluginProxy { Unbound, BoundTo(PluginProxyBinding), } impl PluginProxy { /// Returns a new `PluginProxy`. pub fn new() -> PluginProxy { PluginProxy::Unbound } /// Binds the `PluginProxy` to a `PluginProxyBinding`. pub fn bind(&mut self, inner: PluginProxyBinding) { if let PluginProxy::BoundTo(_) = *self { panic!("trying to bind an already bound plugin proxy!"); } mem::replace(self, PluginProxy::BoundTo(inner)); } fn with_binding R>(&self, f: F) -> R { match *self { PluginProxy::Unbound => { panic!("trying to use an unbound plugin proxy!"); }, PluginProxy::BoundTo(ref binding) => { f(binding) }, } } /// Dispatches an event. pub fn dispatch(&self, event: E) { self.with_binding(move |binding| { binding.dispatcher.send(AbstractEvent::new(event)) .unwrap(); // TODO: may want to return the error }); } /// Sends a stanza. pub fn send(&self, elem: Element) { self.with_binding(move |binding| { binding.sender.send(elem).unwrap(); // TODO: as above, may want to return the error }); } } /// A plugin handler return value. /// /// The `Continue` variant means to do nothing, the `Unload` variant means to unload the plugin. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum PluginReturn { Continue, Unload, } /// A trait whch all plugins should implement. pub trait Plugin: Any + PluginAny { /// Gets a mutable reference to the inner `PluginProxy`. fn get_proxy(&mut self) -> &mut PluginProxy; /// Handles a received stanza. fn handle(&mut self, elem: &Element) -> PluginReturn; #[doc(hidden)] fn bind(&mut self, inner: PluginProxyBinding) { self.get_proxy().bind(inner); } } pub trait PluginAny { fn as_any(&self) -> &Any; } impl PluginAny for T { fn as_any(&self) -> &Any { self } }