xmpp-rs/src/plugin.rs
2017-02-21 17:38:29 +01:00

103 lines
2.6 KiB
Rust

//! 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<Element>,
dispatcher: Sender<AbstractEvent>,
}
impl PluginProxyBinding {
pub fn new(sender: Sender<Element>, dispatcher: Sender<AbstractEvent>) -> 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, F: FnOnce(&PluginProxyBinding) -> 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<E: Event>(&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<T: Any + Sized> PluginAny for T {
fn as_any(&self) -> &Any { self }
}