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}