Detailed changes
@@ -3,7 +3,7 @@ use jid::Jid;
use transport::{Transport, SslTransport};
use error::Error;
use ns;
-use plugin::{Plugin, PluginInit, PluginProxyBinding};
+use plugin::{Plugin, PluginInit, PluginProxyBinding, PluginContainer, PluginRef};
use connection::{Connection, C2S};
use sasl::client::Mechanism as SaslMechanism;
use sasl::client::mechanisms::{Plain, Scram};
@@ -21,9 +21,7 @@ use xml::reader::XmlEvent as ReaderEvent;
use std::sync::{Mutex, Arc};
-use std::collections::{HashSet, HashMap};
-
-use std::any::TypeId;
+use std::collections::HashSet;
/// Struct that should be moved somewhere else and cleaned up.
#[derive(Debug)]
@@ -81,11 +79,12 @@ impl ClientBuilder {
let mut credentials = self.credentials;
credentials.channel_binding = transport.channel_bind();
let transport = Arc::new(Mutex::new(transport));
+ let plugin_container = Arc::new(PluginContainer::new());
let mut client = Client {
jid: self.jid,
transport: transport.clone(),
- plugins: HashMap::new(),
- binding: PluginProxyBinding::new(dispatcher.clone()),
+ binding: PluginProxyBinding::new(dispatcher.clone(), plugin_container.clone()),
+ plugin_container: plugin_container,
dispatcher: dispatcher,
};
client.dispatcher.register(Priority::Default, move |evt: &SendElement| {
@@ -103,7 +102,7 @@ impl ClientBuilder {
pub struct Client {
jid: Jid,
transport: Arc<Mutex<SslTransport>>,
- plugins: HashMap<TypeId, Arc<Plugin>>,
+ plugin_container: Arc<PluginContainer>,
binding: PluginProxyBinding,
dispatcher: Arc<Dispatcher>,
}
@@ -118,11 +117,9 @@ impl Client {
pub fn register_plugin<P: Plugin + PluginInit + 'static>(&mut self, mut plugin: P) {
let binding = self.binding.clone();
plugin.bind(binding);
- let p = Arc::new(plugin) as Arc<Plugin>;
+ let p = Arc::new(plugin);
P::init(&self.dispatcher, p.clone());
- if self.plugins.insert(TypeId::of::<P>(), p).is_some() {
- panic!("registering a plugin that's already registered");
- }
+ self.plugin_container.register(p);
}
pub fn register_handler<E, F>(&mut self, pri: Priority, func: F)
@@ -133,12 +130,8 @@ impl Client {
}
/// Returns the plugin given by the type parameter, if it exists, else panics.
- pub fn plugin<P: Plugin>(&self) -> &P {
- self.plugins.get(&TypeId::of::<P>())
- .expect("the requested plugin was not registered")
- .as_any()
- .downcast_ref::<P>()
- .expect("plugin downcast failure (should not happen!!)")
+ pub fn plugin<P: Plugin>(&self) -> PluginRef<P> {
+ self.plugin_container.get::<P>().unwrap()
}
/// Returns the next event and flush the send queue.
@@ -3,7 +3,7 @@ use jid::Jid;
use transport::{Transport, PlainTransport};
use error::Error;
use ns;
-use plugin::{Plugin, PluginInit, PluginProxyBinding};
+use plugin::{Plugin, PluginInit, PluginProxyBinding, PluginContainer, PluginRef};
use event::{Dispatcher, ReceiveElement, SendElement, Propagation, Priority, Event};
use connection::{Connection, Component2S};
use sha_1::{Sha1, Digest};
@@ -15,10 +15,6 @@ use xml::reader::XmlEvent as ReaderEvent;
use std::fmt::Write;
use std::sync::{Mutex, Arc};
-use std::collections::HashMap;
-
-use std::any::TypeId;
-
/// A builder for `Component`s.
pub struct ComponentBuilder {
jid: Jid,
@@ -63,11 +59,12 @@ impl ComponentBuilder {
Component2S::init(&mut transport, &self.jid.domain, "stream_opening")?;
let dispatcher = Arc::new(Dispatcher::new());
let transport = Arc::new(Mutex::new(transport));
+ let plugin_container = Arc::new(PluginContainer::new());
let mut component = Component {
jid: self.jid,
transport: transport.clone(),
- plugins: HashMap::new(),
- binding: PluginProxyBinding::new(dispatcher.clone()),
+ binding: PluginProxyBinding::new(dispatcher.clone(), plugin_container.clone()),
+ plugin_container: plugin_container,
dispatcher: dispatcher,
};
component.dispatcher.register(Priority::Default, move |evt: &SendElement| {
@@ -84,7 +81,7 @@ impl ComponentBuilder {
pub struct Component {
jid: Jid,
transport: Arc<Mutex<PlainTransport>>,
- plugins: HashMap<TypeId, Arc<Plugin>>,
+ plugin_container: Arc<PluginContainer>,
binding: PluginProxyBinding,
dispatcher: Arc<Dispatcher>,
}
@@ -99,20 +96,9 @@ impl Component {
pub fn register_plugin<P: Plugin + PluginInit + 'static>(&mut self, mut plugin: P) {
let binding = self.binding.clone();
plugin.bind(binding);
- let p = Arc::new(plugin) as Arc<Plugin>;
+ let p = Arc::new(plugin);
P::init(&self.dispatcher, p.clone());
- if self.plugins.insert(TypeId::of::<P>(), p).is_some() {
- panic!("registering a plugin that's already registered");
- }
- }
-
- /// Returns the plugin given by the type parameter, if it exists, else panics.
- pub fn plugin<P: Plugin>(&self) -> &P {
- self.plugins.get(&TypeId::of::<P>())
- .expect("the requested plugin was not registered")
- .as_any()
- .downcast_ref::<P>()
- .expect("plugin downcast failure (should not happen!!)")
+ self.plugin_container.register(p);
}
pub fn register_handler<E, F>(&mut self, pri: Priority, func: F)
@@ -122,6 +108,11 @@ impl Component {
self.dispatcher.register(pri, func);
}
+ /// Returns the plugin given by the type parameter, if it exists, else panics.
+ pub fn plugin<P: Plugin>(&self) -> PluginRef<P> {
+ self.plugin_container.get::<P>().unwrap()
+ }
+
/// Returns the next event and flush the send queue.
pub fn main(&mut self) -> Result<(), Error> {
self.dispatcher.flush_all();
@@ -2,23 +2,81 @@
use event::{Event, Dispatcher, SendElement, Priority, Propagation};
-use std::any::Any;
+use std::any::{Any, TypeId};
-use std::sync::Arc;
+use std::collections::HashMap;
+
+use std::sync::{RwLock, Arc};
+
+use std::marker::PhantomData;
+
+use std::ops::Deref;
+
+use std::convert::AsRef;
use std::mem;
use minidom::Element;
+pub struct PluginContainer {
+ plugins: RwLock<HashMap<TypeId, Arc<Plugin>>>,
+}
+
+impl PluginContainer {
+ pub fn new() -> PluginContainer {
+ PluginContainer {
+ plugins: RwLock::new(HashMap::new()),
+ }
+ }
+
+ pub fn register<P: Plugin + 'static>(&self, plugin: Arc<P>) {
+ let mut guard = self.plugins.write().unwrap();
+ if guard.insert(TypeId::of::<P>(), plugin as Arc<Plugin>).is_some() {
+ panic!("registering a plugin that's already registered");
+ }
+ }
+
+ pub fn get<P: Plugin>(&self) -> Option<PluginRef<P>> {
+ let guard = self.plugins.read().unwrap();
+ let arc = guard.get(&TypeId::of::<P>());
+ arc.map(|arc| PluginRef {
+ inner: arc.clone(),
+ _marker: PhantomData
+ })
+ }
+}
+
+#[derive(Clone)]
+pub struct PluginRef<P: Plugin> {
+ inner: Arc<Plugin>,
+ _marker: PhantomData<P>,
+}
+
+impl<P: Plugin> Deref for PluginRef<P> {
+ type Target = P;
+
+ fn deref(&self) -> &P {
+ self.inner.as_any().downcast_ref::<P>().expect("plugin downcast failure")
+ }
+}
+
+impl<P: Plugin> AsRef<P> for PluginRef<P> {
+ fn as_ref(&self) -> &P {
+ self.inner.as_any().downcast_ref::<P>().expect("plugin downcast failure")
+ }
+}
+
#[derive(Clone)]
pub struct PluginProxyBinding {
dispatcher: Arc<Dispatcher>,
+ plugin_container: Arc<PluginContainer>,
}
impl PluginProxyBinding {
- pub fn new(dispatcher: Arc<Dispatcher>) -> PluginProxyBinding {
+ pub fn new(dispatcher: Arc<Dispatcher>, plugin_container: Arc<PluginContainer>) -> PluginProxyBinding {
PluginProxyBinding {
dispatcher: dispatcher,
+ plugin_container: plugin_container,
}
}
}
@@ -72,6 +130,13 @@ impl PluginProxy {
});
}
+ /// Tries to get another plugin.
+ pub fn plugin<P: Plugin>(&self) -> Option<PluginRef<P>> {
+ self.with_binding(|binding| {
+ binding.plugin_container.get::<P>()
+ })
+ }
+
/// Sends a stanza.
pub fn send(&self, elem: Element) {
self.dispatch(SendElement(elem));