plugin.rs

  1//! Provides the plugin infrastructure.
  2
  3use event::{Event, AbstractEvent};
  4
  5use std::any::Any;
  6
  7use std::sync::mpsc::Sender;
  8
  9use std::mem;
 10
 11use minidom::Element;
 12
 13#[derive(Clone)]
 14pub struct PluginProxyBinding {
 15    sender: Sender<Element>,
 16    dispatcher: Sender<AbstractEvent>,
 17}
 18
 19impl PluginProxyBinding {
 20    pub fn new(sender: Sender<Element>, dispatcher: Sender<AbstractEvent>) -> PluginProxyBinding {
 21        PluginProxyBinding {
 22            sender: sender,
 23            dispatcher: dispatcher,
 24        }
 25    }
 26}
 27
 28pub enum PluginProxy {
 29    Unbound,
 30    BoundTo(PluginProxyBinding),
 31}
 32
 33impl PluginProxy {
 34    /// Returns a new `PluginProxy`.
 35    pub fn new() -> PluginProxy {
 36        PluginProxy::Unbound
 37    }
 38
 39    /// Binds the `PluginProxy` to a `PluginProxyBinding`.
 40    pub fn bind(&mut self, inner: PluginProxyBinding) {
 41        if let PluginProxy::BoundTo(_) = *self {
 42            panic!("trying to bind an already bound plugin proxy!");
 43        }
 44        mem::replace(self, PluginProxy::BoundTo(inner));
 45    }
 46
 47    fn with_binding<R, F: FnOnce(&PluginProxyBinding) -> R>(&self, f: F) -> R {
 48        match *self {
 49            PluginProxy::Unbound => {
 50                panic!("trying to use an unbound plugin proxy!");
 51            },
 52            PluginProxy::BoundTo(ref binding) => {
 53                f(binding)
 54            },
 55        }
 56    }
 57
 58    /// Dispatches an event.
 59    pub fn dispatch<E: Event>(&self, event: E) {
 60        self.with_binding(move |binding| {
 61            binding.dispatcher.send(AbstractEvent::new(event))
 62                              .unwrap(); // TODO: may want to return the error
 63        });
 64    }
 65
 66    /// Sends a stanza.
 67    pub fn send(&self, elem: Element) {
 68        self.with_binding(move |binding| {
 69            binding.sender.send(elem).unwrap(); // TODO: as above, may want to return the error
 70        });
 71    }
 72}
 73
 74/// A plugin handler return value.
 75///
 76/// The `Continue` variant means to do nothing, the `Unload` variant means to unload the plugin.
 77#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 78pub enum PluginReturn {
 79    Continue,
 80    Unload,
 81}
 82
 83/// A trait whch all plugins should implement.
 84pub trait Plugin: Any + PluginAny {
 85    /// Gets a mutable reference to the inner `PluginProxy`.
 86    fn get_proxy(&mut self) -> &mut PluginProxy;
 87
 88    /// Handles a received stanza.
 89    fn handle(&mut self, elem: &Element) -> PluginReturn;
 90
 91    #[doc(hidden)]
 92    fn bind(&mut self, inner: PluginProxyBinding) {
 93        self.get_proxy().bind(inner);
 94    }
 95}
 96
 97pub trait PluginAny {
 98    fn as_any(&self) -> &Any;
 99}
100
101impl<T: Any + Sized> PluginAny for T {
102    fn as_any(&self) -> &Any { self }
103}