#![deny(missing_docs, warnings)]
extern crate unsafe_any as uany;
pub mod typemap;
use std::any::Any;
use typemap::{Key, TypeMap};
use typemap::Implements;
pub trait Plugin<E: ?Sized>: Key {
type Error;
fn eval(ext_type: &mut E) -> Result<Self::Value, Self::Error>;
}
pub trait Extensible<A: uany::UnsafeAnyExt + ?Sized = uany::UnsafeAny> {
fn extensions(&self) -> &TypeMap<A>;
fn extensions_mut(&mut self) -> &mut TypeMap<A>;
}
pub trait Pluggable<A: uany::UnsafeAnyExt + ?Sized = uany::UnsafeAny> {
fn get<'a, P: Plugin<Self>>(&'a mut self) -> Result<P::Value, P::Error>
where P::Value: Clone + Any + Implements<A>, Self: Extensible<A>, A: 'a {
self.get_ref::<P>().map(|v| v.clone())
}
fn get_ref<'a, P: Plugin<Self>>(&'a mut self) -> Result<&P::Value, P::Error>
where P::Value: Any + Implements<A>, Self: Extensible<A>, A: 'a {
self.get_mut::<P>().map(|mutref| &*mutref)
}
fn get_mut<'a, P: Plugin<Self>>(&'a mut self) -> Result<&mut P::Value, P::Error>
where P::Value: Any + Implements<A>, Self: Extensible<A>, A: 'a {
use typemap::Entry::{Occupied, Vacant};
if self.extensions().contains::<P>() {
return Ok(self.extensions_mut().get_mut::<P>().unwrap());
}
P::eval(self).map(move |data| {
match self.extensions_mut().entry::<P>() {
Vacant(entry) => entry.insert(data),
Occupied(..) => panic!("Unreachable.")
}
})
}
fn compute<P: Plugin<Self>>(&mut self) -> Result<P::Value, P::Error> {
<P as Plugin<Self>>::eval(self)
}
}
#[cfg(test)]
mod test {
extern crate void;
use test::void::{Void, ResultVoidExt};
use typemap::{SendMap, Key};
use super::{Extensible, Plugin, Pluggable};
struct Extended {
map: SendMap
}
impl Extended {
fn new() -> Extended {
Extended { map: SendMap::custom() }
}
}
impl Extensible<::uany::UnsafeAny + Send> for Extended {
fn extensions(&self) -> &SendMap { &self.map }
fn extensions_mut(&mut self) -> &mut SendMap { &mut self.map }
}
impl Pluggable<::uany::UnsafeAny + Send> for Extended {}
macro_rules! generate_simple_plugin (
($t:ty, $v:ident, $v2:expr) => {
#[derive(PartialEq, Debug, Clone)]
struct $v(i32);
impl Key for $t { type Value = $t; }
impl Plugin<Extended> for $t {
type Error = Void;
fn eval(_: &mut Extended) -> Result<$t, Void> {
Ok($v($v2))
}
}
}
);
generate_simple_plugin!(One, One, 1);
generate_simple_plugin!(Two, Two, 2);
generate_simple_plugin!(Three, Three, 3);
generate_simple_plugin!(Four, Four, 4);
generate_simple_plugin!(Five, Five, 5);
generate_simple_plugin!(Six, Six, 6);
generate_simple_plugin!(Seven, Seven, 7);
generate_simple_plugin!(Eight, Eight, 8);
generate_simple_plugin!(Nine, Nine, 9);
generate_simple_plugin!(Ten, Ten, 10);
#[test] fn test_simple() {
let mut extended = Extended::new();
assert_eq!(extended.get::<One>(), Ok(One(1)));
assert_eq!(extended.get::<Two>(), Ok(Two(2)));
assert_eq!(extended.get::<Three>(), Ok(Three(3)));
}
#[test] fn test_resize() {
let mut extended = Extended::new();
extended.get::<One>().void_unwrap();
extended.get::<Two>().void_unwrap();
extended.get::<Three>().void_unwrap();
extended.get::<Four>().void_unwrap();
extended.get::<Five>().void_unwrap();
extended.get::<Six>().void_unwrap();
extended.get::<Seven>().void_unwrap();
extended.get::<Eight>().void_unwrap();
extended.get::<Nine>().void_unwrap();
extended.get::<Ten>().void_unwrap();
assert_eq!(extended.get_ref::<One>(), Ok(&One(1)))
}
#[test] fn test_custom_return_type() {
let mut extended = Extended::new();
struct IntPlugin;
impl Key for IntPlugin { type Value = i32; }
impl Plugin<Extended> for IntPlugin {
type Error = Void;
fn eval(_: &mut Extended) -> Result<i32, Void> {
Ok(0i32)
}
}
assert_eq!(extended.get::<IntPlugin>().void_unwrap(), 0i32);
}
}