plugin.rs

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