plugin.rs

  1//! Provides the plugin infrastructure.
  2
  3use event::{Event, Dispatcher, SendElement, Priority, Propagation};
  4
  5use std::any::{Any, TypeId};
  6
  7use std::collections::HashMap;
  8
  9use std::sync::{RwLock, Arc};
 10
 11use std::marker::PhantomData;
 12
 13use std::ops::Deref;
 14
 15use std::convert::AsRef;
 16
 17use std::mem;
 18
 19use minidom::Element;
 20
 21use jid::Jid;
 22
 23pub struct PluginContainer {
 24    plugins: RwLock<HashMap<TypeId, Arc<Plugin>>>,
 25}
 26
 27impl PluginContainer {
 28    pub fn new() -> PluginContainer {
 29        PluginContainer {
 30            plugins: RwLock::new(HashMap::new()),
 31        }
 32    }
 33
 34    pub fn register<P: Plugin + 'static>(&self, plugin: Arc<P>) {
 35        let mut guard = self.plugins.write().unwrap();
 36        if guard.insert(TypeId::of::<P>(), plugin as Arc<Plugin>).is_some() {
 37            panic!("registering a plugin that's already registered");
 38        }
 39    }
 40
 41    pub fn get<P: Plugin>(&self) -> Option<PluginRef<P>> {
 42        let guard = self.plugins.read().unwrap();
 43        let arc = guard.get(&TypeId::of::<P>());
 44        arc.map(|arc| PluginRef {
 45            inner: arc.clone(),
 46            _marker: PhantomData
 47        })
 48    }
 49}
 50
 51#[derive(Clone)]
 52pub struct PluginRef<P: Plugin> {
 53    inner: Arc<Plugin>,
 54    _marker: PhantomData<P>,
 55}
 56
 57impl<P: Plugin> Deref for PluginRef<P> {
 58    type Target = P;
 59
 60    fn deref(&self) -> &P {
 61        self.inner.as_any().downcast_ref::<P>().expect("plugin downcast failure")
 62    }
 63}
 64
 65impl<P: Plugin> AsRef<P> for PluginRef<P> {
 66    fn as_ref(&self) -> &P {
 67        self.inner.as_any().downcast_ref::<P>().expect("plugin downcast failure")
 68    }
 69}
 70
 71#[derive(Clone)]
 72pub struct PluginProxyBinding {
 73    dispatcher: Arc<Dispatcher>,
 74    plugin_container: Arc<PluginContainer>,
 75    jid: Jid,
 76}
 77
 78impl PluginProxyBinding {
 79    pub fn new(dispatcher: Arc<Dispatcher>, plugin_container: Arc<PluginContainer>, jid: Jid) -> PluginProxyBinding {
 80        PluginProxyBinding {
 81            dispatcher: dispatcher,
 82            plugin_container: plugin_container,
 83            jid: jid,
 84        }
 85    }
 86}
 87
 88pub enum PluginProxy {
 89    Unbound,
 90    BoundTo(PluginProxyBinding),
 91}
 92
 93impl PluginProxy {
 94    /// Returns a new `PluginProxy`.
 95    pub fn new() -> PluginProxy {
 96        PluginProxy::Unbound
 97    }
 98
 99    /// Binds the `PluginProxy` to a `PluginProxyBinding`.
100    pub fn bind(&mut self, inner: PluginProxyBinding) {
101        if let PluginProxy::BoundTo(_) = *self {
102            panic!("trying to bind an already bound plugin proxy!");
103        }
104        mem::replace(self, PluginProxy::BoundTo(inner));
105    }
106
107    fn with_binding<R, F: FnOnce(&PluginProxyBinding) -> R>(&self, f: F) -> R {
108        match *self {
109            PluginProxy::Unbound => {
110                panic!("trying to use an unbound plugin proxy!");
111            },
112            PluginProxy::BoundTo(ref binding) => {
113                f(binding)
114            },
115        }
116    }
117
118    /// Dispatches an event.
119    pub fn dispatch<E: Event>(&self, event: E) {
120        self.with_binding(move |binding| {
121            // TODO: proper error handling
122            binding.dispatcher.dispatch(event);
123        });
124    }
125
126    /// Registers an event handler.
127    pub fn register_handler<E, F>(&self, priority: Priority, func: F)
128        where
129            E: Event,
130            F: Fn(&E) -> Propagation + 'static {
131        self.with_binding(move |binding| {
132            // TODO: proper error handling
133            binding.dispatcher.register(priority, func);
134        });
135    }
136
137    /// Tries to get another plugin.
138    pub fn plugin<P: Plugin>(&self) -> Option<PluginRef<P>> {
139        self.with_binding(|binding| {
140            binding.plugin_container.get::<P>()
141        })
142    }
143
144    /// Sends a stanza.
145    pub fn send(&self, elem: Element) {
146        self.dispatch(SendElement(elem));
147    }
148
149    /// Get our own JID.
150    pub fn get_own_jid(&self) -> Jid {
151        self.with_binding(|binding| {
152            binding.jid.clone()
153        })
154    }
155}
156
157/// A trait whch all plugins should implement.
158pub trait Plugin: Any + PluginAny {
159    /// Gets a mutable reference to the inner `PluginProxy`.
160    fn get_proxy(&mut self) -> &mut PluginProxy;
161
162    #[doc(hidden)]
163    fn bind(&mut self, inner: PluginProxyBinding) {
164        self.get_proxy().bind(inner);
165    }
166}
167
168pub trait PluginInit {
169    fn init(dispatcher: &Dispatcher, me: Arc<Plugin>);
170}
171
172pub trait PluginAny {
173    fn as_any(&self) -> &Any;
174}
175
176impl<T: Any + Sized + Plugin> PluginAny for T {
177    fn as_any(&self) -> &Any { self }
178}